@egose/shadcn-theme-ng 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 +38 -4
  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 +39 -10
  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 +38 -4
  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 +39 -10
  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 +39 -10
  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 +39 -10
  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 +38 -4
  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 +39 -10
  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 +39 -10
  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 +39 -10
  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 +39 -10
  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 +39 -10
  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 +39 -10
  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 +38 -4
  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 +39 -10
  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 +39 -10
  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 +39 -10
  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 +40 -6
  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 +39 -10
  62. package/form-toggle-group/types/form-toggle-group.d.ts +21 -1
  63. package/package.json +1 -1
@@ -2,13 +2,14 @@ import * as i0 from '@angular/core';
2
2
  import { inject, input, numberAttribute, 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, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng/label';
7
7
  import { injectHlmDatePickerMultiConfig, HlmDatePickerMulti, HlmDateMultiInput } from '@egose/shadcn-theme-ng/date-picker';
8
8
  import { hlm } from '@egose/shadcn-theme-ng/utils';
9
9
 
10
10
  class EgFormDatePickerMulti {
11
11
  formGroupDirective = inject(FormGroupDirective);
12
+ _errorMessages = injectEgFormErrorMessages();
12
13
  generatedId = inject(HlmFormIdGenerator).generate('eg-form-date-picker-multi');
13
14
  _config = injectHlmDatePickerMultiConfig();
14
15
  label = input(undefined, /* @ts-ignore */
@@ -19,6 +20,13 @@ class EgFormDatePickerMulti {
19
20
  ...(ngDevMode ? [{ debugName: "controlName" }] : /* istanbul ignore next */ []));
20
21
  error = input(undefined, /* @ts-ignore */
21
22
  ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
23
+ /**
24
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
25
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
26
+ * for manual-only messages.
27
+ */
28
+ autoError = input(true, /* @ts-ignore */
29
+ ...(ngDevMode ? [{ debugName: "autoError" }] : /* istanbul ignore next */ []));
22
30
  hint = input(undefined, /* @ts-ignore */
23
31
  ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
24
32
  id = input(undefined, /* @ts-ignore */
@@ -58,6 +66,32 @@ class EgFormDatePickerMulti {
58
66
  ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
59
67
  hintId = computed(() => `${this.effectiveId()}-hint`, /* @ts-ignore */
60
68
  ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
69
+ /**
70
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
71
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
72
+ * computed): `ValidationErrors` is not a signal, so the control must be read
73
+ * fresh on every change-detection pass.
74
+ */
75
+ resolvedError() {
76
+ const explicit = this.error();
77
+ if (explicit)
78
+ return explicit;
79
+ if (!this.autoError())
80
+ return undefined;
81
+ const control = this.formGroupDirective.form.get(this.controlName());
82
+ return resolveEgFormError(control?.errors ?? null, this.label(), this._errorMessages);
83
+ }
84
+ /**
85
+ * Whether the error is surfaced: message present + control invalid +
86
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
87
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
88
+ */
89
+ showError() {
90
+ const control = this.formGroupDirective.form.get(this.controlName());
91
+ return (!!this.resolvedError() &&
92
+ !!control?.invalid &&
93
+ (control.dirty || control.touched || this.formGroupDirective.submitted));
94
+ }
61
95
  /**
62
96
  * Bounds projected onto the picker's `Date` model. The cast keeps the
63
97
  * template's generic inference on `Date` while passing runtime values
@@ -68,12 +102,7 @@ class EgFormDatePickerMulti {
68
102
  $max = computed(() => this.max(), /* @ts-ignore */
69
103
  ...(ngDevMode ? [{ debugName: "$max" }] : /* istanbul ignore next */ []));
70
104
  describedBy() {
71
- const control = this.formGroupDirective.form.get(this.controlName());
72
- return this.error() && control?.invalid && (control.dirty || control.touched)
73
- ? this.errorId()
74
- : this.hint()
75
- ? this.hintId()
76
- : null;
105
+ return this.showError() ? this.errorId() : this.hint() ? this.hintId() : null;
77
106
  }
78
107
  // Styling
79
108
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
@@ -101,7 +130,7 @@ class EgFormDatePickerMulti {
101
130
  $hintClass = computed(() => hlm("mt-0", this._config.hintClass, this.hintClass()), /* @ts-ignore */
102
131
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
103
132
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormDatePickerMulti, deps: [], target: i0.ɵɵFactoryTarget.Component });
104
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormDatePickerMulti, isStandalone: true, selector: "eg-form-date-picker-multi", 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 }, 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 }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, minSelection: { classPropertyName: "minSelection", publicName: "minSelection", isSignal: true, isRequired: false, transformFunction: null }, maxSelection: { classPropertyName: "maxSelection", publicName: "maxSelection", isSignal: true, isRequired: false, transformFunction: null }, autoCloseOnMaxSelection: { classPropertyName: "autoCloseOnMaxSelection", publicName: "autoCloseOnMaxSelection", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, formatDates: { classPropertyName: "formatDates", publicName: "formatDates", isSignal: true, isRequired: false, transformFunction: null }, transformDates: { classPropertyName: "transformDates", publicName: "transformDates", isSignal: true, isRequired: false, transformFunction: null }, parseDate: { classPropertyName: "parseDate", publicName: "parseDate", isSignal: true, isRequired: false, transformFunction: null }, formatInputDates: { classPropertyName: "formatInputDates", publicName: "formatInputDates", 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 }, pickerClass: { classPropertyName: "pickerClass", publicName: "pickerClass", 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-date-picker-multi\n [min]=\"$min()\"\n [max]=\"$max()\"\n [minSelection]=\"minSelection()\"\n [maxSelection]=\"maxSelection()\"\n [disabled]=\"disabled()\"\n [autoCloseOnMaxSelection]=\"autoCloseOnMaxSelection()\"\n [captionLayout]=\"captionLayout()\"\n [formatDates]=\"formatDates()\"\n [transformDates]=\"transformDates()\"\n [formControlName]=\"cnm\"\n [class]=\"$pickerClass()\"\n >\n <hlm-date-multi-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [parseDate]=\"parseDate()\"\n [formatInputDates]=\"formatInputDates()\"\n [inputClass]=\"$inputClass()\"\n />\n </hlm-date-picker-multi>\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: HlmDatePickerMulti, selector: "hlm-date-picker-multi", inputs: ["captionLayout", "min", "max", "minSelection", "maxSelection", "disabled", "date", "autoCloseOnMaxSelection", "formatDates", "transformDates"], outputs: ["dateChange"] }, { kind: "component", type: HlmDateMultiInput, selector: "hlm-date-multi-input", inputs: ["name", "readonly", "ariaLabel", "ariaDescribedby", "class", "inputClass", "parseDate", "formatInputDates"] }] });
133
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormDatePickerMulti, isStandalone: true, selector: "eg-form-date-picker-multi", 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 }, 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 }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, minSelection: { classPropertyName: "minSelection", publicName: "minSelection", isSignal: true, isRequired: false, transformFunction: null }, maxSelection: { classPropertyName: "maxSelection", publicName: "maxSelection", isSignal: true, isRequired: false, transformFunction: null }, autoCloseOnMaxSelection: { classPropertyName: "autoCloseOnMaxSelection", publicName: "autoCloseOnMaxSelection", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, formatDates: { classPropertyName: "formatDates", publicName: "formatDates", isSignal: true, isRequired: false, transformFunction: null }, transformDates: { classPropertyName: "transformDates", publicName: "transformDates", isSignal: true, isRequired: false, transformFunction: null }, parseDate: { classPropertyName: "parseDate", publicName: "parseDate", isSignal: true, isRequired: false, transformFunction: null }, formatInputDates: { classPropertyName: "formatInputDates", publicName: "formatInputDates", 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 }, pickerClass: { classPropertyName: "pickerClass", publicName: "pickerClass", 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-date-picker-multi\n [min]=\"$min()\"\n [max]=\"$max()\"\n [minSelection]=\"minSelection()\"\n [maxSelection]=\"maxSelection()\"\n [disabled]=\"disabled()\"\n [autoCloseOnMaxSelection]=\"autoCloseOnMaxSelection()\"\n [captionLayout]=\"captionLayout()\"\n [formatDates]=\"formatDates()\"\n [transformDates]=\"transformDates()\"\n [formControlName]=\"cnm\"\n [class]=\"$pickerClass()\"\n >\n <hlm-date-multi-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [parseDate]=\"parseDate()\"\n [formatInputDates]=\"formatInputDates()\"\n [inputClass]=\"$inputClass()\"\n />\n </hlm-date-picker-multi>\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: HlmDatePickerMulti, selector: "hlm-date-picker-multi", inputs: ["captionLayout", "min", "max", "minSelection", "maxSelection", "disabled", "date", "autoCloseOnMaxSelection", "formatDates", "transformDates"], outputs: ["dateChange"] }, { kind: "component", type: HlmDateMultiInput, selector: "hlm-date-multi-input", inputs: ["name", "readonly", "ariaLabel", "ariaDescribedby", "class", "inputClass", "parseDate", "formatInputDates"] }] });
105
134
  }
106
135
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormDatePickerMulti, decorators: [{
107
136
  type: Component,
@@ -113,9 +142,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
113
142
  },
114
143
  imports: [ReactiveFormsModule, HlmFormField, HlmError, HlmHint, HlmLabel, HlmDatePickerMulti, HlmDateMultiInput],
115
144
  providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
116
- 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-date-picker-multi\n [min]=\"$min()\"\n [max]=\"$max()\"\n [minSelection]=\"minSelection()\"\n [maxSelection]=\"maxSelection()\"\n [disabled]=\"disabled()\"\n [autoCloseOnMaxSelection]=\"autoCloseOnMaxSelection()\"\n [captionLayout]=\"captionLayout()\"\n [formatDates]=\"formatDates()\"\n [transformDates]=\"transformDates()\"\n [formControlName]=\"cnm\"\n [class]=\"$pickerClass()\"\n >\n <hlm-date-multi-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [parseDate]=\"parseDate()\"\n [formatInputDates]=\"formatInputDates()\"\n [inputClass]=\"$inputClass()\"\n />\n </hlm-date-picker-multi>\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 ",
145
+ 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-date-picker-multi\n [min]=\"$min()\"\n [max]=\"$max()\"\n [minSelection]=\"minSelection()\"\n [maxSelection]=\"maxSelection()\"\n [disabled]=\"disabled()\"\n [autoCloseOnMaxSelection]=\"autoCloseOnMaxSelection()\"\n [captionLayout]=\"captionLayout()\"\n [formatDates]=\"formatDates()\"\n [transformDates]=\"transformDates()\"\n [formControlName]=\"cnm\"\n [class]=\"$pickerClass()\"\n >\n <hlm-date-multi-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [parseDate]=\"parseDate()\"\n [formatInputDates]=\"formatInputDates()\"\n [inputClass]=\"$inputClass()\"\n />\n </hlm-date-picker-multi>\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 ",
117
146
  }]
118
- }], 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 }] }], 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 }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], minSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSelection", required: false }] }], maxSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelection", required: false }] }], autoCloseOnMaxSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoCloseOnMaxSelection", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], formatDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatDates", required: false }] }], transformDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "transformDates", required: false }] }], parseDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "parseDate", required: false }] }], formatInputDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatInputDates", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], pickerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "pickerClass", 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 }] }] } });
147
+ }], 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 }] }], 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 }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], minSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSelection", required: false }] }], maxSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelection", required: false }] }], autoCloseOnMaxSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoCloseOnMaxSelection", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], formatDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatDates", required: false }] }], transformDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "transformDates", required: false }] }], parseDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "parseDate", required: false }] }], formatInputDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatInputDates", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], pickerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "pickerClass", 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 }] }] } });
119
148
 
120
149
  /*
121
150
  * Public API Surface of form-date-picker-multi
@@ -5,12 +5,19 @@ import { NumberInput } from '@angular/cdk/coercion';
5
5
  type DatePickerCaptionLayout = 'dropdown' | 'label' | 'dropdown-months' | 'dropdown-years';
6
6
  declare class EgFormDatePickerMulti {
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>;
@@ -31,6 +38,19 @@ declare class EgFormDatePickerMulti {
31
38
  readonly effectiveId: _angular_core.Signal<string>;
32
39
  readonly errorId: _angular_core.Signal<string>;
33
40
  readonly hintId: _angular_core.Signal<string>;
41
+ /**
42
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
43
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
44
+ * computed): `ValidationErrors` is not a signal, so the control must be read
45
+ * fresh on every change-detection pass.
46
+ */
47
+ protected resolvedError(): string | undefined;
48
+ /**
49
+ * Whether the error is surfaced: message present + control invalid +
50
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
51
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
52
+ */
53
+ protected showError(): boolean;
34
54
  /**
35
55
  * Bounds projected onto the picker's `Date` model. The cast keeps the
36
56
  * template's generic inference on `Date` while passing runtime values
@@ -52,7 +72,7 @@ declare class EgFormDatePickerMulti {
52
72
  $errorClass: _angular_core.Signal<string>;
53
73
  $hintClass: _angular_core.Signal<string>;
54
74
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormDatePickerMulti, never>;
55
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormDatePickerMulti, "eg-form-date-picker-multi", 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; }; "minSelection": { "alias": "minSelection"; "required": false; "isSignal": true; }; "maxSelection": { "alias": "maxSelection"; "required": false; "isSignal": true; }; "autoCloseOnMaxSelection": { "alias": "autoCloseOnMaxSelection"; "required": false; "isSignal": true; }; "captionLayout": { "alias": "captionLayout"; "required": false; "isSignal": true; }; "formatDates": { "alias": "formatDates"; "required": false; "isSignal": true; }; "transformDates": { "alias": "transformDates"; "required": false; "isSignal": true; }; "parseDate": { "alias": "parseDate"; "required": false; "isSignal": true; }; "formatInputDates": { "alias": "formatInputDates"; "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>;
75
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormDatePickerMulti, "eg-form-date-picker-multi", 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; }; "minSelection": { "alias": "minSelection"; "required": false; "isSignal": true; }; "maxSelection": { "alias": "maxSelection"; "required": false; "isSignal": true; }; "autoCloseOnMaxSelection": { "alias": "autoCloseOnMaxSelection"; "required": false; "isSignal": true; }; "captionLayout": { "alias": "captionLayout"; "required": false; "isSignal": true; }; "formatDates": { "alias": "formatDates"; "required": false; "isSignal": true; }; "transformDates": { "alias": "transformDates"; "required": false; "isSignal": true; }; "parseDate": { "alias": "parseDate"; "required": false; "isSignal": true; }; "formatInputDates": { "alias": "formatInputDates"; "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>;
56
76
  }
57
77
 
58
78
  export { EgFormDatePickerMulti };
@@ -84,33 +84,34 @@ Selector (from source): `eg-form-date-range-picker` (standalone component, host
84
84
 
85
85
  ### `EgFormDateRangePicker` — `eg-form-date-range-picker`
86
86
 
87
- | Input | Type | Default | Description |
88
- | ------------------------- | ------------------------------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------- |
89
- | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
90
- | `label` | `string \| undefined` | — | Label text (hidden when omitted). |
91
- | `error` | `string \| undefined` | — | Error text shown when invalid. |
92
- | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
93
- | `controlId` | `string \| undefined` | — | Explicit id (first priority for `effectiveId`). |
94
- | `id` | `string \| undefined` | — | Fallback id (second priority). |
95
- | `name` | `string \| undefined` | — | Native `name` forwarded to the inner input (`controlName` wins when set, like `eg-form-text-input`). |
96
- | `placeholder` | `string` | `'Pick a date range'` | Input placeholder. |
97
- | `readonly` | `boolean` | `false` | Native `readonly` forwarded to the inner input (locks typed text; use `disabled` to lock the calendar too). |
98
- | `disabled` | `boolean` | `false` | Locks interaction via picker `disabled` (form control stays enabled). |
99
- | `required` | `boolean` | `false` | Shows a red `*` next to the label. |
100
- | `min` | `Date \| string \| null` | `null` | Minimum date forwarded to `hlm-date-range-picker`. |
101
- | `max` | `Date \| string \| null` | `null` | Maximum date forwarded to `hlm-date-range-picker`. |
102
- | `autoCloseOnEndSelection` | `boolean` | config default | Forwarded to `hlm-date-range-picker` (falls back to `provideHlmDateRangePickerConfig`, default `false`). |
103
- | `captionLayout` | union | `'label'` | Forwarded to `hlm-date-range-picker` (`'dropdown' \| 'label' \| 'dropdown-months' \| 'dropdown-years'`). |
104
- | `formatDates` | `(dates: [Date \| null, Date \| null]) => string` | config default | Display format, forwarded to `hlm-date-range-picker` (falls back to `provideHlmDateRangePickerConfig`). |
105
- | `transformDates` | `(dates: [Date, Date]) => [Date, Date]` | config default | Model transform, forwarded to `hlm-date-range-picker` (falls back to `provideHlmDateRangePickerConfig`). |
106
- | `parseDate` | `(value: string) => [Date, Date] \| null` | config default | Input parsing, forwarded to `hlm-date-range-input` (falls back to `provideHlmDateRangePickerConfig`). |
107
- | `formatInputDates` | `(dates: [Date \| null, Date \| null]) => string` | config default | Edit format while focused, forwarded to `hlm-date-range-input` (falls back to `provideHlmDateRangePickerConfig`). |
108
- | `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
109
- | `labelClass` | `string` | `''` | Extra label classes (base `tw:mb-1`). |
110
- | `pickerClass` | `string` | `''` | Extra picker-container classes (base `tw:mb-1`). |
111
- | `inputClass` | `string` | `''` | Extra inner-input classes (e.g. `tw:text-lg` for text size). |
112
- | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
113
- | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
87
+ | Input | Type | Default | Description |
88
+ | ------------------------- | ------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
89
+ | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
90
+ | `label` | `string \| undefined` | — | Label text (hidden when omitted). |
91
+ | `error` | `string \| undefined` | — | Error text shown when invalid. |
92
+ | `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`. |
93
+ | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
94
+ | `controlId` | `string \| undefined` | — | Explicit id (first priority for `effectiveId`). |
95
+ | `id` | `string \| undefined` | — | Fallback id (second priority). |
96
+ | `name` | `string \| undefined` | — | Native `name` forwarded to the inner input (`controlName` wins when set, like `eg-form-text-input`). |
97
+ | `placeholder` | `string` | `'Pick a date range'` | Input placeholder. |
98
+ | `readonly` | `boolean` | `false` | Native `readonly` forwarded to the inner input (locks typed text; use `disabled` to lock the calendar too). |
99
+ | `disabled` | `boolean` | `false` | Locks interaction via picker `disabled` (form control stays enabled). |
100
+ | `required` | `boolean` | `false` | Shows a red `*` next to the label. |
101
+ | `min` | `Date \| string \| null` | `null` | Minimum date forwarded to `hlm-date-range-picker`. |
102
+ | `max` | `Date \| string \| null` | `null` | Maximum date forwarded to `hlm-date-range-picker`. |
103
+ | `autoCloseOnEndSelection` | `boolean` | config default | Forwarded to `hlm-date-range-picker` (falls back to `provideHlmDateRangePickerConfig`, default `false`). |
104
+ | `captionLayout` | union | `'label'` | Forwarded to `hlm-date-range-picker` (`'dropdown' \| 'label' \| 'dropdown-months' \| 'dropdown-years'`). |
105
+ | `formatDates` | `(dates: [Date \| null, Date \| null]) => string` | config default | Display format, forwarded to `hlm-date-range-picker` (falls back to `provideHlmDateRangePickerConfig`). |
106
+ | `transformDates` | `(dates: [Date, Date]) => [Date, Date]` | config default | Model transform, forwarded to `hlm-date-range-picker` (falls back to `provideHlmDateRangePickerConfig`). |
107
+ | `parseDate` | `(value: string) => [Date, Date] \| null` | config default | Input parsing, forwarded to `hlm-date-range-input` (falls back to `provideHlmDateRangePickerConfig`). |
108
+ | `formatInputDates` | `(dates: [Date \| null, Date \| null]) => string` | config default | Edit format while focused, forwarded to `hlm-date-range-input` (falls back to `provideHlmDateRangePickerConfig`). |
109
+ | `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
110
+ | `labelClass` | `string` | `''` | Extra label classes (base `tw:mb-1`). |
111
+ | `pickerClass` | `string` | `''` | Extra picker-container classes (base `tw:mb-1`). |
112
+ | `inputClass` | `string` | `''` | Extra inner-input classes (e.g. `tw:text-lg` for text size). |
113
+ | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
114
+ | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
114
115
 
115
116
  | Member | Description |
116
117
  | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -2,13 +2,14 @@ import * as i0 from '@angular/core';
2
2
  import { 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, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng/label';
7
7
  import { injectHlmDateRangePickerConfig, HlmDateRangePicker, HlmDateRangeInput } from '@egose/shadcn-theme-ng/date-picker';
8
8
  import { hlm } from '@egose/shadcn-theme-ng/utils';
9
9
 
10
10
  class EgFormDateRangePicker {
11
11
  formGroupDirective = inject(FormGroupDirective);
12
+ _errorMessages = injectEgFormErrorMessages();
12
13
  generatedId = inject(HlmFormIdGenerator).generate('eg-form-date-range-picker');
13
14
  _config = injectHlmDateRangePickerConfig();
14
15
  // Inputs
@@ -20,6 +21,13 @@ class EgFormDateRangePicker {
20
21
  ...(ngDevMode ? [{ debugName: "controlName" }] : /* istanbul ignore next */ []));
21
22
  error = input(undefined, /* @ts-ignore */
22
23
  ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
24
+ /**
25
+ * Auto-resolve the displayed message from the control's `ValidationErrors`
26
+ * when `error()` is unset. Explicit `error()` always wins. Set to `false`
27
+ * for manual-only messages.
28
+ */
29
+ autoError = input(true, /* @ts-ignore */
30
+ ...(ngDevMode ? [{ debugName: "autoError" }] : /* istanbul ignore next */ []));
23
31
  hint = input(undefined, /* @ts-ignore */
24
32
  ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
25
33
  // HTML attributes
@@ -59,6 +67,32 @@ class EgFormDateRangePicker {
59
67
  ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
60
68
  hintId = computed(() => `${this.effectiveId()}-hint`, /* @ts-ignore */
61
69
  ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
70
+ /**
71
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
72
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
73
+ * computed): `ValidationErrors` is not a signal, so the control must be read
74
+ * fresh on every change-detection pass.
75
+ */
76
+ resolvedError() {
77
+ const explicit = this.error();
78
+ if (explicit)
79
+ return explicit;
80
+ if (!this.autoError())
81
+ return undefined;
82
+ const control = this.formGroupDirective.form.get(this.controlName());
83
+ return resolveEgFormError(control?.errors ?? null, this.label(), this._errorMessages);
84
+ }
85
+ /**
86
+ * Whether the error is surfaced: message present + control invalid +
87
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
88
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
89
+ */
90
+ showError() {
91
+ const control = this.formGroupDirective.form.get(this.controlName());
92
+ return (!!this.resolvedError() &&
93
+ !!control?.invalid &&
94
+ (control.dirty || control.touched || this.formGroupDirective.submitted));
95
+ }
62
96
  /**
63
97
  * Bounds projected onto the picker's `Date` model. The cast keeps the
64
98
  * template's generic inference on `Date` while passing runtime values
@@ -69,12 +103,7 @@ class EgFormDateRangePicker {
69
103
  $max = computed(() => this.max(), /* @ts-ignore */
70
104
  ...(ngDevMode ? [{ debugName: "$max" }] : /* istanbul ignore next */ []));
71
105
  describedBy() {
72
- const control = this.formGroupDirective.form.get(this.controlName());
73
- return this.error() && control?.invalid && (control.dirty || control.touched)
74
- ? this.errorId()
75
- : this.hint()
76
- ? this.hintId()
77
- : null;
106
+ return this.showError() ? this.errorId() : this.hint() ? this.hintId() : null;
78
107
  }
79
108
  // Styling
80
109
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
@@ -102,7 +131,7 @@ class EgFormDateRangePicker {
102
131
  $hintClass = computed(() => hlm("mt-0", this._config.hintClass, this.hintClass()), /* @ts-ignore */
103
132
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
104
133
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormDateRangePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
105
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormDateRangePicker, isStandalone: true, selector: "eg-form-date-range-picker", 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 }, 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 }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, autoCloseOnEndSelection: { classPropertyName: "autoCloseOnEndSelection", publicName: "autoCloseOnEndSelection", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, formatDates: { classPropertyName: "formatDates", publicName: "formatDates", isSignal: true, isRequired: false, transformFunction: null }, transformDates: { classPropertyName: "transformDates", publicName: "transformDates", isSignal: true, isRequired: false, transformFunction: null }, parseDate: { classPropertyName: "parseDate", publicName: "parseDate", isSignal: true, isRequired: false, transformFunction: null }, formatInputDates: { classPropertyName: "formatInputDates", publicName: "formatInputDates", 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 }, pickerClass: { classPropertyName: "pickerClass", publicName: "pickerClass", 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-date-range-picker\n [min]=\"$min()\"\n [max]=\"$max()\"\n [disabled]=\"disabled()\"\n [autoCloseOnEndSelection]=\"autoCloseOnEndSelection()\"\n [captionLayout]=\"captionLayout()\"\n [formatDates]=\"formatDates()\"\n [transformDates]=\"transformDates()\"\n [formControlName]=\"cnm\"\n [class]=\"$pickerClass()\"\n >\n <hlm-date-range-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [parseDate]=\"parseDate()\"\n [formatInputDates]=\"formatInputDates()\"\n [inputClass]=\"$inputClass()\"\n />\n </hlm-date-range-picker>\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: HlmDateRangePicker, selector: "hlm-date-range-picker", inputs: ["captionLayout", "min", "max", "disabled", "date", "autoCloseOnEndSelection", "formatDates", "transformDates"], outputs: ["dateChange"] }, { kind: "component", type: HlmDateRangeInput, selector: "hlm-date-range-input", inputs: ["name", "readonly", "ariaLabel", "ariaDescribedby", "class", "inputClass", "parseDate", "formatInputDates"] }] });
134
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormDateRangePicker, isStandalone: true, selector: "eg-form-date-range-picker", 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 }, 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 }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, autoCloseOnEndSelection: { classPropertyName: "autoCloseOnEndSelection", publicName: "autoCloseOnEndSelection", isSignal: true, isRequired: false, transformFunction: null }, captionLayout: { classPropertyName: "captionLayout", publicName: "captionLayout", isSignal: true, isRequired: false, transformFunction: null }, formatDates: { classPropertyName: "formatDates", publicName: "formatDates", isSignal: true, isRequired: false, transformFunction: null }, transformDates: { classPropertyName: "transformDates", publicName: "transformDates", isSignal: true, isRequired: false, transformFunction: null }, parseDate: { classPropertyName: "parseDate", publicName: "parseDate", isSignal: true, isRequired: false, transformFunction: null }, formatInputDates: { classPropertyName: "formatInputDates", publicName: "formatInputDates", 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 }, pickerClass: { classPropertyName: "pickerClass", publicName: "pickerClass", 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-date-range-picker\n [min]=\"$min()\"\n [max]=\"$max()\"\n [disabled]=\"disabled()\"\n [autoCloseOnEndSelection]=\"autoCloseOnEndSelection()\"\n [captionLayout]=\"captionLayout()\"\n [formatDates]=\"formatDates()\"\n [transformDates]=\"transformDates()\"\n [formControlName]=\"cnm\"\n [class]=\"$pickerClass()\"\n >\n <hlm-date-range-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [parseDate]=\"parseDate()\"\n [formatInputDates]=\"formatInputDates()\"\n [inputClass]=\"$inputClass()\"\n />\n </hlm-date-range-picker>\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: HlmDateRangePicker, selector: "hlm-date-range-picker", inputs: ["captionLayout", "min", "max", "disabled", "date", "autoCloseOnEndSelection", "formatDates", "transformDates"], outputs: ["dateChange"] }, { kind: "component", type: HlmDateRangeInput, selector: "hlm-date-range-input", inputs: ["name", "readonly", "ariaLabel", "ariaDescribedby", "class", "inputClass", "parseDate", "formatInputDates"] }] });
106
135
  }
107
136
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormDateRangePicker, decorators: [{
108
137
  type: Component,
@@ -114,9 +143,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
114
143
  },
115
144
  imports: [ReactiveFormsModule, HlmFormField, HlmError, HlmHint, HlmLabel, HlmDateRangePicker, HlmDateRangeInput],
116
145
  providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
117
- 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-date-range-picker\n [min]=\"$min()\"\n [max]=\"$max()\"\n [disabled]=\"disabled()\"\n [autoCloseOnEndSelection]=\"autoCloseOnEndSelection()\"\n [captionLayout]=\"captionLayout()\"\n [formatDates]=\"formatDates()\"\n [transformDates]=\"transformDates()\"\n [formControlName]=\"cnm\"\n [class]=\"$pickerClass()\"\n >\n <hlm-date-range-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [parseDate]=\"parseDate()\"\n [formatInputDates]=\"formatInputDates()\"\n [inputClass]=\"$inputClass()\"\n />\n </hlm-date-range-picker>\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 ",
146
+ 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-date-range-picker\n [min]=\"$min()\"\n [max]=\"$max()\"\n [disabled]=\"disabled()\"\n [autoCloseOnEndSelection]=\"autoCloseOnEndSelection()\"\n [captionLayout]=\"captionLayout()\"\n [formatDates]=\"formatDates()\"\n [transformDates]=\"transformDates()\"\n [formControlName]=\"cnm\"\n [class]=\"$pickerClass()\"\n >\n <hlm-date-range-input\n [inputId]=\"effectiveId()\"\n [name]=\"cnm || name()\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"lbl\"\n [ariaDescribedby]=\"describedBy()\"\n [placeholder]=\"placeholder()\"\n [parseDate]=\"parseDate()\"\n [formatInputDates]=\"formatInputDates()\"\n [inputClass]=\"$inputClass()\"\n />\n </hlm-date-range-picker>\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 ",
118
147
  }]
119
- }], 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 }] }], 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 }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], autoCloseOnEndSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoCloseOnEndSelection", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], formatDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatDates", required: false }] }], transformDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "transformDates", required: false }] }], parseDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "parseDate", required: false }] }], formatInputDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatInputDates", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], pickerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "pickerClass", 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 }] }] } });
148
+ }], 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 }] }], 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 }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], autoCloseOnEndSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoCloseOnEndSelection", required: false }] }], captionLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionLayout", required: false }] }], formatDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatDates", required: false }] }], transformDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "transformDates", required: false }] }], parseDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "parseDate", required: false }] }], formatInputDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatInputDates", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], pickerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "pickerClass", 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 }] }] } });
120
149
 
121
150
  /*
122
151
  * Public API Surface of form-date-range-picker
@@ -4,12 +4,19 @@ import { ClassValue } from 'clsx';
4
4
  type DateRangeCaptionLayout = 'dropdown' | 'label' | 'dropdown-months' | 'dropdown-years';
5
5
  declare class EgFormDateRangePicker {
6
6
  private readonly formGroupDirective;
7
+ private readonly _errorMessages;
7
8
  private readonly generatedId;
8
9
  private readonly _config;
9
10
  label: _angular_core.InputSignal<string | undefined>;
10
11
  controlId: _angular_core.InputSignal<string | undefined>;
11
12
  controlName: _angular_core.InputSignal<string>;
12
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>;
13
20
  hint: _angular_core.InputSignal<string | undefined>;
14
21
  id: _angular_core.InputSignal<string | undefined>;
15
22
  name: _angular_core.InputSignal<string | undefined>;
@@ -28,6 +35,19 @@ declare class EgFormDateRangePicker {
28
35
  readonly effectiveId: _angular_core.Signal<string>;
29
36
  readonly errorId: _angular_core.Signal<string>;
30
37
  readonly hintId: _angular_core.Signal<string>;
38
+ /**
39
+ * Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
40
+ * auto-resolved from the control's `ValidationErrors`. Plain method (not a
41
+ * computed): `ValidationErrors` is not a signal, so the control must be read
42
+ * fresh on every change-detection pass.
43
+ */
44
+ protected resolvedError(): string | undefined;
45
+ /**
46
+ * Whether the error is surfaced: message present + control invalid +
47
+ * touched/dirty/submitted. Gates the visual `<hlm-error>` (and
48
+ * `describedBy()`, where present) so sighted and screen-reader output agree.
49
+ */
50
+ protected showError(): boolean;
31
51
  /**
32
52
  * Bounds projected onto the picker's `Date` model. The cast keeps the
33
53
  * template's generic inference on `Date` while passing runtime values
@@ -49,7 +69,7 @@ declare class EgFormDateRangePicker {
49
69
  $errorClass: _angular_core.Signal<string>;
50
70
  $hintClass: _angular_core.Signal<string>;
51
71
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormDateRangePicker, never>;
52
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormDateRangePicker, "eg-form-date-range-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; }; "autoCloseOnEndSelection": { "alias": "autoCloseOnEndSelection"; "required": false; "isSignal": true; }; "captionLayout": { "alias": "captionLayout"; "required": false; "isSignal": true; }; "formatDates": { "alias": "formatDates"; "required": false; "isSignal": true; }; "transformDates": { "alias": "transformDates"; "required": false; "isSignal": true; }; "parseDate": { "alias": "parseDate"; "required": false; "isSignal": true; }; "formatInputDates": { "alias": "formatInputDates"; "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>;
72
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormDateRangePicker, "eg-form-date-range-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; }; "autoCloseOnEndSelection": { "alias": "autoCloseOnEndSelection"; "required": false; "isSignal": true; }; "captionLayout": { "alias": "captionLayout"; "required": false; "isSignal": true; }; "formatDates": { "alias": "formatDates"; "required": false; "isSignal": true; }; "transformDates": { "alias": "transformDates"; "required": false; "isSignal": true; }; "parseDate": { "alias": "parseDate"; "required": false; "isSignal": true; }; "formatInputDates": { "alias": "formatInputDates"; "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>;
53
73
  }
54
74
 
55
75
  export { EgFormDateRangePicker };
@@ -338,6 +338,15 @@ export class CheckFieldComponent {
338
338
  }
339
339
  ```
340
340
 
341
+ ## Automatic error messages (`eg-form-*` wrappers)
342
+
343
+ The `eg-form-*` wrappers auto-resolve their displayed message from the control's `ValidationErrors` when no explicit `error` is set:
344
+
345
+ - Resolution order: explicit `error()` wins; otherwise (when `autoError()` is `true`, the default) the message is resolved from a custom dictionary entry, then the built-in defaults (`required`, `requiredTrue`, `email`, `minlength`, `maxlength`, `min`, `max`, `pattern`), then a generic "`label` is invalid" fallback. `error=""` is treated as unset.
346
+ - Set `autoError="false"` on a wrapper for manual-only messages.
347
+ - Global wording / custom validator keys (e.g. `usernameTaken`) and i18n are configured app-wide via `provideEgFormErrorMessages({...})` (merged over `DEFAULT_EG_FORM_ERROR_MESSAGES`, read with `injectEgFormErrorMessages()`); per-call overrides go through `resolveEgFormError(errors, label, messages)`.
348
+ - _When_ a message surfaces: wrappers render `<hlm-error>` (and point `aria-describedby` at it) only when the control is invalid + touched/dirty/submitted — otherwise the hint shows.
349
+
341
350
  ## Accessibility notes
342
351
 
343
352
  - The wrapper itself adds no label — always include a `<label hlmLabel>` (or `aria-label` on the control) so the field has an accessible name.