From 439d3d3c950e2f2c3a528a8cfded2cc72c470c8f Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Wed, 15 Jul 2026 03:39:19 +0400 Subject: [PATCH] feat(design-system): add reusable FormField wrapper primitive Standalone, OnPush. Label/hint/error slots, required marker, aria-describedby wiring, role=alert on error. Colors via existing tenant CSS vars with fallbacks. --- .../ui/form-field/form-field.component.html | 23 +++++++++++++ .../ui/form-field/form-field.component.scss | 32 +++++++++++++++++++ .../ui/form-field/form-field.component.ts | 21 ++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/app/shared/ui/form-field/form-field.component.html create mode 100644 src/app/shared/ui/form-field/form-field.component.scss create mode 100644 src/app/shared/ui/form-field/form-field.component.ts diff --git a/src/app/shared/ui/form-field/form-field.component.html b/src/app/shared/ui/form-field/form-field.component.html new file mode 100644 index 0000000..08ef6c5 --- /dev/null +++ b/src/app/shared/ui/form-field/form-field.component.html @@ -0,0 +1,23 @@ +
+ @if (label()) { + + } + +
+ +
+ + @if (error()) { + + } @else if (hint()) { +

{{ hint() }}

+ } +
diff --git a/src/app/shared/ui/form-field/form-field.component.scss b/src/app/shared/ui/form-field/form-field.component.scss new file mode 100644 index 0000000..b04efe7 --- /dev/null +++ b/src/app/shared/ui/form-field/form-field.component.scss @@ -0,0 +1,32 @@ +.app-form-field { + display: flex; + flex-direction: column; + gap: var(--space-xs, 0.25rem); +} + +.app-form-field__label { + font-size: 0.875rem; + font-weight: 600; + color: var(--text-primary, #1f322d); +} + +.app-form-field__required { + color: var(--error-color, #c0392b); + margin-left: 0.125rem; +} + +.app-form-field__control { + display: block; +} + +.app-form-field__hint { + margin: 0; + font-size: 0.8125rem; + color: var(--text-secondary, #6b7280); +} + +.app-form-field__error { + margin: 0; + font-size: 0.8125rem; + color: var(--error-color, #c0392b); +} diff --git a/src/app/shared/ui/form-field/form-field.component.ts b/src/app/shared/ui/form-field/form-field.component.ts new file mode 100644 index 0000000..6f9dd21 --- /dev/null +++ b/src/app/shared/ui/form-field/form-field.component.ts @@ -0,0 +1,21 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; + +let nextFormFieldId = 0; + +@Component({ + selector: 'app-form-field', + standalone: true, + templateUrl: './form-field.component.html', + styleUrl: './form-field.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FormFieldComponent { + readonly label = input(null); + readonly hint = input(null); + readonly error = input(null); + readonly required = input(false); + + protected readonly fieldId = `app-form-field-${++nextFormFieldId}`; + protected readonly hintId = `${this.fieldId}-hint`; + protected readonly errorId = `${this.fieldId}-error`; +}