@egose/shadcn-theme-ng-tw 0.3.0 → 0.4.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 (63) hide show
  1. package/form-autocomplete/README.md +20 -19
  2. package/form-autocomplete/fesm2022/form-autocomplete.mjs +41 -9
  3. package/form-autocomplete/types/form-autocomplete.d.ts +21 -1
  4. package/form-checkbox/README.md +18 -17
  5. package/form-checkbox/fesm2022/form-checkbox.mjs +42 -15
  6. package/form-checkbox/types/form-checkbox.d.ts +21 -1
  7. package/form-combobox/README.md +21 -20
  8. package/form-combobox/fesm2022/form-combobox.mjs +41 -9
  9. package/form-combobox/types/form-combobox.d.ts +21 -1
  10. package/form-date-picker/README.md +28 -27
  11. package/form-date-picker/fesm2022/form-date-picker.mjs +42 -15
  12. package/form-date-picker/types/form-date-picker.d.ts +21 -1
  13. package/form-date-picker-multi/README.md +28 -27
  14. package/form-date-picker-multi/fesm2022/form-date-picker-multi.mjs +42 -15
  15. package/form-date-picker-multi/types/form-date-picker-multi.d.ts +21 -1
  16. package/form-date-range-picker/README.md +28 -27
  17. package/form-date-range-picker/fesm2022/form-date-range-picker.mjs +42 -15
  18. package/form-date-range-picker/types/form-date-range-picker.d.ts +21 -1
  19. package/form-field/README.md +9 -0
  20. package/form-field/fesm2022/form-field.mjs +80 -5
  21. package/form-field/types/form-field.d.ts +50 -2
  22. package/form-field-simple/fesm2022/form-field-simple.mjs +15 -1
  23. package/form-field-simple/types/form-field-simple.d.ts +9 -2
  24. package/form-input-otp/README.md +17 -16
  25. package/form-input-otp/fesm2022/form-input-otp.mjs +41 -9
  26. package/form-input-otp/types/form-input-otp.d.ts +21 -1
  27. package/form-month-year-picker/README.md +26 -25
  28. package/form-month-year-picker/fesm2022/form-month-year-picker.mjs +42 -15
  29. package/form-month-year-picker/types/form-month-year-picker.d.ts +21 -1
  30. package/form-native-select/README.md +18 -17
  31. package/form-native-select/fesm2022/form-native-select.mjs +56 -17
  32. package/form-native-select/types/form-native-select.d.ts +21 -1
  33. package/form-phone-input/README.md +23 -22
  34. package/form-phone-input/fesm2022/form-phone-input.mjs +42 -15
  35. package/form-phone-input/types/form-phone-input.d.ts +21 -1
  36. package/form-radio-group/README.md +18 -17
  37. package/form-radio-group/fesm2022/form-radio-group.mjs +42 -15
  38. package/form-radio-group/types/form-radio-group.d.ts +21 -1
  39. package/form-searchable-multiselect/README.md +18 -17
  40. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +42 -15
  41. package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +21 -1
  42. package/form-select/README.md +20 -19
  43. package/form-select/fesm2022/form-select.mjs +42 -15
  44. package/form-select/types/form-select.d.ts +21 -1
  45. package/form-slider/README.md +19 -18
  46. package/form-slider/fesm2022/form-slider.mjs +41 -9
  47. package/form-slider/types/form-slider.d.ts +21 -1
  48. package/form-switch/README.md +16 -15
  49. package/form-switch/fesm2022/form-switch.mjs +42 -15
  50. package/form-switch/types/form-switch.d.ts +21 -1
  51. package/form-text-input/README.md +27 -26
  52. package/form-text-input/fesm2022/form-text-input.mjs +42 -15
  53. package/form-text-input/types/form-text-input.d.ts +21 -1
  54. package/form-textarea/README.md +23 -22
  55. package/form-textarea/fesm2022/form-textarea.mjs +42 -15
  56. package/form-textarea/types/form-textarea.d.ts +21 -1
  57. package/form-toggle/README.md +17 -16
  58. package/form-toggle/fesm2022/form-toggle.mjs +41 -7
  59. package/form-toggle/types/form-toggle.d.ts +21 -3
  60. package/form-toggle-group/README.md +20 -19
  61. package/form-toggle-group/fesm2022/form-toggle-group.mjs +42 -15
  62. package/form-toggle-group/types/form-toggle-group.d.ts +21 -1
  63. package/package.json +1 -1
@@ -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-tw/form-field';
5
+ import { injectEgFormErrorMessages, HlmFormIdGenerator, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng-tw/label';
7
7
  import { formatNanpPhoneNumber, HlmPhoneInput } from '@egose/shadcn-theme-ng-tw/phone-input';
8
8
  import { hlm } from '@egose/shadcn-theme-ng-tw/utils';
@@ -17,6 +17,7 @@ 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();
22
23
  label = input(undefined, /* @ts-ignore */
@@ -27,6 +28,13 @@ class EgFormPhoneInput {
27
28
  ...(ngDevMode ? [{ debugName: "controlName" }] : /* istanbul ignore next */ []));
28
29
  error = input(undefined, /* @ts-ignore */
29
30
  ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
31
+ /**
32
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
33
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
34
+ * for manual-only messages.
35
+ */
36
+ autoError = input(true, /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "autoError" }] : /* istanbul ignore next */ []));
30
38
  hint = input(undefined, /* @ts-ignore */
31
39
  ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
32
40
  id = input(undefined, /* @ts-ignore */
@@ -55,13 +63,34 @@ class EgFormPhoneInput {
55
63
  ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
56
64
  hintId = computed(() => `${this.effectiveId()}-hint`, /* @ts-ignore */
57
65
  ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
58
- describedBy() {
66
+ /**
67
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
68
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
69
+ * computed): `ValidationErrors` is not a signal, so the control must be read
70
+ * fresh on every change-detection pass.
71
+ */
72
+ resolvedError() {
73
+ const explicit = this.error();
74
+ if (explicit)
75
+ return explicit;
76
+ if (!this.autoError())
77
+ return undefined;
78
+ const control = this.formGroupDirective.form.get(this.controlName());
79
+ return resolveEgFormError(control?.errors ?? null, this.label(), this._errorMessages);
80
+ }
81
+ /**
82
+ * Whether the error is surfaced: message present + control invalid +
83
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
84
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
85
+ */
86
+ showError() {
59
87
  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;
88
+ return (!!this.resolvedError() &&
89
+ !!control?.invalid &&
90
+ (control.dirty || control.touched || this.formGroupDirective.submitted));
91
+ }
92
+ describedBy() {
93
+ return this.showError() ? this.errorId() : this.hint() ? this.hintId() : null;
65
94
  }
66
95
  // Styling
67
96
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
@@ -85,10 +114,9 @@ class EgFormPhoneInput {
85
114
  $hintClass = computed(() => hlm('tw:mt-0', this._config.hintClass, this.hintClass()), /* @ts-ignore */
86
115
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
87
116
  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: `
117
+ 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: `
89
118
  @let lbl = label();
90
119
  @let cnm = controlName();
91
- @let err = error();
92
120
  @let hnt = hint();
93
121
  @let rqrd = required();
94
122
 
@@ -118,9 +146,9 @@ class EgFormPhoneInput {
118
146
  [class]="$inputClass()"
119
147
  />
120
148
 
121
- @if (err) {
149
+ @if (showError()) {
122
150
  <hlm-error [id]="errorId()" [class]="$errorClass()">
123
- {{ err }}
151
+ {{ resolvedError() }}
124
152
  </hlm-error>
125
153
  }
126
154
 
@@ -145,7 +173,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
145
173
  template: `
146
174
  @let lbl = label();
147
175
  @let cnm = controlName();
148
- @let err = error();
149
176
  @let hnt = hint();
150
177
  @let rqrd = required();
151
178
 
@@ -175,9 +202,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
175
202
  [class]="$inputClass()"
176
203
  />
177
204
 
178
- @if (err) {
205
+ @if (showError()) {
179
206
  <hlm-error [id]="errorId()" [class]="$errorClass()">
180
- {{ err }}
207
+ {{ resolvedError() }}
181
208
  </hlm-error>
182
209
  }
183
210
 
@@ -189,7 +216,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
189
216
  </hlm-form-field>
190
217
  `,
191
218
  }]
192
- }], 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 }] }] } });
219
+ }], 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 }] }] } });
193
220
 
194
221
  /*
195
222
  * Public API Surface of form-phone-input
@@ -5,12 +5,19 @@ 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;
10
11
  label: _angular_core.InputSignal<string | undefined>;
11
12
  controlId: _angular_core.InputSignal<string | undefined>;
12
13
  controlName: _angular_core.InputSignal<string>;
13
14
  error: _angular_core.InputSignal<string | undefined>;
15
+ /**
16
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
17
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
18
+ * for manual-only messages.
19
+ */
20
+ autoError: _angular_core.InputSignal<boolean>;
14
21
  hint: _angular_core.InputSignal<string | undefined>;
15
22
  id: _angular_core.InputSignal<string | undefined>;
16
23
  name: _angular_core.InputSignal<string | undefined>;
@@ -25,6 +32,19 @@ declare class EgFormPhoneInput {
25
32
  readonly effectiveId: _angular_core.Signal<string>;
26
33
  readonly errorId: _angular_core.Signal<string>;
27
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;
28
48
  describedBy(): string | null;
29
49
  userClass: _angular_core.InputSignal<ClassValue>;
30
50
  labelClass: _angular_core.InputSignal<string>;
@@ -37,7 +57,7 @@ declare class EgFormPhoneInput {
37
57
  $errorClass: _angular_core.Signal<string>;
38
58
  $hintClass: _angular_core.Signal<string>;
39
59
  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>;
60
+ 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
61
  }
42
62
 
43
63
  interface EgFormPhoneInputConfig {
@@ -70,23 +70,24 @@ Selector (from source): `eg-form-radio-group` (standalone component, host `tw:w-
70
70
 
71
71
  ### `EgFormRadioGroup` — `eg-form-radio-group`
72
72
 
73
- | Input | Type | Default | Description |
74
- | ------------- | ------------------------------- | ------- | ------------------------------------------------------------------ |
75
- | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
76
- | `label` | `string \| undefined` | — | Group label text (hidden when omitted). |
77
- | `error` | `string \| undefined` | — | Error text shown when invalid. |
78
- | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
79
- | `controlId` | `string \| undefined` | — | Explicit id prefix (first priority for `effectiveId`). |
80
- | `id` | `string \| undefined` | — | Fallback id prefix (second priority). |
81
- | `name` | `string \| undefined` | — | Native group `name` (`controlName` wins when set). |
82
- | `disabled` | `boolean` | `false` | Locks interaction (form control stays enabled). |
83
- | `required` | `boolean` | `false` | Shows a red `*` next to the label; forwarded to the group. |
84
- | `options` | `{ value, label, disabled? }[]` | `[]` | Rendered as labelled `hlm-radio` options. |
85
- | `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
86
- | `labelClass` | `string` | `''` | Extra group-label classes (base `tw:mb-1`). |
87
- | `groupClass` | `string` | `''` | Extra group classes (base `tw:flex tw:flex-col tw:gap-2`). |
88
- | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
89
- | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
73
+ | Input | Type | Default | Description |
74
+ | ------------- | ------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
75
+ | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
76
+ | `label` | `string \| undefined` | — | Group label text (hidden when omitted). |
77
+ | `error` | `string \| undefined` | — | Error text shown when invalid. |
78
+ | `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`. |
79
+ | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
80
+ | `controlId` | `string \| undefined` | — | Explicit id prefix (first priority for `effectiveId`). |
81
+ | `id` | `string \| undefined` | — | Fallback id prefix (second priority). |
82
+ | `name` | `string \| undefined` | — | Native group `name` (`controlName` wins when set). |
83
+ | `disabled` | `boolean` | `false` | Locks interaction (form control stays enabled). |
84
+ | `required` | `boolean` | `false` | Shows a red `*` next to the label; forwarded to the group. |
85
+ | `options` | `{ value, label, disabled? }[]` | `[]` | Rendered as labelled `hlm-radio` options. |
86
+ | `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
87
+ | `labelClass` | `string` | `''` | Extra group-label classes (base `tw:mb-1`). |
88
+ | `groupClass` | `string` | `''` | Extra group classes (base `tw:flex tw:flex-col tw:gap-2`). |
89
+ | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
90
+ | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
90
91
 
91
92
  | Member | Description |
92
93
  | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -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-tw/form-field';
5
+ import { injectEgFormErrorMessages, HlmFormIdGenerator, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng-tw/label';
7
7
  import { HlmRadioGroup, HlmRadio, HlmRadioIndicator } from '@egose/shadcn-theme-ng-tw/radio-group';
8
8
  import { hlm } from '@egose/shadcn-theme-ng-tw/utils';
@@ -17,6 +17,7 @@ function injectEgFormRadioGroupConfig() {
17
17
 
18
18
  class EgFormRadioGroup {
19
19
  formGroupDirective = inject(FormGroupDirective);
20
+ _errorMessages = injectEgFormErrorMessages();
20
21
  generatedId = inject(HlmFormIdGenerator).generate('eg-form-radio-group');
21
22
  _config = injectEgFormRadioGroupConfig();
22
23
  label = input(undefined, /* @ts-ignore */
@@ -27,6 +28,13 @@ class EgFormRadioGroup {
27
28
  ...(ngDevMode ? [{ debugName: "controlName" }] : /* istanbul ignore next */ []));
28
29
  error = input(undefined, /* @ts-ignore */
29
30
  ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
31
+ /**
32
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
33
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
34
+ * for manual-only messages.
35
+ */
36
+ autoError = input(true, /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "autoError" }] : /* istanbul ignore next */ []));
30
38
  hint = input(undefined, /* @ts-ignore */
31
39
  ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
32
40
  id = input(undefined, /* @ts-ignore */
@@ -45,6 +53,32 @@ class EgFormRadioGroup {
45
53
  ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
46
54
  hintId = computed(() => `${this.effectiveId()}-hint`, /* @ts-ignore */
47
55
  ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
56
+ /**
57
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
58
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
59
+ * computed): `ValidationErrors` is not a signal, so the control must be read
60
+ * fresh on every change-detection pass.
61
+ */
62
+ resolvedError() {
63
+ const explicit = this.error();
64
+ if (explicit)
65
+ return explicit;
66
+ if (!this.autoError())
67
+ return undefined;
68
+ const control = this.formGroupDirective.form.get(this.controlName());
69
+ return resolveEgFormError(control?.errors ?? null, this.label(), this._errorMessages);
70
+ }
71
+ /**
72
+ * Whether the error is surfaced: message present + control invalid +
73
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
74
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
75
+ */
76
+ showError() {
77
+ const control = this.formGroupDirective.form.get(this.controlName());
78
+ return (!!this.resolvedError() &&
79
+ !!control?.invalid &&
80
+ (control.dirty || control.touched || this.formGroupDirective.submitted));
81
+ }
48
82
  /**
49
83
  * Combined lock for the brain `linkedSignal`-based disabled state: the raw
50
84
  * input write always carries the resolved value, so a same-pass
@@ -54,12 +88,7 @@ class EgFormRadioGroup {
54
88
  return this.disabled() || !!this.formGroupDirective.form.get(this.controlName())?.disabled;
55
89
  }
56
90
  describedBy() {
57
- const control = this.formGroupDirective.form.get(this.controlName());
58
- return this.error() && control?.invalid && (control.dirty || control.touched)
59
- ? this.errorId()
60
- : this.hint()
61
- ? this.hintId()
62
- : null;
91
+ return this.showError() ? this.errorId() : this.hint() ? this.hintId() : null;
63
92
  }
64
93
  // Styling
65
94
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
@@ -83,10 +112,9 @@ class EgFormRadioGroup {
83
112
  $hintClass = computed(() => hlm('tw:mt-0', this._config.hintClass, this.hintClass()), /* @ts-ignore */
84
113
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
85
114
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormRadioGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
86
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormRadioGroup, isStandalone: true, selector: "eg-form-radio-group", 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 }, groupClass: { classPropertyName: "groupClass", publicName: "groupClass", 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: `
115
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormRadioGroup, isStandalone: true, selector: "eg-form-radio-group", 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 }, groupClass: { classPropertyName: "groupClass", publicName: "groupClass", 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: `
87
116
  @let lbl = label();
88
117
  @let cnm = controlName();
89
- @let err = error();
90
118
  @let hnt = hint();
91
119
  @let rqrd = required();
92
120
 
@@ -121,9 +149,9 @@ class EgFormRadioGroup {
121
149
  }
122
150
  </hlm-radio-group>
123
151
 
124
- @if (err) {
152
+ @if (showError()) {
125
153
  <hlm-error [id]="errorId()" [class]="$errorClass()">
126
- {{ err }}
154
+ {{ resolvedError() }}
127
155
  </hlm-error>
128
156
  }
129
157
 
@@ -148,7 +176,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
148
176
  template: `
149
177
  @let lbl = label();
150
178
  @let cnm = controlName();
151
- @let err = error();
152
179
  @let hnt = hint();
153
180
  @let rqrd = required();
154
181
 
@@ -183,9 +210,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
183
210
  }
184
211
  </hlm-radio-group>
185
212
 
186
- @if (err) {
213
+ @if (showError()) {
187
214
  <hlm-error [id]="errorId()" [class]="$errorClass()">
188
- {{ err }}
215
+ {{ resolvedError() }}
189
216
  </hlm-error>
190
217
  }
191
218
 
@@ -197,7 +224,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
197
224
  </hlm-form-field>
198
225
  `,
199
226
  }]
200
- }], 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 }] }], groupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
227
+ }], 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 }] }], groupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
201
228
 
202
229
  /*
203
230
  * Public API Surface of form-radio-group
@@ -9,12 +9,19 @@ interface RadioOption {
9
9
  }
10
10
  declare class EgFormRadioGroup {
11
11
  private readonly formGroupDirective;
12
+ private readonly _errorMessages;
12
13
  private readonly generatedId;
13
14
  private readonly _config;
14
15
  label: _angular_core.InputSignal<string | undefined>;
15
16
  controlId: _angular_core.InputSignal<string | undefined>;
16
17
  controlName: _angular_core.InputSignal<string>;
17
18
  error: _angular_core.InputSignal<string | undefined>;
19
+ /**
20
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
21
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
22
+ * for manual-only messages.
23
+ */
24
+ autoError: _angular_core.InputSignal<boolean>;
18
25
  hint: _angular_core.InputSignal<string | undefined>;
19
26
  id: _angular_core.InputSignal<string | undefined>;
20
27
  name: _angular_core.InputSignal<string | undefined>;
@@ -24,6 +31,19 @@ declare class EgFormRadioGroup {
24
31
  readonly effectiveId: _angular_core.Signal<string>;
25
32
  readonly errorId: _angular_core.Signal<string>;
26
33
  readonly hintId: _angular_core.Signal<string>;
34
+ /**
35
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
36
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
37
+ * computed): `ValidationErrors` is not a signal, so the control must be read
38
+ * fresh on every change-detection pass.
39
+ */
40
+ protected resolvedError(): string | undefined;
41
+ /**
42
+ * Whether the error is surfaced: message present + control invalid +
43
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
44
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
45
+ */
46
+ protected showError(): boolean;
27
47
  /**
28
48
  * Combined lock for the brain `linkedSignal`-based disabled state: the raw
29
49
  * input write always carries the resolved value, so a same-pass
@@ -42,7 +62,7 @@ declare class EgFormRadioGroup {
42
62
  $errorClass: _angular_core.Signal<string>;
43
63
  $hintClass: _angular_core.Signal<string>;
44
64
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormRadioGroup, never>;
45
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormRadioGroup, "eg-form-radio-group", 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; }; "groupClass": { "alias": "groupClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
65
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormRadioGroup, "eg-form-radio-group", 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; }; "groupClass": { "alias": "groupClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
46
66
  }
47
67
 
48
68
  interface EgFormRadioGroupConfig {
@@ -77,23 +77,24 @@ Real selectors involved: `eg-form-searchable-multiselect` (this wrapper), `eg-fo
77
77
 
78
78
  ### `eg-form-searchable-multiselect` — `EgFormSearchableMultiselect`
79
79
 
80
- | Input | Type | Default | Description |
81
- | --------------------- | --------------------- | ------------------------ | --------------------------------------------------------------------------------------------------- |
82
- | `label` | `string \| undefined` | `undefined` | Field label. When set, a `<label hlmLabel>` bound to the control id is rendered. |
83
- | `controlName` | `string` | `''` | **Required.** Name of the control in the parent `FormGroup`; forwarded as `formControlName`. |
84
- | `controlId` | `string \| undefined` | `undefined` | Explicit control id. Falls back to `id`, then to a generated `eg-form-searchable-multiselect-…` id. |
85
- | `id` | `string \| undefined` | `undefined` | Alias for an explicit control id (same fallback chain as `controlId`). |
86
- | `error` | `string \| undefined` | `undefined` | Error text rendered in `<hlm-error>`. |
87
- | `hint` | `string \| undefined` | `undefined` | Hint text rendered in `<hlm-hint>`. |
88
- | `placeholder` | `string` | `'Start typing to add…'` | Placeholder forwarded to the inner multiselect. |
89
- | `disabled` | `boolean` | `false` | Wrapper-level disable, forwarded as `wrapperDisabled` to the inner multiselect. |
90
- | `required` | `boolean` | `false` | Adds `required` to the inner control and renders a red `*` next to the label. |
91
- | `options` | `SelectOption[]` | `[]` | `{ label: string; value: string }[]` forwarded to the inner multiselect. |
92
- | `class` (`userClass`) | `ClassValue` | `''` | Extra classes for the host (merged over `tw:w-full`). |
93
- | `labelClass` | `string` | `''` | Extra classes for the `<label>` (merged over `tw:mb-1 tw:gap-0`). |
94
- | `controlClass` | `string` | `''` | Extra classes for the inner multiselect (merged over `tw:w-full`). |
95
- | `errorClass` | `string` | `''` | Extra classes for `<hlm-error>` (merged over `tw:mt-0`). |
96
- | `hintClass` | `string` | `''` | Extra classes for `<hlm-hint>` (merged over `tw:mt-0`). |
80
+ | Input | Type | Default | Description |
81
+ | --------------------- | --------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
82
+ | `label` | `string \| undefined` | `undefined` | Field label. When set, a `<label hlmLabel>` bound to the control id is rendered. |
83
+ | `controlName` | `string` | `''` | **Required.** Name of the control in the parent `FormGroup`; forwarded as `formControlName`. |
84
+ | `controlId` | `string \| undefined` | `undefined` | Explicit control id. Falls back to `id`, then to a generated `eg-form-searchable-multiselect-…` id. |
85
+ | `id` | `string \| undefined` | `undefined` | Alias for an explicit control id (same fallback chain as `controlId`). |
86
+ | `error` | `string \| undefined` | `undefined` | Error text rendered in `<hlm-error>`. |
87
+ | `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`. |
88
+ | `hint` | `string \| undefined` | `undefined` | Hint text rendered in `<hlm-hint>`. |
89
+ | `placeholder` | `string` | `'Start typing to add…'` | Placeholder forwarded to the inner multiselect. |
90
+ | `disabled` | `boolean` | `false` | Wrapper-level disable, forwarded as `wrapperDisabled` to the inner multiselect. |
91
+ | `required` | `boolean` | `false` | Adds `required` to the inner control and renders a red `*` next to the label. |
92
+ | `options` | `SelectOption[]` | `[]` | `{ label: string; value: string }[]` forwarded to the inner multiselect. |
93
+ | `class` (`userClass`) | `ClassValue` | `''` | Extra classes for the host (merged over `tw:w-full`). |
94
+ | `labelClass` | `string` | `''` | Extra classes for the `<label>` (merged over `tw:mb-1 tw:gap-0`). |
95
+ | `controlClass` | `string` | `''` | Extra classes for the inner multiselect (merged over `tw:w-full`). |
96
+ | `errorClass` | `string` | `''` | Extra classes for `<hlm-error>` (merged over `tw:mt-0`). |
97
+ | `hintClass` | `string` | `''` | Extra classes for `<hlm-hint>` (merged over `tw:mt-0`). |
97
98
 
98
99
  No outputs. Readonly computeds/methods (usable via template ref): `effectiveId()`, `errorId()` (`<id>-error`), `hintId()` (`<id>-hint`), `describedBy(): string | null` (returns the error id when the control is invalid + dirty/touched, else the hint id, else `null`).
99
100