@egose/shadcn-theme-ng 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/form-autocomplete/README.md +20 -19
  3. package/form-autocomplete/fesm2022/form-autocomplete.mjs +44 -9
  4. package/form-autocomplete/types/form-autocomplete.d.ts +22 -1
  5. package/form-checkbox/README.md +20 -19
  6. package/form-checkbox/fesm2022/form-checkbox.mjs +99 -15
  7. package/form-checkbox/types/form-checkbox.d.ts +43 -3
  8. package/form-combobox/README.md +21 -20
  9. package/form-combobox/fesm2022/form-combobox.mjs +44 -9
  10. package/form-combobox/types/form-combobox.d.ts +22 -1
  11. package/form-date-picker/README.md +28 -27
  12. package/form-date-picker/fesm2022/form-date-picker.mjs +45 -15
  13. package/form-date-picker/types/form-date-picker.d.ts +22 -1
  14. package/form-date-picker-multi/README.md +28 -27
  15. package/form-date-picker-multi/fesm2022/form-date-picker-multi.mjs +45 -15
  16. package/form-date-picker-multi/types/form-date-picker-multi.d.ts +22 -1
  17. package/form-date-range-picker/README.md +28 -27
  18. package/form-date-range-picker/fesm2022/form-date-range-picker.mjs +45 -15
  19. package/form-date-range-picker/types/form-date-range-picker.d.ts +22 -1
  20. package/form-field/README.md +9 -0
  21. package/form-field/fesm2022/form-field.mjs +97 -5
  22. package/form-field/types/form-field.d.ts +96 -2
  23. package/form-field-simple/fesm2022/form-field-simple.mjs +15 -1
  24. package/form-field-simple/types/form-field-simple.d.ts +9 -2
  25. package/form-input-otp/README.md +17 -16
  26. package/form-input-otp/fesm2022/form-input-otp.mjs +43 -8
  27. package/form-input-otp/types/form-input-otp.d.ts +22 -1
  28. package/form-month-year-picker/README.md +26 -25
  29. package/form-month-year-picker/fesm2022/form-month-year-picker.mjs +45 -15
  30. package/form-month-year-picker/types/form-month-year-picker.d.ts +22 -1
  31. package/form-native-select/README.md +18 -17
  32. package/form-native-select/fesm2022/form-native-select.mjs +44 -14
  33. package/form-native-select/types/form-native-select.d.ts +22 -1
  34. package/form-phone-input/README.md +23 -22
  35. package/form-phone-input/fesm2022/form-phone-input.mjs +44 -14
  36. package/form-phone-input/types/form-phone-input.d.ts +22 -1
  37. package/form-radio-group/README.md +18 -17
  38. package/form-radio-group/fesm2022/form-radio-group.mjs +44 -14
  39. package/form-radio-group/types/form-radio-group.d.ts +22 -1
  40. package/form-searchable-multiselect/README.md +18 -17
  41. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +44 -14
  42. package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +22 -1
  43. package/form-select/README.md +20 -19
  44. package/form-select/fesm2022/form-select.mjs +44 -14
  45. package/form-select/types/form-select.d.ts +22 -1
  46. package/form-slider/README.md +19 -18
  47. package/form-slider/fesm2022/form-slider.mjs +43 -8
  48. package/form-slider/types/form-slider.d.ts +22 -1
  49. package/form-switch/README.md +16 -15
  50. package/form-switch/fesm2022/form-switch.mjs +44 -14
  51. package/form-switch/types/form-switch.d.ts +22 -1
  52. package/form-text-input/README.md +27 -26
  53. package/form-text-input/fesm2022/form-text-input.mjs +44 -14
  54. package/form-text-input/types/form-text-input.d.ts +22 -1
  55. package/form-textarea/README.md +23 -22
  56. package/form-textarea/fesm2022/form-textarea.mjs +44 -14
  57. package/form-textarea/types/form-textarea.d.ts +22 -1
  58. package/form-toggle/README.md +17 -16
  59. package/form-toggle/fesm2022/form-toggle.mjs +47 -10
  60. package/form-toggle/types/form-toggle.d.ts +22 -3
  61. package/form-toggle-group/README.md +20 -19
  62. package/form-toggle-group/fesm2022/form-toggle-group.mjs +44 -14
  63. package/form-toggle-group/types/form-toggle-group.d.ts +22 -1
  64. package/package.json +5 -1
  65. package/stepper/README.md +353 -0
  66. package/stepper/fesm2022/stepper.mjs +396 -0
  67. package/stepper/package.json +24 -0
  68. package/stepper/types/stepper.d.ts +116 -0
@@ -3,12 +3,20 @@ import { ClassValue } from 'clsx';
3
3
 
4
4
  declare class EgFormMonthYearPicker {
5
5
  private readonly formGroupDirective;
6
+ private readonly _errorMessages;
6
7
  private readonly generatedId;
7
8
  private readonly _config;
9
+ private readonly _shared;
8
10
  label: _angular_core.InputSignal<string | undefined>;
9
11
  controlId: _angular_core.InputSignal<string | undefined>;
10
12
  controlName: _angular_core.InputSignal<string>;
11
13
  error: _angular_core.InputSignal<string | undefined>;
14
+ /**
15
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
16
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
17
+ * for manual-only messages.
18
+ */
19
+ autoError: _angular_core.InputSignal<boolean>;
12
20
  hint: _angular_core.InputSignal<string | undefined>;
13
21
  id: _angular_core.InputSignal<string | undefined>;
14
22
  name: _angular_core.InputSignal<string | undefined>;
@@ -26,6 +34,19 @@ declare class EgFormMonthYearPicker {
26
34
  readonly effectiveId: _angular_core.Signal<string>;
27
35
  readonly errorId: _angular_core.Signal<string>;
28
36
  readonly hintId: _angular_core.Signal<string>;
37
+ /**
38
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
39
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
40
+ * computed): `ValidationErrors` is not a signal, so the control must be read
41
+ * fresh on every change-detection pass.
42
+ */
43
+ protected resolvedError(): string | undefined;
44
+ /**
45
+ * Whether the error is surfaced: message present + control invalid +
46
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
47
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
48
+ */
49
+ protected showError(): boolean;
29
50
  /**
30
51
  * Bounds projected onto the picker's `Date` model. The cast keeps the
31
52
  * template's generic inference on `Date` while passing runtime values
@@ -47,7 +68,7 @@ declare class EgFormMonthYearPicker {
47
68
  $errorClass: _angular_core.Signal<string>;
48
69
  $hintClass: _angular_core.Signal<string>;
49
70
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormMonthYearPicker, never>;
50
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormMonthYearPicker, "eg-form-month-year-picker", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "controlName": { "alias": "controlName"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "autoCloseOnSelect": { "alias": "autoCloseOnSelect"; "required": false; "isSignal": true; }; "formatDate": { "alias": "formatDate"; "required": false; "isSignal": true; }; "transformDate": { "alias": "transformDate"; "required": false; "isSignal": true; }; "parseDate": { "alias": "parseDate"; "required": false; "isSignal": true; }; "formatInputDate": { "alias": "formatInputDate"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "pickerClass": { "alias": "pickerClass"; "required": false; "isSignal": true; }; "inputClass": { "alias": "inputClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
71
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormMonthYearPicker, "eg-form-month-year-picker", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "controlName": { "alias": "controlName"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "autoError": { "alias": "autoError"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "autoCloseOnSelect": { "alias": "autoCloseOnSelect"; "required": false; "isSignal": true; }; "formatDate": { "alias": "formatDate"; "required": false; "isSignal": true; }; "transformDate": { "alias": "transformDate"; "required": false; "isSignal": true; }; "parseDate": { "alias": "parseDate"; "required": false; "isSignal": true; }; "formatInputDate": { "alias": "formatInputDate"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "pickerClass": { "alias": "pickerClass"; "required": false; "isSignal": true; }; "inputClass": { "alias": "inputClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
51
72
  }
52
73
 
53
74
  export { EgFormMonthYearPicker };
@@ -76,23 +76,24 @@ Selector (from source): `eg-form-native-select` (standalone component, host `tw:
76
76
 
77
77
  ### `EgFormNativeSelect` — `eg-form-native-select`
78
78
 
79
- | Input | Type | Default | Description |
80
- | ------------- | ------------------------------- | ------- | ---------------------------------------------------------------------- |
81
- | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
82
- | `label` | `string \| undefined` | — | Label text (hidden when omitted). |
83
- | `error` | `string \| undefined` | — | Error text shown when invalid. |
84
- | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
85
- | `controlId` | `string \| undefined` | — | Explicit id (first priority for `effectiveId`). |
86
- | `id` | `string \| undefined` | — | Fallback id (second priority). |
87
- | `name` | `string \| undefined` | — | Native `name` forwarded to the inner `<select>` (`controlName` wins). |
88
- | `disabled` | `boolean` | `false` | Locks interaction (form control stays enabled). |
89
- | `required` | `boolean` | `false` | Shows a red `*` next to the label. |
90
- | `options` | `{ value, label, disabled? }[]` | `[]` | Rendered as native `<option>` elements. |
91
- | `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
92
- | `labelClass` | `string` | `''` | Extra label classes (base `tw:mb-1 tw:gap-0`). |
93
- | `selectClass` | `string` | `''` | Extra inner-select classes, merged into `HlmNativeSelect.selectClass`. |
94
- | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
95
- | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
79
+ | Input | Type | Default | Description |
80
+ | ------------- | ------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
81
+ | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
82
+ | `label` | `string \| undefined` | — | Label text (hidden when omitted). |
83
+ | `error` | `string \| undefined` | — | Error text shown when invalid. |
84
+ | `autoError` | `boolean` | `true` | Auto-resolve the message from the control's `ValidationErrors` when `error` is unset. Explicit `error` always wins; `error=""` counts as unset. Global wording via `provideEgFormErrorMessages`. |
85
+ | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
86
+ | `controlId` | `string \| undefined` | — | Explicit id (first priority for `effectiveId`). |
87
+ | `id` | `string \| undefined` | — | Fallback id (second priority). |
88
+ | `name` | `string \| undefined` | — | Native `name` forwarded to the inner `<select>` (`controlName` wins). |
89
+ | `disabled` | `boolean` | `false` | Locks interaction (form control stays enabled). |
90
+ | `required` | `boolean` | `false` | Shows a red `*` next to the label. |
91
+ | `options` | `{ value, label, disabled? }[]` | `[]` | Rendered as native `<option>` elements. |
92
+ | `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
93
+ | `labelClass` | `string` | `''` | Extra label classes (base `tw:mb-1 tw:gap-0`). |
94
+ | `selectClass` | `string` | `''` | Extra inner-select classes, merged into `HlmNativeSelect.selectClass`. |
95
+ | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
96
+ | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
96
97
 
97
98
  | Member | Description |
98
99
  | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, input, computed, Component } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormGroupDirective, ReactiveFormsModule, ControlContainer } from '@angular/forms';
5
- import { HlmFormIdGenerator, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng/form-field';
5
+ import { injectEgFormErrorMessages, HlmFormIdGenerator, injectEgFormSharedConfig, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng/label';
7
7
  import { HlmNativeSelect } from '@egose/shadcn-theme-ng/native-select';
8
8
  import { hlm } from '@egose/shadcn-theme-ng/utils';
@@ -17,8 +17,10 @@ function injectEgFormNativeSelectConfig() {
17
17
 
18
18
  class EgFormNativeSelect {
19
19
  formGroupDirective = inject(FormGroupDirective);
20
+ _errorMessages = injectEgFormErrorMessages();
20
21
  generatedId = inject(HlmFormIdGenerator).generate('eg-form-native-select');
21
22
  _config = injectEgFormNativeSelectConfig();
23
+ _shared = injectEgFormSharedConfig();
22
24
  label = input(undefined, /* @ts-ignore */
23
25
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
24
26
  controlId = input(undefined, /* @ts-ignore */
@@ -27,6 +29,13 @@ class EgFormNativeSelect {
27
29
  ...(ngDevMode ? [{ debugName: "controlName" }] : /* istanbul ignore next */ []));
28
30
  error = input(undefined, /* @ts-ignore */
29
31
  ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
32
+ /**
33
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
34
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
35
+ * for manual-only messages.
36
+ */
37
+ autoError = input(true, /* @ts-ignore */
38
+ ...(ngDevMode ? [{ debugName: "autoError" }] : /* istanbul ignore next */ []));
30
39
  hint = input(undefined, /* @ts-ignore */
31
40
  ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
32
41
  id = input(undefined, /* @ts-ignore */
@@ -45,13 +54,34 @@ class EgFormNativeSelect {
45
54
  ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
46
55
  hintId = computed(() => `${this.effectiveId()}-hint`, /* @ts-ignore */
47
56
  ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
48
- describedBy() {
57
+ /**
58
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
59
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
60
+ * computed): `ValidationErrors` is not a signal, so the control must be read
61
+ * fresh on every change-detection pass.
62
+ */
63
+ resolvedError() {
64
+ const explicit = this.error();
65
+ if (explicit)
66
+ return explicit;
67
+ if (!this.autoError())
68
+ return undefined;
69
+ const control = this.formGroupDirective.form.get(this.controlName());
70
+ return resolveEgFormError(control?.errors ?? null, this.label(), this._errorMessages);
71
+ }
72
+ /**
73
+ * Whether the error is surfaced: message present + control invalid +
74
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
75
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
76
+ */
77
+ showError() {
49
78
  const control = this.formGroupDirective.form.get(this.controlName());
50
- return this.error() && control?.invalid && (control.dirty || control.touched)
51
- ? this.errorId()
52
- : this.hint()
53
- ? this.hintId()
54
- : null;
79
+ return (!!this.resolvedError() &&
80
+ !!control?.invalid &&
81
+ (control.dirty || control.touched || this.formGroupDirective.submitted));
82
+ }
83
+ describedBy() {
84
+ return this.showError() ? this.errorId() : this.hint() ? this.hintId() : null;
55
85
  }
56
86
  // Styling
57
87
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
@@ -66,16 +96,16 @@ class EgFormNativeSelect {
66
96
  // Computed classes (library base < global config < per-instance)
67
97
  $userClass = computed(() => hlm("w-full", this.userClass()), /* @ts-ignore */
68
98
  ...(ngDevMode ? [{ debugName: "$userClass" }] : /* istanbul ignore next */ []));
69
- $labelClass = computed(() => hlm("mb-1 gap-0", this._config.labelClass, this.labelClass()), /* @ts-ignore */
99
+ $labelClass = computed(() => hlm("mb-1 gap-0", this._shared.labelClass, this._config.labelClass, this.labelClass()), /* @ts-ignore */
70
100
  ...(ngDevMode ? [{ debugName: "$labelClass" }] : /* istanbul ignore next */ []));
71
- $selectClass = computed(() => hlm("w-full", this._config.selectClass, this.selectClass()), /* @ts-ignore */
101
+ $selectClass = computed(() => hlm("w-full", this._shared.selectClass, this._config.selectClass, this.selectClass()), /* @ts-ignore */
72
102
  ...(ngDevMode ? [{ debugName: "$selectClass" }] : /* istanbul ignore next */ []));
73
- $errorClass = computed(() => hlm("mt-0", this._config.errorClass, this.errorClass()), /* @ts-ignore */
103
+ $errorClass = computed(() => hlm("mt-0", this._shared.errorClass, this._config.errorClass, this.errorClass()), /* @ts-ignore */
74
104
  ...(ngDevMode ? [{ debugName: "$errorClass" }] : /* istanbul ignore next */ []));
75
- $hintClass = computed(() => hlm("mt-0", this._config.hintClass, this.hintClass()), /* @ts-ignore */
105
+ $hintClass = computed(() => hlm("mt-0", this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
76
106
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
77
107
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormNativeSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
78
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormNativeSelect, isStandalone: true, selector: "eg-form-native-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, selectClass: { classPropertyName: "selectClass", publicName: "selectClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: "\n @let lbl = label();\n @let cnm = controlName();\n @let err = error();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <hlm-native-select\n [selectId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [ariaDescribedby]=\"describedBy()\"\n [disabled]=\"disabled()\"\n [formControlName]=\"cnm\"\n [selectClass]=\"$selectClass()\"\n >\n @for (option of options(); track option.value) {\n <option class=\"bg-[Canvas] text-[CanvasText]\" [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</option>\n }\n </hlm-native-select>\n\n @if (err) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ err }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ", isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HlmFormField, selector: "hlm-form-field", inputs: ["class"] }, { kind: "directive", type: HlmError, selector: "hlm-error", inputs: ["class"] }, { kind: "directive", type: HlmHint, selector: "hlm-hint", inputs: ["class"] }, { kind: "directive", type: HlmLabel, selector: "[hlmLabel]", inputs: ["class"] }, { kind: "component", type: HlmNativeSelect, selector: "hlm-native-select", inputs: ["selectId", "name", "ariaDescribedby", "selectClass", "selectIconClass", "size", "disabled", "forceInvalid", "aria-invalid", "value"], outputs: ["valueChange"] }] });
108
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormNativeSelect, isStandalone: true, selector: "eg-form-native-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, autoError: { classPropertyName: "autoError", publicName: "autoError", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, selectClass: { classPropertyName: "selectClass", publicName: "selectClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: "\n @let lbl = label();\n @let cnm = controlName();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <hlm-native-select\n [selectId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [ariaDescribedby]=\"describedBy()\"\n [disabled]=\"disabled()\"\n [formControlName]=\"cnm\"\n [selectClass]=\"$selectClass()\"\n >\n @for (option of options(); track option.value) {\n <option\n class=\"bg-[Canvas] text-[CanvasText]\"\n [value]=\"option.value\"\n [disabled]=\"option.disabled ?? false\"\n >\n {{ option.label }}\n </option>\n }\n </hlm-native-select>\n\n @if (showError()) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ resolvedError() }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ", isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HlmFormField, selector: "hlm-form-field", inputs: ["class"] }, { kind: "directive", type: HlmError, selector: "hlm-error", inputs: ["class"] }, { kind: "directive", type: HlmHint, selector: "hlm-hint", inputs: ["class"] }, { kind: "directive", type: HlmLabel, selector: "[hlmLabel]", inputs: ["class"] }, { kind: "component", type: HlmNativeSelect, selector: "hlm-native-select", inputs: ["selectId", "name", "ariaDescribedby", "selectClass", "selectIconClass", "size", "disabled", "forceInvalid", "aria-invalid", "value"], outputs: ["valueChange"] }] });
79
109
  }
80
110
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormNativeSelect, decorators: [{
81
111
  type: Component,
@@ -87,9 +117,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
87
117
  },
88
118
  imports: [ReactiveFormsModule, HlmFormField, HlmError, HlmHint, HlmLabel, HlmNativeSelect],
89
119
  providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
90
- template: "\n @let lbl = label();\n @let cnm = controlName();\n @let err = error();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <hlm-native-select\n [selectId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [ariaDescribedby]=\"describedBy()\"\n [disabled]=\"disabled()\"\n [formControlName]=\"cnm\"\n [selectClass]=\"$selectClass()\"\n >\n @for (option of options(); track option.value) {\n <option class=\"bg-[Canvas] text-[CanvasText]\" [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</option>\n }\n </hlm-native-select>\n\n @if (err) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ err }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ",
120
+ template: "\n @let lbl = label();\n @let cnm = controlName();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <hlm-native-select\n [selectId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [ariaDescribedby]=\"describedBy()\"\n [disabled]=\"disabled()\"\n [formControlName]=\"cnm\"\n [selectClass]=\"$selectClass()\"\n >\n @for (option of options(); track option.value) {\n <option\n class=\"bg-[Canvas] text-[CanvasText]\"\n [value]=\"option.value\"\n [disabled]=\"option.disabled ?? false\"\n >\n {{ option.label }}\n </option>\n }\n </hlm-native-select>\n\n @if (showError()) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ resolvedError() }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ",
91
121
  }]
92
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], controlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlName", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], selectClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
122
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], controlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlName", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], autoError: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoError", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], selectClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
93
123
 
94
124
  /*
95
125
  * Public API Surface of form-native-select
@@ -9,12 +9,20 @@ interface NativeSelectOption {
9
9
  }
10
10
  declare class EgFormNativeSelect {
11
11
  private readonly formGroupDirective;
12
+ private readonly _errorMessages;
12
13
  private readonly generatedId;
13
14
  private readonly _config;
15
+ private readonly _shared;
14
16
  label: _angular_core.InputSignal<string | undefined>;
15
17
  controlId: _angular_core.InputSignal<string | undefined>;
16
18
  controlName: _angular_core.InputSignal<string>;
17
19
  error: _angular_core.InputSignal<string | undefined>;
20
+ /**
21
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
22
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
23
+ * for manual-only messages.
24
+ */
25
+ autoError: _angular_core.InputSignal<boolean>;
18
26
  hint: _angular_core.InputSignal<string | undefined>;
19
27
  id: _angular_core.InputSignal<string | undefined>;
20
28
  name: _angular_core.InputSignal<string | undefined>;
@@ -24,6 +32,19 @@ declare class EgFormNativeSelect {
24
32
  readonly effectiveId: _angular_core.Signal<string>;
25
33
  readonly errorId: _angular_core.Signal<string>;
26
34
  readonly hintId: _angular_core.Signal<string>;
35
+ /**
36
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
37
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
38
+ * computed): `ValidationErrors` is not a signal, so the control must be read
39
+ * fresh on every change-detection pass.
40
+ */
41
+ protected resolvedError(): string | undefined;
42
+ /**
43
+ * Whether the error is surfaced: message present + control invalid +
44
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
45
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
46
+ */
47
+ protected showError(): boolean;
27
48
  describedBy(): string | null;
28
49
  userClass: _angular_core.InputSignal<ClassValue>;
29
50
  labelClass: _angular_core.InputSignal<string>;
@@ -36,7 +57,7 @@ declare class EgFormNativeSelect {
36
57
  $errorClass: _angular_core.Signal<string>;
37
58
  $hintClass: _angular_core.Signal<string>;
38
59
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormNativeSelect, never>;
39
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormNativeSelect, "eg-form-native-select", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "controlName": { "alias": "controlName"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "selectClass": { "alias": "selectClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
60
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormNativeSelect, "eg-form-native-select", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "controlName": { "alias": "controlName"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "autoError": { "alias": "autoError"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "selectClass": { "alias": "selectClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
40
61
  }
41
62
 
42
63
  interface EgFormNativeSelectConfig {
@@ -71,28 +71,29 @@ Selector (from source): `eg-form-phone-input` (standalone component, host `tw:w-
71
71
 
72
72
  ### `EgFormPhoneInput` — `eg-form-phone-input`
73
73
 
74
- | Input | Type | Default | Description |
75
- | ------------------- | ---------------------------- | ----------------------- | ------------------------------------------------------------------ |
76
- | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
77
- | `label` | `string \| undefined` | — | Label text (hidden when omitted). |
78
- | `error` | `string \| undefined` | — | Error text shown when invalid. |
79
- | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
80
- | `controlId` | `string \| undefined` | — | Explicit id (first priority for `effectiveId`). |
81
- | `id` | `string \| undefined` | — | Fallback id (second priority). |
82
- | `name` | `string \| undefined` | — | Native `name` forwarded to the inner input (`controlName` wins). |
83
- | `placeholder` | `string` | `'(555) 123-4567'` | Input placeholder. |
84
- | `autocomplete` | `string` | `'tel'` | Native autocomplete token. |
85
- | `readonly` | `boolean` | `false` | Native `readonly` forwarded to the inner input. |
86
- | `disabled` | `boolean` | `false` | Locks interaction (form control stays enabled). |
87
- | `required` | `boolean` | `false` | Shows a red `*` next to the label. |
88
- | `maxDigits` | `number` | `10` | Maximum digit count kept in the model. |
89
- | `modelFormat` | `'digits' \| 'formatted'` | `'digits'` | Model shape: raw digits or formatted display text. |
90
- | `formatPhoneNumber` | `(digits: string) => string` | `formatNanpPhoneNumber` | Display formatter forwarded to the input. |
91
- | `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
92
- | `labelClass` | `string` | `''` | Extra label classes (base `tw:mb-1 tw:gap-0`). |
93
- | `inputClass` | `string` | `''` | Extra inner-input classes. |
94
- | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
95
- | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
74
+ | Input | Type | Default | Description |
75
+ | ------------------- | ---------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
76
+ | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
77
+ | `label` | `string \| undefined` | — | Label text (hidden when omitted). |
78
+ | `error` | `string \| undefined` | — | Error text shown when invalid. |
79
+ | `autoError` | `boolean` | `true` | Auto-resolve the message from the control's `ValidationErrors` when `error` is unset. Explicit `error` always wins; `error=""` counts as unset. Global wording via `provideEgFormErrorMessages`. |
80
+ | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
81
+ | `controlId` | `string \| undefined` | — | Explicit id (first priority for `effectiveId`). |
82
+ | `id` | `string \| undefined` | — | Fallback id (second priority). |
83
+ | `name` | `string \| undefined` | — | Native `name` forwarded to the inner input (`controlName` wins). |
84
+ | `placeholder` | `string` | `'(555) 123-4567'` | Input placeholder. |
85
+ | `autocomplete` | `string` | `'tel'` | Native autocomplete token. |
86
+ | `readonly` | `boolean` | `false` | Native `readonly` forwarded to the inner input. |
87
+ | `disabled` | `boolean` | `false` | Locks interaction (form control stays enabled). |
88
+ | `required` | `boolean` | `false` | Shows a red `*` next to the label. |
89
+ | `maxDigits` | `number` | `10` | Maximum digit count kept in the model. |
90
+ | `modelFormat` | `'digits' \| 'formatted'` | `'digits'` | Model shape: raw digits or formatted display text. |
91
+ | `formatPhoneNumber` | `(digits: string) => string` | `formatNanpPhoneNumber` | Display formatter forwarded to the input. |
92
+ | `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
93
+ | `labelClass` | `string` | `''` | Extra label classes (base `tw:mb-1 tw:gap-0`). |
94
+ | `inputClass` | `string` | `''` | Extra inner-input classes. |
95
+ | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
96
+ | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
96
97
 
97
98
  | Member | Description |
98
99
  | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, input, computed, Component } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormGroupDirective, ReactiveFormsModule, ControlContainer } from '@angular/forms';
5
- import { HlmFormIdGenerator, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng/form-field';
5
+ import { injectEgFormErrorMessages, HlmFormIdGenerator, injectEgFormSharedConfig, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng/label';
7
7
  import { formatNanpPhoneNumber, HlmPhoneInput } from '@egose/shadcn-theme-ng/phone-input';
8
8
  import { hlm } from '@egose/shadcn-theme-ng/utils';
@@ -17,8 +17,10 @@ function injectEgFormPhoneInputConfig() {
17
17
 
18
18
  class EgFormPhoneInput {
19
19
  formGroupDirective = inject(FormGroupDirective);
20
+ _errorMessages = injectEgFormErrorMessages();
20
21
  generatedId = inject(HlmFormIdGenerator).generate('eg-form-phone-input');
21
22
  _config = injectEgFormPhoneInputConfig();
23
+ _shared = injectEgFormSharedConfig();
22
24
  label = input(undefined, /* @ts-ignore */
23
25
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
24
26
  controlId = input(undefined, /* @ts-ignore */
@@ -27,6 +29,13 @@ class EgFormPhoneInput {
27
29
  ...(ngDevMode ? [{ debugName: "controlName" }] : /* istanbul ignore next */ []));
28
30
  error = input(undefined, /* @ts-ignore */
29
31
  ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
32
+ /**
33
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
34
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
35
+ * for manual-only messages.
36
+ */
37
+ autoError = input(true, /* @ts-ignore */
38
+ ...(ngDevMode ? [{ debugName: "autoError" }] : /* istanbul ignore next */ []));
30
39
  hint = input(undefined, /* @ts-ignore */
31
40
  ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
32
41
  id = input(undefined, /* @ts-ignore */
@@ -55,13 +64,34 @@ class EgFormPhoneInput {
55
64
  ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
56
65
  hintId = computed(() => `${this.effectiveId()}-hint`, /* @ts-ignore */
57
66
  ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
58
- describedBy() {
67
+ /**
68
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
69
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
70
+ * computed): `ValidationErrors` is not a signal, so the control must be read
71
+ * fresh on every change-detection pass.
72
+ */
73
+ resolvedError() {
74
+ const explicit = this.error();
75
+ if (explicit)
76
+ return explicit;
77
+ if (!this.autoError())
78
+ return undefined;
79
+ const control = this.formGroupDirective.form.get(this.controlName());
80
+ return resolveEgFormError(control?.errors ?? null, this.label(), this._errorMessages);
81
+ }
82
+ /**
83
+ * Whether the error is surfaced: message present + control invalid +
84
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
85
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
86
+ */
87
+ showError() {
59
88
  const control = this.formGroupDirective.form.get(this.controlName());
60
- return this.error() && control?.invalid && (control.dirty || control.touched)
61
- ? this.errorId()
62
- : this.hint()
63
- ? this.hintId()
64
- : null;
89
+ return (!!this.resolvedError() &&
90
+ !!control?.invalid &&
91
+ (control.dirty || control.touched || this.formGroupDirective.submitted));
92
+ }
93
+ describedBy() {
94
+ return this.showError() ? this.errorId() : this.hint() ? this.hintId() : null;
65
95
  }
66
96
  // Styling
67
97
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
@@ -76,16 +106,16 @@ class EgFormPhoneInput {
76
106
  // Computed classes (library base < global config < per-instance)
77
107
  $userClass = computed(() => hlm("w-full", this.userClass()), /* @ts-ignore */
78
108
  ...(ngDevMode ? [{ debugName: "$userClass" }] : /* istanbul ignore next */ []));
79
- $labelClass = computed(() => hlm("mb-1 gap-0", this._config.labelClass, this.labelClass()), /* @ts-ignore */
109
+ $labelClass = computed(() => hlm("mb-1 gap-0", this._shared.labelClass, this._config.labelClass, this.labelClass()), /* @ts-ignore */
80
110
  ...(ngDevMode ? [{ debugName: "$labelClass" }] : /* istanbul ignore next */ []));
81
- $inputClass = computed(() => hlm("mb-1", this._config.inputClass, this.inputClass()), /* @ts-ignore */
111
+ $inputClass = computed(() => hlm("mb-1", this._shared.inputClass, this._config.inputClass, this.inputClass()), /* @ts-ignore */
82
112
  ...(ngDevMode ? [{ debugName: "$inputClass" }] : /* istanbul ignore next */ []));
83
- $errorClass = computed(() => hlm("mt-0", this._config.errorClass, this.errorClass()), /* @ts-ignore */
113
+ $errorClass = computed(() => hlm("mt-0", this._shared.errorClass, this._config.errorClass, this.errorClass()), /* @ts-ignore */
84
114
  ...(ngDevMode ? [{ debugName: "$errorClass" }] : /* istanbul ignore next */ []));
85
- $hintClass = computed(() => hlm("mt-0", this._config.hintClass, this.hintClass()), /* @ts-ignore */
115
+ $hintClass = computed(() => hlm("mt-0", this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
86
116
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
87
117
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormPhoneInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
88
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormPhoneInput, isStandalone: true, selector: "eg-form-phone-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, maxDigits: { classPropertyName: "maxDigits", publicName: "maxDigits", isSignal: true, isRequired: false, transformFunction: null }, formatPhoneNumber: { classPropertyName: "formatPhoneNumber", publicName: "formatPhoneNumber", isSignal: true, isRequired: false, transformFunction: null }, modelFormat: { classPropertyName: "modelFormat", publicName: "modelFormat", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, inputClass: { classPropertyName: "inputClass", publicName: "inputClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: "\n @let lbl = label();\n @let cnm = controlName();\n @let err = error();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <hlm-phone-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [autocomplete]=\"autocomplete()\"\n [maxDigits]=\"maxDigits()\"\n [formatPhoneNumber]=\"formatPhoneNumber()\"\n [modelFormat]=\"modelFormat()\"\n [disabled]=\"disabled()\"\n [formControlName]=\"cnm\"\n [class]=\"$inputClass()\"\n />\n\n @if (err) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ err }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ", isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HlmFormField, selector: "hlm-form-field", inputs: ["class"] }, { kind: "directive", type: HlmError, selector: "hlm-error", inputs: ["class"] }, { kind: "directive", type: HlmHint, selector: "hlm-hint", inputs: ["class"] }, { kind: "directive", type: HlmLabel, selector: "[hlmLabel]", inputs: ["class"] }, { kind: "component", type: HlmPhoneInput, selector: "hlm-phone-input", inputs: ["inputId", "name", "ariaLabel", "ariaDescribedby", "placeholder", "autocomplete", "readonly", "disabled", "forceInvalid", "maxDigits", "modelFormat", "formatPhoneNumber", "class", "inputClass"] }] });
118
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormPhoneInput, isStandalone: true, selector: "eg-form-phone-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, autoError: { classPropertyName: "autoError", publicName: "autoError", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, maxDigits: { classPropertyName: "maxDigits", publicName: "maxDigits", isSignal: true, isRequired: false, transformFunction: null }, formatPhoneNumber: { classPropertyName: "formatPhoneNumber", publicName: "formatPhoneNumber", isSignal: true, isRequired: false, transformFunction: null }, modelFormat: { classPropertyName: "modelFormat", publicName: "modelFormat", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, inputClass: { classPropertyName: "inputClass", publicName: "inputClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: "\n @let lbl = label();\n @let cnm = controlName();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <hlm-phone-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [autocomplete]=\"autocomplete()\"\n [maxDigits]=\"maxDigits()\"\n [formatPhoneNumber]=\"formatPhoneNumber()\"\n [modelFormat]=\"modelFormat()\"\n [disabled]=\"disabled()\"\n [formControlName]=\"cnm\"\n [class]=\"$inputClass()\"\n />\n\n @if (showError()) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ resolvedError() }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ", isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HlmFormField, selector: "hlm-form-field", inputs: ["class"] }, { kind: "directive", type: HlmError, selector: "hlm-error", inputs: ["class"] }, { kind: "directive", type: HlmHint, selector: "hlm-hint", inputs: ["class"] }, { kind: "directive", type: HlmLabel, selector: "[hlmLabel]", inputs: ["class"] }, { kind: "component", type: HlmPhoneInput, selector: "hlm-phone-input", inputs: ["inputId", "name", "ariaLabel", "ariaDescribedby", "placeholder", "autocomplete", "readonly", "disabled", "forceInvalid", "maxDigits", "modelFormat", "formatPhoneNumber", "class", "inputClass"] }] });
89
119
  }
90
120
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormPhoneInput, decorators: [{
91
121
  type: Component,
@@ -97,9 +127,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
97
127
  },
98
128
  imports: [ReactiveFormsModule, HlmFormField, HlmError, HlmHint, HlmLabel, HlmPhoneInput],
99
129
  providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
100
- template: "\n @let lbl = label();\n @let cnm = controlName();\n @let err = error();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <hlm-phone-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [autocomplete]=\"autocomplete()\"\n [maxDigits]=\"maxDigits()\"\n [formatPhoneNumber]=\"formatPhoneNumber()\"\n [modelFormat]=\"modelFormat()\"\n [disabled]=\"disabled()\"\n [formControlName]=\"cnm\"\n [class]=\"$inputClass()\"\n />\n\n @if (err) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ err }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ",
130
+ template: "\n @let lbl = label();\n @let cnm = controlName();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <hlm-phone-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [autocomplete]=\"autocomplete()\"\n [maxDigits]=\"maxDigits()\"\n [formatPhoneNumber]=\"formatPhoneNumber()\"\n [modelFormat]=\"modelFormat()\"\n [disabled]=\"disabled()\"\n [formControlName]=\"cnm\"\n [class]=\"$inputClass()\"\n />\n\n @if (showError()) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ resolvedError() }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ",
101
131
  }]
102
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], controlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlName", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], maxDigits: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDigits", required: false }] }], formatPhoneNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatPhoneNumber", required: false }] }], modelFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelFormat", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], inputClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
132
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], controlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlName", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], autoError: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoError", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], maxDigits: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDigits", required: false }] }], formatPhoneNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatPhoneNumber", required: false }] }], modelFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelFormat", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], inputClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
103
133
 
104
134
  /*
105
135
  * Public API Surface of form-phone-input
@@ -5,12 +5,20 @@ import { ClassValue } from 'clsx';
5
5
 
6
6
  declare class EgFormPhoneInput {
7
7
  private readonly formGroupDirective;
8
+ private readonly _errorMessages;
8
9
  private readonly generatedId;
9
10
  private readonly _config;
11
+ private readonly _shared;
10
12
  label: _angular_core.InputSignal<string | undefined>;
11
13
  controlId: _angular_core.InputSignal<string | undefined>;
12
14
  controlName: _angular_core.InputSignal<string>;
13
15
  error: _angular_core.InputSignal<string | undefined>;
16
+ /**
17
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
18
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
19
+ * for manual-only messages.
20
+ */
21
+ autoError: _angular_core.InputSignal<boolean>;
14
22
  hint: _angular_core.InputSignal<string | undefined>;
15
23
  id: _angular_core.InputSignal<string | undefined>;
16
24
  name: _angular_core.InputSignal<string | undefined>;
@@ -25,6 +33,19 @@ declare class EgFormPhoneInput {
25
33
  readonly effectiveId: _angular_core.Signal<string>;
26
34
  readonly errorId: _angular_core.Signal<string>;
27
35
  readonly hintId: _angular_core.Signal<string>;
36
+ /**
37
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
38
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
39
+ * computed): `ValidationErrors` is not a signal, so the control must be read
40
+ * fresh on every change-detection pass.
41
+ */
42
+ protected resolvedError(): string | undefined;
43
+ /**
44
+ * Whether the error is surfaced: message present + control invalid +
45
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
46
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
47
+ */
48
+ protected showError(): boolean;
28
49
  describedBy(): string | null;
29
50
  userClass: _angular_core.InputSignal<ClassValue>;
30
51
  labelClass: _angular_core.InputSignal<string>;
@@ -37,7 +58,7 @@ declare class EgFormPhoneInput {
37
58
  $errorClass: _angular_core.Signal<string>;
38
59
  $hintClass: _angular_core.Signal<string>;
39
60
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormPhoneInput, never>;
40
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormPhoneInput, "eg-form-phone-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "controlName": { "alias": "controlName"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "maxDigits": { "alias": "maxDigits"; "required": false; "isSignal": true; }; "formatPhoneNumber": { "alias": "formatPhoneNumber"; "required": false; "isSignal": true; }; "modelFormat": { "alias": "modelFormat"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "inputClass": { "alias": "inputClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
61
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormPhoneInput, "eg-form-phone-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "controlName": { "alias": "controlName"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "autoError": { "alias": "autoError"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "maxDigits": { "alias": "maxDigits"; "required": false; "isSignal": true; }; "formatPhoneNumber": { "alias": "formatPhoneNumber"; "required": false; "isSignal": true; }; "modelFormat": { "alias": "modelFormat"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "inputClass": { "alias": "inputClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
41
62
  }
42
63
 
43
64
  interface EgFormPhoneInputConfig {