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.
This commit is contained in:
sdarbinyan
2026-07-15 03:39:19 +04:00
parent 27ff3169b9
commit 439d3d3c95
3 changed files with 76 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
<div class="app-form-field">
@if (label()) {
<label class="app-form-field__label" [for]="fieldId">
{{ label() }}
@if (required()) {
<span class="app-form-field__required" aria-hidden="true">*</span>
}
</label>
}
<div
class="app-form-field__control"
[attr.aria-describedby]="error() ? errorId : (hint() ? hintId : null)"
>
<ng-content />
</div>
@if (error()) {
<p class="app-form-field__error" [id]="errorId" role="alert">{{ error() }}</p>
} @else if (hint()) {
<p class="app-form-field__hint" [id]="hintId">{{ hint() }}</p>
}
</div>

View File

@@ -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);
}

View File

@@ -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<string | null>(null);
readonly hint = input<string | null>(null);
readonly error = input<string | null>(null);
readonly required = input(false);
protected readonly fieldId = `app-form-field-${++nextFormFieldId}`;
protected readonly hintId = `${this.fieldId}-hint`;
protected readonly errorId = `${this.fieldId}-error`;
}