@ng-modular-forms/core 0.7.8 → 0.8.0

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,70 +1,89 @@
1
1
  import * as i2 from '@angular/forms';
2
- import { NgControl, FormControl, Validators, TouchedChangeEvent, ReactiveFormsModule, FormGroup } from '@angular/forms';
2
+ import { NgControl, Validators, TouchedChangeEvent, ReactiveFormsModule, FormGroup } from '@angular/forms';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, DestroyRef, input, booleanAttribute, signal, computed, Directive, ChangeDetectionStrategy, Component, Injectable } from '@angular/core';
5
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
- import { merge, startWith, Subscription } from 'rxjs';
4
+ import { viewChild, input, computed, booleanAttribute, signal, inject, ChangeDetectorRef, DestroyRef, ElementRef, Directive, ChangeDetectionStrategy, Component, effect, Injectable } from '@angular/core';
5
+ import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
6
+ import { merge, startWith, Subject, take, catchError, EMPTY, map, debounceTime, distinctUntilChanged, filter, tap, switchMap, of, Subscription } from 'rxjs';
7
7
  import * as i1 from '@angular/common';
8
- import { CommonModule } from '@angular/common';
8
+ import { CommonModule, AsyncPipe } from '@angular/common';
9
9
 
10
10
  class FormControlBase {
11
- destroyRef = inject(DestroyRef);
12
11
  static nextId = 0;
13
- id = input(`nmf-form-control-${FormControlBase.nextId++}`, { alias: 'id' });
12
+ focusableElement = viewChild('focusable');
13
+ id = input(`nmf-form-control-${FormControlBase.nextId++}`);
14
14
  label = input('');
15
- classList = input([]);
16
15
  loading = input(false);
17
16
  name = input('');
18
17
  placeholder = input('');
18
+ autocompleteAttr = input(null);
19
+ _classList = input('', { alias: 'classList' });
20
+ classList = computed(() => {
21
+ const classList = this._classList();
22
+ if (Array.isArray(classList)) {
23
+ return classList.filter((className) => !!className.trim());
24
+ }
25
+ return classList.split(/\s+/).filter((className) => className.length > 0);
26
+ });
19
27
  _disabledByInput = input(false, {
20
28
  transform: booleanAttribute,
21
29
  alias: 'disabledOverride',
22
30
  });
23
31
  _disabledByCva = signal(false);
32
+ cdr = inject(ChangeDetectorRef);
33
+ destroyRef = inject(DestroyRef);
24
34
  ngControl = inject(NgControl, {
25
- self: true,
26
35
  optional: true,
27
36
  });
28
- standaloneControl = new FormControl(null);
29
- get formControl() {
30
- return (this.ngControl?.control ??
31
- this.standaloneControl);
32
- }
37
+ _focused = signal(false);
38
+ _value = null;
33
39
  disabled = computed(() => this._disabledByInput() || this._disabledByCva());
34
40
  isRequired = signal(this.ngControl?.control?.hasValidator(Validators.required) ?? false);
35
41
  hasErrors = signal(false);
36
42
  onChange = () => { };
37
43
  onTouched = () => { };
44
+ get value() {
45
+ return this._value;
46
+ }
47
+ get control() {
48
+ return this.ngControl?.control;
49
+ }
50
+ get focused() {
51
+ return this._focused();
52
+ }
38
53
  constructor() {
39
54
  if (this.ngControl) {
40
55
  this.ngControl.valueAccessor = this;
41
56
  }
42
57
  }
43
58
  ngOnInit() {
44
- const control = this.ngControl?.control;
59
+ const control = this.control;
45
60
  if (!control)
46
61
  return;
47
62
  merge(control.statusChanges, control.valueChanges)
48
63
  .pipe(startWith(null), takeUntilDestroyed(this.destroyRef))
49
64
  .subscribe(() => {
50
- this.hasErrors.set(control.invalid && control.touched);
51
- this.isRequired.set(control.hasValidator(Validators.required) ?? false);
65
+ this.onControlStateChange();
52
66
  });
53
67
  control.events
54
68
  .pipe(takeUntilDestroyed(this.destroyRef))
55
69
  .subscribe((event) => {
56
70
  if (event instanceof TouchedChangeEvent) {
57
- this.hasErrors.set(control.invalid && control.touched);
71
+ this.onControlStateChange();
58
72
  }
59
73
  });
60
74
  }
61
- writeValue(value) {
62
- const control = this.ngControl?.control;
63
- if (!control)
75
+ onControlStateChange() {
76
+ const control = this.control;
77
+ if (!control) {
64
78
  return;
65
- if (control.value !== value) {
66
- control.setValue(value, { emitEvent: false });
67
79
  }
80
+ this.hasErrors.set(control.invalid && control.touched);
81
+ this.isRequired.set(control.hasValidator(Validators.required) ?? false);
82
+ this.cdr.markForCheck();
83
+ }
84
+ writeValue(value) {
85
+ this._value = value;
86
+ this.cdr.markForCheck();
68
87
  }
69
88
  registerOnChange(fn) {
70
89
  this.onChange = fn;
@@ -75,8 +94,43 @@ class FormControlBase {
75
94
  setDisabledState(isDisabled) {
76
95
  this._disabledByCva.set(isDisabled);
77
96
  }
97
+ focus() {
98
+ const target = this.focusableElement();
99
+ if (!target)
100
+ return;
101
+ // Type guard check for native ElementRef wrapper
102
+ if (target instanceof ElementRef) {
103
+ target.nativeElement.focus();
104
+ }
105
+ // Type guard check for a custom component instance with executable methods
106
+ else if ('focus' in target && typeof target.focus === 'function') {
107
+ target.focus();
108
+ }
109
+ }
110
+ blur() {
111
+ const target = this.focusableElement();
112
+ if (!target)
113
+ return;
114
+ if (target instanceof ElementRef) {
115
+ target.nativeElement.blur();
116
+ }
117
+ else if ('blur' in target && typeof target.blur === 'function') {
118
+ target.blur();
119
+ }
120
+ }
121
+ onFocusIn() {
122
+ if (this.focused) {
123
+ return;
124
+ }
125
+ this._focused.set(true);
126
+ }
127
+ onFocusOut() {
128
+ //this.control?.markAsTouched();
129
+ this._focused.set(false);
130
+ this.onTouched();
131
+ }
78
132
  errorMessage() {
79
- const control = this.ngControl?.control;
133
+ const control = this.control;
80
134
  if (control == null || !control.errors || !control.touched)
81
135
  return null;
82
136
  const firstKey = Object.keys(control.errors)[0];
@@ -105,10 +159,10 @@ class FormControlBase {
105
159
  return 'Invalid value';
106
160
  }
107
161
  }
108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormControlBase, deps: [], target: i0.ɵɵFactoryTarget.Directive });
109
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: FormControlBase, isStandalone: true, inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, classList: { classPropertyName: "classList", publicName: "classList", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, _disabledByInput: { classPropertyName: "_disabledByInput", publicName: "disabledOverride", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
162
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormControlBase, deps: [], target: i0.ɵɵFactoryTarget.Directive });
163
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "19.2.25", type: FormControlBase, isStandalone: true, inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, autocompleteAttr: { classPropertyName: "autocompleteAttr", publicName: "autocompleteAttr", isSignal: true, isRequired: false, transformFunction: null }, _classList: { classPropertyName: "_classList", publicName: "classList", isSignal: true, isRequired: false, transformFunction: null }, _disabledByInput: { classPropertyName: "_disabledByInput", publicName: "disabledOverride", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "focusableElement", first: true, predicate: ["focusable"], descendants: true, isSignal: true }], ngImport: i0 });
110
164
  }
111
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormControlBase, decorators: [{
165
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormControlBase, decorators: [{
112
166
  type: Directive
113
167
  }], ctorParameters: () => [] });
114
168
 
@@ -174,32 +228,19 @@ function getControlValue(controlName, form) {
174
228
  }
175
229
 
176
230
  class FormHandlerBase {
177
- registeredControls = {};
178
- /**
179
- * Registers form controls for later reactive access.
180
- */
181
- registerControls(form, controlNames) {
182
- controlNames.forEach((controlName) => {
183
- const control = getControl(controlName.replace(/_/g, '.'), form);
184
- if (!control) {
185
- throw new Error(`Failed to register control "${controlName}". Available controls: ${Object.keys(form.controls).join(', ')}`);
186
- }
187
- this.registeredControls[controlName] = control;
188
- });
231
+ _form;
232
+ initializeForm(form) {
233
+ this._form = form;
189
234
  }
190
235
  getControl(key) {
191
- const control = this.registeredControls[key];
236
+ const control = getControl(String(key), this._form);
192
237
  if (!control) {
193
- throw new Error(`Control with name: "${key}" not found. Ensure it is registered in registerControls(...) before usage.`);
238
+ throw new Error(`Control "${String(key)}" not found.`);
194
239
  }
195
240
  return control;
196
241
  }
197
242
  valueChangesOf(key) {
198
- const control = this.registeredControls[key];
199
- if (!control) {
200
- throw new Error(`Control with name: "${key}" not found. Ensure it is registered in registerControls(...) before usage.`);
201
- }
202
- return control.valueChanges;
243
+ return this.getControl(key).valueChanges;
203
244
  }
204
245
  }
205
246
 
@@ -259,6 +300,125 @@ class CurrencyBehavior {
259
300
  }
260
301
  }
261
302
 
303
+ class LookupBehavior {
304
+ _status = signal('default');
305
+ _options = signal([]);
306
+ _selectedOption = signal(null);
307
+ status = this._status.asReadonly();
308
+ options = this._options.asReadonly();
309
+ selectedOption = this._selectedOption.asReadonly();
310
+ /*
311
+ * Emits when the options have been updated. Ensures Material autocomplete updates its
312
+ */
313
+ optionsUpdated$ = new Subject();
314
+ filteredOptions;
315
+ bOptions;
316
+ constructor(bOptions) {
317
+ this.bOptions = bOptions;
318
+ }
319
+ setSelectedOption(value) {
320
+ this._selectedOption.set(value);
321
+ }
322
+ selectOption(event, option) {
323
+ event?.stopPropagation();
324
+ const compare = this.bOptions.resolvers.compare() ?? undefined;
325
+ const selected = this.options().find((o) => compare ? compare(o.value, option.value) : o.value === option.value);
326
+ if (!selected) {
327
+ return;
328
+ }
329
+ this.setSelectedOption(selected);
330
+ }
331
+ clearSelectedOption() {
332
+ this.setSelectedOption(null);
333
+ this.optionsUpdated$.next();
334
+ }
335
+ selectedMatchedOption(value) {
336
+ const { destroyRef, resolvers } = this.bOptions;
337
+ const compare = resolvers.compare() ?? undefined;
338
+ const label = resolvers.label() ?? undefined;
339
+ const labelAsync = resolvers.labelAsync() ?? undefined;
340
+ const match = this._options().find((o) => compare ? compare(o.value, value) : o.value === value) ?? null;
341
+ if (match) {
342
+ this._selectedOption.set(match);
343
+ return;
344
+ }
345
+ if (value === null) {
346
+ this._selectedOption.set(null);
347
+ return;
348
+ }
349
+ if (labelAsync) {
350
+ this._status.set('loading');
351
+ labelAsync(value)
352
+ .pipe(take(1), catchError(() => {
353
+ this._status.set('error');
354
+ return EMPTY;
355
+ }), takeUntilDestroyed(destroyRef))
356
+ .subscribe((label) => {
357
+ this._selectedOption.set({
358
+ value,
359
+ label,
360
+ });
361
+ this._status.set('default');
362
+ });
363
+ return;
364
+ }
365
+ if (label) {
366
+ this._selectedOption.set({
367
+ value: value,
368
+ label: label(value),
369
+ });
370
+ return;
371
+ }
372
+ }
373
+ updateOptions(results, status) {
374
+ this._status.set(status ?? 'default');
375
+ this._options.set(results);
376
+ this.optionsUpdated$.next();
377
+ }
378
+ filterOptions(name, results) {
379
+ const filterValue = name.toLowerCase();
380
+ return results.filter((option) => option.label.toLowerCase().includes(filterValue) ||
381
+ String(option.value).includes(filterValue));
382
+ }
383
+ setupFilteredOptions(source, searchQuery) {
384
+ this.filteredOptions = merge(source, this.optionsUpdated$).pipe(startWith(''), map(() => {
385
+ const options = this.options();
386
+ let value = searchQuery;
387
+ if (typeof searchQuery === 'function') {
388
+ value = searchQuery();
389
+ }
390
+ if (typeof value !== 'string') {
391
+ return this.options().slice();
392
+ }
393
+ return value ? this.filterOptions(value, options) : options.slice();
394
+ }));
395
+ }
396
+ setupOptionsProvider(source, debounceDelay, searchThreshold) {
397
+ const { destroyRef, resolvers } = this.bOptions;
398
+ const search = resolvers.search() ?? undefined;
399
+ if (!search) {
400
+ return;
401
+ }
402
+ source.pipe(takeUntilDestroyed(destroyRef)).subscribe((value) => {
403
+ if (!value || value.length < searchThreshold) {
404
+ this.updateOptions([]);
405
+ }
406
+ });
407
+ source
408
+ .pipe(debounceTime(debounceDelay), distinctUntilChanged((a, b) => a === b), filter(() => this.selectedOption() == null), filter((q) => typeof q === 'string' && q.length >= searchThreshold), tap(() => this.updateOptions([], 'loading')), switchMap((query) => search(query).pipe(catchError(() => {
409
+ this._status.set('error');
410
+ return of(null);
411
+ }))), takeUntilDestroyed(destroyRef))
412
+ .subscribe((response) => {
413
+ if (!response) {
414
+ return;
415
+ }
416
+ const status = response.length ? 'default' : 'empty';
417
+ this.updateOptions(response, status);
418
+ });
419
+ }
420
+ }
421
+
262
422
  class TextBehavior {
263
423
  _showPassword = signal(false);
264
424
  showPassword = this._showPassword.asReadonly();
@@ -272,9 +432,11 @@ class FormFieldComponent {
272
432
  label = input();
273
433
  isRequired = input();
274
434
  loading = input();
435
+ hint = input();
275
436
  errorMessage = input();
276
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
277
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: FormFieldComponent, isStandalone: true, selector: "nmf-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isRequired: { classPropertyName: "isRequired", publicName: "isRequired", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
437
+ hasErrors = computed(() => this.errorMessage() != null);
438
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
439
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: FormFieldComponent, isStandalone: true, selector: "nmf-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isRequired: { classPropertyName: "isRequired", publicName: "isRequired", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
278
440
  <div class="nmf-field" [class.loading]="loading()">
279
441
  @if (label()) {
280
442
  <label class="nmf-label">
@@ -293,13 +455,19 @@ class FormFieldComponent {
293
455
  </div>
294
456
  }
295
457
 
296
- <p class="nmf-error">
458
+ @if (hint()) {
459
+ <p class="nmf-hint">
460
+ {{ hint() }}
461
+ </p>
462
+ }
463
+
464
+ <p class="nmf-hint" [class.error]="hasErrors()">
297
465
  {{ errorMessage() }}
298
466
  </p>
299
467
  </div>
300
468
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
301
469
  }
302
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormFieldComponent, decorators: [{
470
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormFieldComponent, decorators: [{
303
471
  type: Component,
304
472
  args: [{
305
473
  selector: 'nmf-form-field',
@@ -325,7 +493,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
325
493
  </div>
326
494
  }
327
495
 
328
- <p class="nmf-error">
496
+ @if (hint()) {
497
+ <p class="nmf-hint">
498
+ {{ hint() }}
499
+ </p>
500
+ }
501
+
502
+ <p class="nmf-hint" [class.error]="hasErrors()">
329
503
  {{ errorMessage() }}
330
504
  </p>
331
505
  </div>
@@ -360,8 +534,8 @@ class InputCurrencyComponent extends FormControlBase {
360
534
  const valid = parsedValue != null && parsedValue >= 0;
361
535
  return valid ? 'inherit' : '#dc6262';
362
536
  });
363
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputCurrencyComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
364
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: InputCurrencyComponent, isStandalone: true, selector: "nmf-currency", usesInheritance: true, ngImport: i0, template: `
537
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputCurrencyComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
538
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: InputCurrencyComponent, isStandalone: true, selector: "nmf-currency", usesInheritance: true, ngImport: i0, template: `
365
539
  <nmf-form-field
366
540
  [label]="label()"
367
541
  [isRequired]="isRequired()"
@@ -381,8 +555,8 @@ class InputCurrencyComponent extends FormControlBase {
381
555
  }
382
556
 
383
557
  <input
558
+ #focusable
384
559
  type="text"
385
- autocomplete="off"
386
560
  class="nmf-input"
387
561
  [ngClass]="classList()"
388
562
  [class.error]="hasErrors()"
@@ -395,15 +569,16 @@ class InputCurrencyComponent extends FormControlBase {
395
569
  [disabled]="disabled()"
396
570
  [required]="isRequired()"
397
571
  [placeholder]="placeholder()"
572
+ [autocomplete]="autocompleteAttr()"
398
573
  (blur)="onTouched()"
399
574
  (input)="onInput($event)"
400
575
  (keydown)="handleKeyDown($event)"
401
576
  />
402
577
  </div>
403
578
  </nmf-form-field>
404
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
579
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "hint", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
405
580
  }
406
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputCurrencyComponent, decorators: [{
581
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputCurrencyComponent, decorators: [{
407
582
  type: Component,
408
583
  args: [{
409
584
  selector: 'nmf-currency',
@@ -430,8 +605,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
430
605
  }
431
606
 
432
607
  <input
608
+ #focusable
433
609
  type="text"
434
- autocomplete="off"
435
610
  class="nmf-input"
436
611
  [ngClass]="classList()"
437
612
  [class.error]="hasErrors()"
@@ -444,6 +619,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
444
619
  [disabled]="disabled()"
445
620
  [required]="isRequired()"
446
621
  [placeholder]="placeholder()"
622
+ [autocomplete]="autocompleteAttr()"
447
623
  (blur)="onTouched()"
448
624
  (input)="onInput($event)"
449
625
  (keydown)="handleKeyDown($event)"
@@ -485,8 +661,8 @@ class InputDatepickerComponent extends FormControlBase {
485
661
  this.displayValue.set(this.formatDate(parsed) ?? '');
486
662
  this.onChange(parsed);
487
663
  }
488
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputDatepickerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
489
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: InputDatepickerComponent, isStandalone: true, selector: "nmf-datepicker", inputs: { minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
664
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputDatepickerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
665
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.25", type: InputDatepickerComponent, isStandalone: true, selector: "nmf-datepicker", inputs: { minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
490
666
  <nmf-form-field
491
667
  [label]="label()"
492
668
  [isRequired]="isRequired()"
@@ -494,6 +670,7 @@ class InputDatepickerComponent extends FormControlBase {
494
670
  [errorMessage]="errorMessage()"
495
671
  >
496
672
  <input
673
+ #focusable
497
674
  type="date"
498
675
  class="nmf-input"
499
676
  [ngClass]="classList()"
@@ -507,13 +684,14 @@ class InputDatepickerComponent extends FormControlBase {
507
684
  [disabled]="disabled()"
508
685
  [required]="isRequired()"
509
686
  [placeholder]="placeholder()"
687
+ [autocomplete]="autocompleteAttr()"
510
688
  (blur)="onTouched()"
511
689
  (input)="onInput($event)"
512
690
  />
513
691
  </nmf-form-field>
514
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
692
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "hint", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
515
693
  }
516
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputDatepickerComponent, decorators: [{
694
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputDatepickerComponent, decorators: [{
517
695
  type: Component,
518
696
  args: [{
519
697
  selector: 'nmf-datepicker',
@@ -528,6 +706,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
528
706
  [errorMessage]="errorMessage()"
529
707
  >
530
708
  <input
709
+ #focusable
531
710
  type="date"
532
711
  class="nmf-input"
533
712
  [ngClass]="classList()"
@@ -541,6 +720,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
541
720
  [disabled]="disabled()"
542
721
  [required]="isRequired()"
543
722
  [placeholder]="placeholder()"
723
+ [autocomplete]="autocompleteAttr()"
544
724
  (blur)="onTouched()"
545
725
  (input)="onInput($event)"
546
726
  />
@@ -549,6 +729,326 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
549
729
  }]
550
730
  }] });
551
731
 
732
+ class InputLookupComponent extends FormControlBase {
733
+ autocompleteAttr = input('off');
734
+ /*
735
+ * Static options to display in the dropdown. This is for synchronous sources.
736
+ */
737
+ optionsSource = input([]);
738
+ /*
739
+ * Must return a cancellable observable. This is for asynchronous sources (API calls, etc).
740
+ */
741
+ optionsProvider = input();
742
+ /*
743
+ * When using a synchronous options source, or an asynchronous provider that returns an object where the shape is known,
744
+ * this function is used to determine the display value.
745
+ */
746
+ displayWith = input();
747
+ /*
748
+ * Used to determine the display value asynchronously when using primitive types for form values
749
+ * eg: countryCode instead of Country itself.
750
+ *
751
+ * If not provided, the raw value will be used. Only needed for patching/hydrating the form.
752
+ */
753
+ displayProvider = input();
754
+ /*
755
+ * Used to compare options during selection if object equality is not sufficient.
756
+ */
757
+ compareWith = input();
758
+ /*
759
+ * The provided hint will be displayed when asynchronous lookup is empty.
760
+ */
761
+ emptyOptionsLabel = input('No results found');
762
+ /*
763
+ * Search will be debounced by this many milliseconds.
764
+ */
765
+ debounceTime = input(500);
766
+ /*
767
+ * Search will not be triggered until the user has typed at least this many characters.
768
+ */
769
+ searchThreshold = input(2);
770
+ _activeIndex = signal(-1);
771
+ activeIndex = this._activeIndex.asReadonly();
772
+ _searchQuery = signal('');
773
+ _isInteractingWithOptions = signal(false);
774
+ _searchQuery$ = toObservable(this._searchQuery);
775
+ isOpen = signal(false);
776
+ openUpwards = signal(false);
777
+ displayLabel = computed(() => {
778
+ const selected = this.behavior.selectedOption();
779
+ if (selected) {
780
+ return selected.label;
781
+ }
782
+ return this._searchQuery();
783
+ });
784
+ inputElement = inject((ElementRef));
785
+ behavior;
786
+ constructor() {
787
+ super();
788
+ this.behavior = new LookupBehavior({
789
+ destroyRef: this.destroyRef,
790
+ resolvers: {
791
+ compare: this.compareWith,
792
+ label: this.displayWith,
793
+ labelAsync: this.displayProvider,
794
+ search: this.optionsProvider,
795
+ },
796
+ });
797
+ effect(() => {
798
+ const currentOptions = this.optionsSource() ?? [];
799
+ this.updateOptions(currentOptions);
800
+ });
801
+ effect(() => {
802
+ const selectedOption = this.behavior.selectedOption();
803
+ this.onChange(selectedOption?.value ?? null);
804
+ });
805
+ }
806
+ ngOnInit() {
807
+ super.ngOnInit();
808
+ this.behavior.setupFilteredOptions(this._searchQuery$, this._searchQuery);
809
+ this.behavior.setupOptionsProvider(this._searchQuery$, 500, 2);
810
+ }
811
+ writeValue(value) {
812
+ super.writeValue(value);
813
+ this.behavior.selectedMatchedOption(value);
814
+ }
815
+ onFocusOut() {
816
+ super.onFocusOut();
817
+ if (this._isInteractingWithOptions()) {
818
+ return;
819
+ }
820
+ this.isOpen.set(false);
821
+ }
822
+ onFocusIn() {
823
+ super.onFocusIn();
824
+ if (!this.behavior.selectedOption()) {
825
+ this.calculateDropdownPosition();
826
+ this.isOpen.set(true);
827
+ }
828
+ }
829
+ ngOnDestroy() {
830
+ this.behavior.optionsUpdated$.complete();
831
+ }
832
+ onInput(event) {
833
+ this._searchQuery.set(event.target.value);
834
+ }
835
+ selectOption(event, option) {
836
+ this.behavior.selectOption(event, option);
837
+ this._isInteractingWithOptions.set(false);
838
+ this.isOpen.set(false);
839
+ }
840
+ resetActiveIndex() {
841
+ this._activeIndex.set(-1);
842
+ }
843
+ setOptionsInteraction(state) {
844
+ this._isInteractingWithOptions.set(state);
845
+ }
846
+ updateOptions(results, status) {
847
+ this.behavior.updateOptions(results, status);
848
+ this.resetActiveIndex();
849
+ }
850
+ clearSelectedOption() {
851
+ this._searchQuery.set('');
852
+ this.behavior.clearSelectedOption();
853
+ this.focus();
854
+ }
855
+ onKeyDown(event, currentOptions) {
856
+ if (!this.isOpen() || !currentOptions || currentOptions.length === 0) {
857
+ if (event.key === 'ArrowDown') {
858
+ this.calculateDropdownPosition();
859
+ this.isOpen.set(true);
860
+ event.preventDefault();
861
+ }
862
+ return;
863
+ }
864
+ switch (event.key) {
865
+ case 'ArrowDown':
866
+ event.preventDefault();
867
+ this._activeIndex.update((prev) => prev + 1 >= currentOptions.length ? 0 : prev + 1);
868
+ break;
869
+ case 'ArrowUp':
870
+ event.preventDefault();
871
+ this._activeIndex.update((prev) => prev - 1 < 0 ? currentOptions.length - 1 : prev - 1);
872
+ break;
873
+ case 'Enter':
874
+ event.preventDefault();
875
+ if (this._activeIndex() >= 0 &&
876
+ this._activeIndex() < currentOptions.length) {
877
+ this.selectOption(event, currentOptions[this._activeIndex()]);
878
+ }
879
+ break;
880
+ case 'Escape':
881
+ event.preventDefault();
882
+ this.isOpen.set(false);
883
+ this.resetActiveIndex();
884
+ break;
885
+ case 'Backspace':
886
+ case 'Delete':
887
+ if (this.behavior.selectedOption() !== null) {
888
+ event.preventDefault();
889
+ this.clearSelectedOption();
890
+ }
891
+ break;
892
+ }
893
+ }
894
+ calculateDropdownPosition() {
895
+ const rect = this.inputElement.nativeElement.getBoundingClientRect();
896
+ const spaceBelow = window.innerHeight - rect.bottom;
897
+ const spaceAbove = rect.top;
898
+ this.openUpwards.set(spaceBelow < 225 && spaceAbove > spaceBelow);
899
+ }
900
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputLookupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
901
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: InputLookupComponent, isStandalone: true, selector: "nmf-lookup", inputs: { autocompleteAttr: { classPropertyName: "autocompleteAttr", publicName: "autocompleteAttr", isSignal: true, isRequired: false, transformFunction: null }, optionsSource: { classPropertyName: "optionsSource", publicName: "optionsSource", isSignal: true, isRequired: false, transformFunction: null }, optionsProvider: { classPropertyName: "optionsProvider", publicName: "optionsProvider", isSignal: true, isRequired: false, transformFunction: null }, displayWith: { classPropertyName: "displayWith", publicName: "displayWith", isSignal: true, isRequired: false, transformFunction: null }, displayProvider: { classPropertyName: "displayProvider", publicName: "displayProvider", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, emptyOptionsLabel: { classPropertyName: "emptyOptionsLabel", publicName: "emptyOptionsLabel", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null }, searchThreshold: { classPropertyName: "searchThreshold", publicName: "searchThreshold", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["nmfLookup"], usesInheritance: true, ngImport: i0, template: `
902
+ <nmf-form-field
903
+ [label]="label()"
904
+ [hint]="behavior.status() === 'empty' ? emptyOptionsLabel() : null"
905
+ [isRequired]="isRequired()"
906
+ [loading]="behavior.status() === 'loading' || loading()"
907
+ [errorMessage]="errorMessage()"
908
+ >
909
+ <div class="nmf-input-wrapper" [style.position]="'relative'">
910
+ @if ({ options: behavior.filteredOptions | async }; as stream) {
911
+ <input
912
+ #focusable
913
+ type="text"
914
+ class="nmf-input"
915
+ [attr.list]="id + '-options'"
916
+ [ngClass]="classList()"
917
+ [class.error]="hasErrors()"
918
+ [class.disabled]="disabled()"
919
+ [style.cursor]="
920
+ behavior.selectedOption() != null ? 'not-allowed' : 'text'
921
+ "
922
+ [id]="id()"
923
+ [name]="name()"
924
+ [value]="displayLabel()"
925
+ [disabled]="disabled()"
926
+ [required]="isRequired()"
927
+ [readonly]="behavior.selectedOption() != null"
928
+ [placeholder]="placeholder()"
929
+ [autocomplete]="autocompleteAttr()"
930
+ (blur)="onFocusOut()"
931
+ (focus)="onFocusIn()"
932
+ (input)="onInput($event)"
933
+ (keydown)="onKeyDown($event, stream.options)"
934
+ />
935
+
936
+ @if (isOpen() && stream.options && stream.options.length > 0) {
937
+ <ul
938
+ class="nmf-options-list"
939
+ [class.upward]="openUpwards()"
940
+ (pointerdown)="setOptionsInteraction(true)"
941
+ (pointerup)="setOptionsInteraction(false)"
942
+ >
943
+ @for (option of stream.options; track option; let i = $index) {
944
+ <li
945
+ [class.selected]="behavior.selectedOption() == option"
946
+ [class.active]="activeIndex() === i"
947
+ (click)="selectOption($event, option)"
948
+ >
949
+ {{
950
+ displayWith() ? displayWith()!(option.value) : option.label
951
+ }}
952
+ </li>
953
+ }
954
+ </ul>
955
+ }
956
+
957
+ @if (behavior.selectedOption() && !disabled()) {
958
+ <button
959
+ class="nmf-clear-button"
960
+ type="button"
961
+ aria-label="Clear selection"
962
+ (click)="clearSelectedOption()"
963
+ >
964
+ X
965
+ </button>
966
+ }
967
+ }
968
+ </div>
969
+ </nmf-form-field>
970
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "hint", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
971
+ }
972
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputLookupComponent, decorators: [{
973
+ type: Component,
974
+ args: [{
975
+ selector: 'nmf-lookup',
976
+ exportAs: 'nmfLookup',
977
+ imports: [CommonModule, ReactiveFormsModule, FormFieldComponent, AsyncPipe],
978
+ changeDetection: ChangeDetectionStrategy.OnPush,
979
+ template: `
980
+ <nmf-form-field
981
+ [label]="label()"
982
+ [hint]="behavior.status() === 'empty' ? emptyOptionsLabel() : null"
983
+ [isRequired]="isRequired()"
984
+ [loading]="behavior.status() === 'loading' || loading()"
985
+ [errorMessage]="errorMessage()"
986
+ >
987
+ <div class="nmf-input-wrapper" [style.position]="'relative'">
988
+ @if ({ options: behavior.filteredOptions | async }; as stream) {
989
+ <input
990
+ #focusable
991
+ type="text"
992
+ class="nmf-input"
993
+ [attr.list]="id + '-options'"
994
+ [ngClass]="classList()"
995
+ [class.error]="hasErrors()"
996
+ [class.disabled]="disabled()"
997
+ [style.cursor]="
998
+ behavior.selectedOption() != null ? 'not-allowed' : 'text'
999
+ "
1000
+ [id]="id()"
1001
+ [name]="name()"
1002
+ [value]="displayLabel()"
1003
+ [disabled]="disabled()"
1004
+ [required]="isRequired()"
1005
+ [readonly]="behavior.selectedOption() != null"
1006
+ [placeholder]="placeholder()"
1007
+ [autocomplete]="autocompleteAttr()"
1008
+ (blur)="onFocusOut()"
1009
+ (focus)="onFocusIn()"
1010
+ (input)="onInput($event)"
1011
+ (keydown)="onKeyDown($event, stream.options)"
1012
+ />
1013
+
1014
+ @if (isOpen() && stream.options && stream.options.length > 0) {
1015
+ <ul
1016
+ class="nmf-options-list"
1017
+ [class.upward]="openUpwards()"
1018
+ (pointerdown)="setOptionsInteraction(true)"
1019
+ (pointerup)="setOptionsInteraction(false)"
1020
+ >
1021
+ @for (option of stream.options; track option; let i = $index) {
1022
+ <li
1023
+ [class.selected]="behavior.selectedOption() == option"
1024
+ [class.active]="activeIndex() === i"
1025
+ (click)="selectOption($event, option)"
1026
+ >
1027
+ {{
1028
+ displayWith() ? displayWith()!(option.value) : option.label
1029
+ }}
1030
+ </li>
1031
+ }
1032
+ </ul>
1033
+ }
1034
+
1035
+ @if (behavior.selectedOption() && !disabled()) {
1036
+ <button
1037
+ class="nmf-clear-button"
1038
+ type="button"
1039
+ aria-label="Clear selection"
1040
+ (click)="clearSelectedOption()"
1041
+ >
1042
+ X
1043
+ </button>
1044
+ }
1045
+ }
1046
+ </div>
1047
+ </nmf-form-field>
1048
+ `,
1049
+ }]
1050
+ }], ctorParameters: () => [] });
1051
+
552
1052
  class InputNumberComponent extends FormControlBase {
553
1053
  formatValue = input(false);
554
1054
  displayValue = signal('');
@@ -577,8 +1077,8 @@ class InputNumberComponent extends FormControlBase {
577
1077
  this.displayValue.set(value != null ? String(value) : '');
578
1078
  }
579
1079
  }
580
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputNumberComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
581
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: InputNumberComponent, isStandalone: true, selector: "nmf-number", inputs: { formatValue: { classPropertyName: "formatValue", publicName: "formatValue", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1080
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputNumberComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1081
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.25", type: InputNumberComponent, isStandalone: true, selector: "nmf-number", inputs: { formatValue: { classPropertyName: "formatValue", publicName: "formatValue", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
582
1082
  <nmf-form-field
583
1083
  [label]="label()"
584
1084
  [isRequired]="isRequired()"
@@ -586,7 +1086,7 @@ class InputNumberComponent extends FormControlBase {
586
1086
  [errorMessage]="errorMessage()"
587
1087
  >
588
1088
  <input
589
- autocomplete="off"
1089
+ #focusable
590
1090
  class="nmf-input"
591
1091
  [ngClass]="classList()"
592
1092
  [class.error]="hasErrors()"
@@ -598,14 +1098,15 @@ class InputNumberComponent extends FormControlBase {
598
1098
  [disabled]="disabled()"
599
1099
  [required]="isRequired()"
600
1100
  [placeholder]="placeholder()"
1101
+ [autocomplete]="autocompleteAttr()"
601
1102
  (blur)="onTouched()"
602
1103
  (input)="onInput($event)"
603
1104
  (keydown)="handleKeyDown($event)"
604
1105
  />
605
1106
  </nmf-form-field>
606
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1107
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "hint", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
607
1108
  }
608
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputNumberComponent, decorators: [{
1109
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputNumberComponent, decorators: [{
609
1110
  type: Component,
610
1111
  args: [{
611
1112
  selector: 'nmf-number',
@@ -620,7 +1121,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
620
1121
  [errorMessage]="errorMessage()"
621
1122
  >
622
1123
  <input
623
- autocomplete="off"
1124
+ #focusable
624
1125
  class="nmf-input"
625
1126
  [ngClass]="classList()"
626
1127
  [class.error]="hasErrors()"
@@ -632,6 +1133,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
632
1133
  [disabled]="disabled()"
633
1134
  [required]="isRequired()"
634
1135
  [placeholder]="placeholder()"
1136
+ [autocomplete]="autocompleteAttr()"
635
1137
  (blur)="onTouched()"
636
1138
  (input)="onInput($event)"
637
1139
  (keydown)="handleKeyDown($event)"
@@ -644,9 +1146,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
644
1146
  class InputSelectComponent extends FormControlBase {
645
1147
  options = input([]);
646
1148
  emptyOptionLabel = input('Select an option');
647
- clearOptionLabel = input('Clear selection');
648
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
649
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: InputSelectComponent, isStandalone: true, selector: "nmf-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, emptyOptionLabel: { classPropertyName: "emptyOptionLabel", publicName: "emptyOptionLabel", isSignal: true, isRequired: false, transformFunction: null }, clearOptionLabel: { classPropertyName: "clearOptionLabel", publicName: "clearOptionLabel", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1149
+ allowEmptyOptionSelection = input(false);
1150
+ handleChange(event) {
1151
+ if (this._disabledByCva())
1152
+ return;
1153
+ const input = event.target;
1154
+ this.onChange(input.value || null);
1155
+ }
1156
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1157
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: InputSelectComponent, isStandalone: true, selector: "nmf-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, emptyOptionLabel: { classPropertyName: "emptyOptionLabel", publicName: "emptyOptionLabel", isSignal: true, isRequired: false, transformFunction: null }, allowEmptyOptionSelection: { classPropertyName: "allowEmptyOptionSelection", publicName: "allowEmptyOptionSelection", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
650
1158
  <nmf-form-field
651
1159
  [label]="label()"
652
1160
  [isRequired]="isRequired()"
@@ -655,38 +1163,36 @@ class InputSelectComponent extends FormControlBase {
655
1163
  >
656
1164
  <div class="select-wrapper" [class.disabled]="disabled()">
657
1165
  <select
1166
+ #focusable
658
1167
  class="nmf-input"
659
1168
  [ngClass]="classList()"
660
1169
  [class.error]="hasErrors()"
661
1170
  [class.disabled]="disabled()"
1171
+ [id]="id()"
1172
+ [value]="value ?? ''"
1173
+ [disabled]="disabled()"
662
1174
  [required]="isRequired()"
663
- [formControl]="formControl"
1175
+ [autocomplete]="autocompleteAttr()"
664
1176
  (blur)="onTouched()"
1177
+ (change)="handleChange($event)"
665
1178
  >
666
1179
  <!-- Empty option -->
667
- <option [ngValue]="null" disabled>
1180
+ <option [value]="''" [disabled]="!allowEmptyOptionSelection()">
668
1181
  {{ emptyOptionLabel() }}
669
1182
  </option>
670
1183
 
671
1184
  <!-- Options -->
672
- @for (option of options(); track option.key) {
673
- <option [ngValue]="option.key" [disabled]="option.disabled">
1185
+ @for (option of options(); track option.value) {
1186
+ <option [value]="option.value" [disabled]="option.disabled">
674
1187
  {{ option.label }}
675
1188
  </option>
676
1189
  }
677
-
678
- <!-- Clear option -->
679
- @if (clearOptionLabel()) {
680
- <option [ngValue]="null">
681
- {{ clearOptionLabel() }}
682
- </option>
683
- }
684
1190
  </select>
685
1191
  </div>
686
1192
  </nmf-form-field>
687
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1193
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "hint", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
688
1194
  }
689
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputSelectComponent, decorators: [{
1195
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputSelectComponent, decorators: [{
690
1196
  type: Component,
691
1197
  args: [{
692
1198
  selector: 'nmf-select',
@@ -702,32 +1208,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
702
1208
  >
703
1209
  <div class="select-wrapper" [class.disabled]="disabled()">
704
1210
  <select
1211
+ #focusable
705
1212
  class="nmf-input"
706
1213
  [ngClass]="classList()"
707
1214
  [class.error]="hasErrors()"
708
1215
  [class.disabled]="disabled()"
1216
+ [id]="id()"
1217
+ [value]="value ?? ''"
1218
+ [disabled]="disabled()"
709
1219
  [required]="isRequired()"
710
- [formControl]="formControl"
1220
+ [autocomplete]="autocompleteAttr()"
711
1221
  (blur)="onTouched()"
1222
+ (change)="handleChange($event)"
712
1223
  >
713
1224
  <!-- Empty option -->
714
- <option [ngValue]="null" disabled>
1225
+ <option [value]="''" [disabled]="!allowEmptyOptionSelection()">
715
1226
  {{ emptyOptionLabel() }}
716
1227
  </option>
717
1228
 
718
1229
  <!-- Options -->
719
- @for (option of options(); track option.key) {
720
- <option [ngValue]="option.key" [disabled]="option.disabled">
1230
+ @for (option of options(); track option.value) {
1231
+ <option [value]="option.value" [disabled]="option.disabled">
721
1232
  {{ option.label }}
722
1233
  </option>
723
1234
  }
724
-
725
- <!-- Clear option -->
726
- @if (clearOptionLabel()) {
727
- <option [ngValue]="null">
728
- {{ clearOptionLabel() }}
729
- </option>
730
- }
731
1235
  </select>
732
1236
  </div>
733
1237
  </nmf-form-field>
@@ -741,8 +1245,14 @@ class InputTextComponent extends FormControlBase {
741
1245
  computedType = computed(() => this.behavior.showPassword() && this.type() === 'password'
742
1246
  ? 'text'
743
1247
  : this.type());
744
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputTextComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
745
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: InputTextComponent, isStandalone: true, selector: "nmf-text", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1248
+ onInput(event) {
1249
+ if (this._disabledByInput())
1250
+ return;
1251
+ const input = event.target;
1252
+ this.onChange(input.value);
1253
+ }
1254
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputTextComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1255
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: InputTextComponent, isStandalone: true, selector: "nmf-text", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
746
1256
  <nmf-form-field
747
1257
  [label]="label()"
748
1258
  [isRequired]="isRequired()"
@@ -751,6 +1261,7 @@ class InputTextComponent extends FormControlBase {
751
1261
  >
752
1262
  <div class="nmf-input-wrapper">
753
1263
  <input
1264
+ #focusable
754
1265
  class="nmf-input"
755
1266
  [ngClass]="classList()"
756
1267
  [class.error]="hasErrors()"
@@ -758,10 +1269,13 @@ class InputTextComponent extends FormControlBase {
758
1269
  [id]="id()"
759
1270
  [name]="name()"
760
1271
  [type]="computedType()"
1272
+ [value]="value"
1273
+ [disabled]="disabled()"
761
1274
  [required]="isRequired()"
762
1275
  [placeholder]="placeholder()"
763
- [formControl]="formControl"
1276
+ [autocomplete]="autocompleteAttr()"
764
1277
  (blur)="onTouched()"
1278
+ (input)="onInput($event)"
765
1279
  />
766
1280
 
767
1281
  @if (type() === 'password' && !loading() && !disabled()) {
@@ -815,9 +1329,9 @@ class InputTextComponent extends FormControlBase {
815
1329
  />
816
1330
  </svg>
817
1331
  </ng-template>
818
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1332
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "hint", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
819
1333
  }
820
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputTextComponent, decorators: [{
1334
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputTextComponent, decorators: [{
821
1335
  type: Component,
822
1336
  args: [{
823
1337
  selector: 'nmf-text',
@@ -833,6 +1347,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
833
1347
  >
834
1348
  <div class="nmf-input-wrapper">
835
1349
  <input
1350
+ #focusable
836
1351
  class="nmf-input"
837
1352
  [ngClass]="classList()"
838
1353
  [class.error]="hasErrors()"
@@ -840,10 +1355,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
840
1355
  [id]="id()"
841
1356
  [name]="name()"
842
1357
  [type]="computedType()"
1358
+ [value]="value"
1359
+ [disabled]="disabled()"
843
1360
  [required]="isRequired()"
844
1361
  [placeholder]="placeholder()"
845
- [formControl]="formControl"
1362
+ [autocomplete]="autocompleteAttr()"
846
1363
  (blur)="onTouched()"
1364
+ (input)="onInput($event)"
847
1365
  />
848
1366
 
849
1367
  @if (type() === 'password' && !loading() && !disabled()) {
@@ -904,8 +1422,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
904
1422
  class InputTextareaComponent extends FormControlBase {
905
1423
  rows = input(5);
906
1424
  cols = input(5);
907
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputTextareaComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
908
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: InputTextareaComponent, isStandalone: true, selector: "nmf-textarea", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, cols: { classPropertyName: "cols", publicName: "cols", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1425
+ onInput(event) {
1426
+ if (this._disabledByInput())
1427
+ return;
1428
+ const input = event.target;
1429
+ this.onChange(input.value);
1430
+ }
1431
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputTextareaComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1432
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.25", type: InputTextareaComponent, isStandalone: true, selector: "nmf-textarea", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, cols: { classPropertyName: "cols", publicName: "cols", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
909
1433
  <nmf-form-field
910
1434
  [label]="label()"
911
1435
  [isRequired]="isRequired()"
@@ -913,6 +1437,7 @@ class InputTextareaComponent extends FormControlBase {
913
1437
  [errorMessage]="errorMessage()"
914
1438
  >
915
1439
  <textarea
1440
+ #focusable
916
1441
  class="nmf-input"
917
1442
  [ngClass]="classList()"
918
1443
  [class.error]="hasErrors()"
@@ -920,15 +1445,18 @@ class InputTextareaComponent extends FormControlBase {
920
1445
  [id]="id()"
921
1446
  [rows]="rows()"
922
1447
  [cols]="cols()"
1448
+ [value]="value"
1449
+ [disabled]="disabled()"
923
1450
  [required]="isRequired()"
924
1451
  [placeholder]="placeholder()"
925
- [formControl]="formControl"
1452
+ [autocomplete]="autocompleteAttr()"
926
1453
  (blur)="onTouched()"
1454
+ (input)="onInput($event)"
927
1455
  ></textarea>
928
1456
  </nmf-form-field>
929
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1457
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "hint", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
930
1458
  }
931
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputTextareaComponent, decorators: [{
1459
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputTextareaComponent, decorators: [{
932
1460
  type: Component,
933
1461
  args: [{
934
1462
  selector: 'nmf-textarea',
@@ -943,6 +1471,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
943
1471
  [errorMessage]="errorMessage()"
944
1472
  >
945
1473
  <textarea
1474
+ #focusable
946
1475
  class="nmf-input"
947
1476
  [ngClass]="classList()"
948
1477
  [class.error]="hasErrors()"
@@ -950,10 +1479,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
950
1479
  [id]="id()"
951
1480
  [rows]="rows()"
952
1481
  [cols]="cols()"
1482
+ [value]="value"
1483
+ [disabled]="disabled()"
953
1484
  [required]="isRequired()"
954
1485
  [placeholder]="placeholder()"
955
- [formControl]="formControl"
1486
+ [autocomplete]="autocompleteAttr()"
956
1487
  (blur)="onTouched()"
1488
+ (input)="onInput($event)"
957
1489
  ></textarea>
958
1490
  </nmf-form-field>
959
1491
  `,
@@ -992,8 +1524,8 @@ class InputTimepickerComponent extends FormControlBase {
992
1524
  this.displayValue.set(this.formatTime(parsed) ?? '');
993
1525
  this.onChange(parsed);
994
1526
  }
995
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputTimepickerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
996
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: InputTimepickerComponent, isStandalone: true, selector: "nmf-timepicker", inputs: { step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1527
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputTimepickerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1528
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.25", type: InputTimepickerComponent, isStandalone: true, selector: "nmf-timepicker", inputs: { step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
997
1529
  <nmf-form-field
998
1530
  [label]="label()"
999
1531
  [isRequired]="isRequired()"
@@ -1001,8 +1533,8 @@ class InputTimepickerComponent extends FormControlBase {
1001
1533
  [errorMessage]="errorMessage()"
1002
1534
  >
1003
1535
  <input
1536
+ #focusable
1004
1537
  type="time"
1005
- autocomplete="off"
1006
1538
  class="nmf-input"
1007
1539
  [ngClass]="classList()"
1008
1540
  [class.error]="hasErrors()"
@@ -1014,13 +1546,14 @@ class InputTimepickerComponent extends FormControlBase {
1014
1546
  [disabled]="disabled()"
1015
1547
  [required]="isRequired()"
1016
1548
  [placeholder]="placeholder()"
1549
+ [autocomplete]="autocompleteAttr()"
1017
1550
  (blur)="onTouched()"
1018
1551
  (input)="onInput($event)"
1019
1552
  />
1020
1553
  </nmf-form-field>
1021
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1554
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "nmf-form-field", inputs: ["label", "isRequired", "loading", "hint", "errorMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1022
1555
  }
1023
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: InputTimepickerComponent, decorators: [{
1556
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: InputTimepickerComponent, decorators: [{
1024
1557
  type: Component,
1025
1558
  args: [{
1026
1559
  selector: 'nmf-timepicker',
@@ -1035,8 +1568,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
1035
1568
  [errorMessage]="errorMessage()"
1036
1569
  >
1037
1570
  <input
1571
+ #focusable
1038
1572
  type="time"
1039
- autocomplete="off"
1040
1573
  class="nmf-input"
1041
1574
  [ngClass]="classList()"
1042
1575
  [class.error]="hasErrors()"
@@ -1048,6 +1581,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
1048
1581
  [disabled]="disabled()"
1049
1582
  [required]="isRequired()"
1050
1583
  [placeholder]="placeholder()"
1584
+ [autocomplete]="autocompleteAttr()"
1051
1585
  (blur)="onTouched()"
1052
1586
  (input)="onInput($event)"
1053
1587
  />
@@ -1082,10 +1616,10 @@ class FormHydrator {
1082
1616
  control.patchValue(value, { emitEvent: false });
1083
1617
  });
1084
1618
  }
1085
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormHydrator, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1086
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormHydrator, providedIn: 'root' });
1619
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormHydrator, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1620
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormHydrator, providedIn: 'root' });
1087
1621
  }
1088
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormHydrator, decorators: [{
1622
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormHydrator, decorators: [{
1089
1623
  type: Injectable,
1090
1624
  args: [{ providedIn: 'root' }]
1091
1625
  }] });
@@ -1105,10 +1639,10 @@ class FormSerializer {
1105
1639
  });
1106
1640
  return result;
1107
1641
  }
1108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormSerializer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1109
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormSerializer, providedIn: 'root' });
1642
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormSerializer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1643
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormSerializer, providedIn: 'root' });
1110
1644
  }
1111
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormSerializer, decorators: [{
1645
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormSerializer, decorators: [{
1112
1646
  type: Injectable,
1113
1647
  args: [{ providedIn: 'root' }]
1114
1648
  }] });
@@ -1185,10 +1719,10 @@ class FormOrchestrator extends FormMapperBase {
1185
1719
  ngOnDestroy() {
1186
1720
  this._logicSubscription.unsubscribe();
1187
1721
  }
1188
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormOrchestrator, deps: [{ token: FormHydrator }, { token: FormSerializer }], target: i0.ɵɵFactoryTarget.Directive });
1189
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: FormOrchestrator, isStandalone: true, usesInheritance: true, ngImport: i0 });
1722
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormOrchestrator, deps: [{ token: FormHydrator }, { token: FormSerializer }], target: i0.ɵɵFactoryTarget.Directive });
1723
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.25", type: FormOrchestrator, isStandalone: true, usesInheritance: true, ngImport: i0 });
1190
1724
  }
1191
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormOrchestrator, decorators: [{
1725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FormOrchestrator, decorators: [{
1192
1726
  type: Directive
1193
1727
  }], ctorParameters: () => [{ type: FormHydrator }, { type: FormSerializer }] });
1194
1728
 
@@ -1200,5 +1734,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
1200
1734
  * Generated bundle index. Do not edit.
1201
1735
  */
1202
1736
 
1203
- export { CurrencyBehavior, FormControlBase, FormHandlerBase, FormHydrator, FormMapperBase, FormOrchestrator, FormSerializer, InputCurrencyComponent, InputDatepickerComponent, InputNumberComponent, InputSelectComponent, InputTextComponent, InputTextareaComponent, InputTimepickerComponent, TextBehavior, formatNumber, getControl, getControlValue, parseNumber };
1737
+ export { CurrencyBehavior, FormControlBase, FormHandlerBase, FormHydrator, FormMapperBase, FormOrchestrator, FormSerializer, InputCurrencyComponent, InputDatepickerComponent, InputLookupComponent, InputNumberComponent, InputSelectComponent, InputTextComponent, InputTextareaComponent, InputTimepickerComponent, LookupBehavior, TextBehavior, formatNumber, getControl, getControlValue, parseNumber };
1204
1738
  //# sourceMappingURL=ng-modular-forms-core.mjs.map