import { booleanAttribute, Directive, input, model, signal } from '@angular/core'; import { AbstractControl, ValidationErrors } from '@angular/forms'; import type { DisabledReason, FormValueControl, ValidationError, WithOptionalFieldTree, } from '@angular/forms/signals'; @Directive() export abstract class BaseInput implements FormValueControl { id = input(''); label = input(''); class = input(''); icon = input(''); name = input(''); required = input(false, { transform: booleanAttribute }); disabled = input(false, { transform: booleanAttribute }); readonly = input(false, { transform: booleanAttribute }); hidden = input(false, { transform: booleanAttribute }); invalid = input(false, { transform: booleanAttribute }); pending = input(false, { transform: booleanAttribute }); dirty = input(false, { transform: booleanAttribute }); maxLength = input(undefined); minLength = input(undefined); min = input(undefined); max = input(undefined); pattern = input([]); disabledReasons = input[]>([]); errors = input([]); touched = model(false); value = model({} as T); private readonly accessorDisabled = signal(false); private readonly legacyControl = signal(null); private readonly legacyErrors = signal(null); readonly defaultClasses = 'border-primary border-2 rounded-sm focus:border-primary focus:ring-primary'; get feedbackState() { return this.legacyControl() ?? this.invalid(); } get displayErrors() { const errors = this.errors(); return errors.length > 0 ? errors : this.legacyErrors(); } isDisabled() { return this.disabled() || this.accessorDisabled(); } onInput(event: Event) { const target = event.target as HTMLInputElement | HTMLSelectElement; const value = target.value as T; this.value.set(value); } onBlur() { this.touched.set(true); } setLegacyDisabledState(isDisabled: boolean) { this.accessorDisabled.set(isDisabled); } setLegacyFormState(control: AbstractControl | null) { this.legacyControl.set(control); this.legacyErrors.set(control?.errors ?? null); } }