diff --git a/src/app/form-field-info/form-field-info.html b/src/app/form-field-info/form-field-info.html new file mode 100644 index 0000000..e3924bf --- /dev/null +++ b/src/app/form-field-info/form-field-info.html @@ -0,0 +1,7 @@ + diff --git a/src/app/form-field-info/form-field-info.scss b/src/app/form-field-info/form-field-info.scss new file mode 100644 index 0000000..8db87ba --- /dev/null +++ b/src/app/form-field-info/form-field-info.scss @@ -0,0 +1,26 @@ +:host { + display: block; + margin-top: -0.75rem; + margin-bottom: 1rem; +} + +ul { + padding: 0; + + li { + list-style: none; + font-size: 0.8em; + + &.pending { + color: #886b02; + } + + &.invalid { + color: var(--pico-del-color); + } + + &.valid { + color: var(--pico-ins-color); + } + } +} diff --git a/src/app/form-field-info/form-field-info.spec.ts b/src/app/form-field-info/form-field-info.spec.ts new file mode 100644 index 0000000..86d54f7 --- /dev/null +++ b/src/app/form-field-info/form-field-info.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FormFieldInfo } from './form-field-info'; + +describe('FormFieldInfo', () => { + let component: FormFieldInfo; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormFieldInfo] + }) + .compileComponents(); + + fixture = TestBed.createComponent(FormFieldInfo); + component = fixture.componentInstance; + await fixture.whenStable(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/form-field-info/form-field-info.ts b/src/app/form-field-info/form-field-info.ts new file mode 100644 index 0000000..e58d409 --- /dev/null +++ b/src/app/form-field-info/form-field-info.ts @@ -0,0 +1,28 @@ +import { Component, computed, input, signal } from '@angular/core'; +import { FieldTree } from '@angular/forms/signals'; + +import { FIELD_INFO } from '../form-props'; + +@Component({ + selector: 'app-form-field-info', + imports: [], + templateUrl: './form-field-info.html', + styleUrl: './form-field-info.scss', +}) +export class FormFieldInfo { + readonly fieldRef = input.required>(); + + protected readonly messages = computed(() => { + const field = this.fieldRef()(); + let messages: { info: string; cssClass: 'info' | 'pending' | 'valid' | 'invalid' }[] = []; + + if (field.pending()) { + messages = [{ info: 'Checking availability ...', cssClass: 'pending' }]; + } else if (field.touched() && field.errors().length > 0) { + messages = field.errors().map((e) => ({ info: e.message || 'Invalid', cssClass: 'invalid' })); + } else if (field.hasMetadata(FIELD_INFO)) { + messages = [{ info: field.metadata(FIELD_INFO)!, cssClass: field.valid() ? 'valid': 'info' }]; + } + return messages; + }); +} diff --git a/src/app/form-props.ts b/src/app/form-props.ts new file mode 100644 index 0000000..cbfa5f0 --- /dev/null +++ b/src/app/form-props.ts @@ -0,0 +1,3 @@ +import { createMetadataKey } from "@angular/forms/signals"; + +export const FIELD_INFO = createMetadataKey() diff --git a/src/app/multiselect/multiselect.html b/src/app/multiselect/multiselect.html index 0c4de14..25af118 100644 --- a/src/app/multiselect/multiselect.html +++ b/src/app/multiselect/multiselect.html @@ -1,4 +1,4 @@ -