Release @pi/ui 0.0.9: a field shows its errors once touched
An untouched field with errors was painted red from the start, so a form with required fields opened full of «Campo obligatorio». Text fields, selects, checkboxes, radio groups and file uploads now wait until the field is touched (blur, or the form's submit()). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,12 @@ hecho **no se pueden enlazar a mano** esas entradas en un elemento que ya use
|
||||
`[formField]`: Angular lo rechaza con `NG8022`. Los validadores van en el
|
||||
`form()`, no en la plantilla.
|
||||
|
||||
Los errores se ven cuando el campo está **tocado**: al salir de él, o al
|
||||
enviar con `submit()` de Signal Forms, que marca todo el formulario. Un campo
|
||||
obligatorio vacío no sale en rojo nada más abrir el formulario. Para volver a
|
||||
abrir un formulario como nuevo, `f().reset(valor)` pone los valores y quita el
|
||||
estado de tocado.
|
||||
|
||||
Se puede ver funcionando en la app `playground` (`nx serve playground`).
|
||||
|
||||
## Theming: tokens CSS
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@pi/ui",
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.9",
|
||||
"description": "Librería de componentes Angular standalone (botones, campos con Signal Forms, cards, charts, drawer/hub/modal, theming vía tokens CSS...).",
|
||||
"license": "MIT",
|
||||
"generators": "./generators.json",
|
||||
|
||||
@@ -59,6 +59,7 @@ export class PiFileUploadComponent implements FormValueControl<File[]> {
|
||||
|
||||
readonly errors = input<readonly ValidationError.WithOptionalFieldTree[]>([]);
|
||||
readonly disabled = input(false);
|
||||
readonly touched = input(false);
|
||||
readonly required = input(false);
|
||||
readonly name = input('');
|
||||
|
||||
@@ -94,7 +95,10 @@ export class PiFileUploadComponent implements FormValueControl<File[]> {
|
||||
this.errors().map((error) => error.message ?? error.kind),
|
||||
);
|
||||
|
||||
protected readonly hasError = computed(() => this.errors().length > 0);
|
||||
/** El error se ve cuando el campo está tocado (al salir de él o al enviar el formulario), no antes. */
|
||||
protected readonly hasError = computed(
|
||||
() => this.touched() && this.errors().length > 0,
|
||||
);
|
||||
|
||||
/* --- Arrastrar y soltar ----------------------------------------------- */
|
||||
|
||||
|
||||
@@ -76,7 +76,10 @@ export abstract class PiBaseFormFieldComponent<
|
||||
this.errors().map((error) => error.message ?? error.kind),
|
||||
);
|
||||
|
||||
protected readonly hasError = computed(() => this.errors().length > 0);
|
||||
/** El error se ve cuando el campo está tocado (al salir de él o al enviar el formulario), no antes. */
|
||||
protected readonly hasError = computed(
|
||||
() => this.touched() && this.errors().length > 0,
|
||||
);
|
||||
|
||||
/**
|
||||
* `MatInput` normalmente deriva `errorState` de un `NgControl` (`ngModel`,
|
||||
|
||||
@@ -49,6 +49,7 @@ export class PiCheckboxComponent implements FormCheckboxControl {
|
||||
|
||||
readonly checked = model(false);
|
||||
readonly disabled = input(false);
|
||||
readonly touched = input(false);
|
||||
readonly required = input(false);
|
||||
readonly name = input('');
|
||||
readonly errors = input<readonly ValidationError.WithOptionalFieldTree[]>([]);
|
||||
@@ -70,7 +71,10 @@ export class PiCheckboxComponent implements FormCheckboxControl {
|
||||
this.errors().map((error) => error.message ?? error.kind),
|
||||
);
|
||||
|
||||
protected readonly hasError = computed(() => this.errors().length > 0);
|
||||
/** El error se ve cuando el campo está tocado (al salir de él o al enviar el formulario), no antes. */
|
||||
protected readonly hasError = computed(
|
||||
() => this.touched() && this.errors().length > 0,
|
||||
);
|
||||
|
||||
/**
|
||||
* `name` solo lo rellena la directiva `FormField`; suelto llega vacío. Sin
|
||||
|
||||
@@ -57,6 +57,7 @@ export class PiRadioGroupComponent<
|
||||
|
||||
readonly errors = input<readonly ValidationError.WithOptionalFieldTree[]>([]);
|
||||
readonly disabled = input(false);
|
||||
readonly touched = input(false);
|
||||
readonly required = input(false);
|
||||
readonly name = input('');
|
||||
|
||||
@@ -77,7 +78,10 @@ export class PiRadioGroupComponent<
|
||||
this.errors().map((error) => error.message ?? error.kind),
|
||||
);
|
||||
|
||||
protected readonly hasError = computed(() => this.errors().length > 0);
|
||||
/** El error se ve cuando el campo está tocado (al salir de él o al enviar el formulario), no antes. */
|
||||
protected readonly hasError = computed(
|
||||
() => this.touched() && this.errors().length > 0,
|
||||
);
|
||||
|
||||
/** Agrupa los `<input type="radio">`; debe ser único por grupo. */
|
||||
private readonly uniqueName = `pi-radio-group-${nextUniqueId++}`;
|
||||
|
||||
@@ -51,8 +51,9 @@ export abstract class PiBaseSelectComponent<
|
||||
/** Se emite cuando el usuario interactúa; `FormField` lo usa para marcar `touched`. */
|
||||
readonly touch = output<void>();
|
||||
|
||||
/** El error se ve cuando el campo está tocado, no antes. */
|
||||
protected get hasError(): boolean {
|
||||
return this.errors().length > 0;
|
||||
return this.touched() && this.errors().length > 0;
|
||||
}
|
||||
|
||||
// ======================
|
||||
|
||||
Reference in New Issue
Block a user