@fovestta2/web-angular 1.0.4 → 1.0.5

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 (48) hide show
  1. package/esm2022/lib/add-update-form/add-update-form.component.mjs +81 -26
  2. package/esm2022/lib/fv-checkbox/fv-checkbox.component.mjs +13 -3
  3. package/esm2022/lib/fv-controls.module.mjs +22 -4
  4. package/esm2022/lib/fv-date-field/fv-date-field.component.mjs +13 -3
  5. package/esm2022/lib/fv-dropdown/fv-dropdown.component.mjs +67 -6
  6. package/esm2022/lib/fv-email-field/fv-email-field.component.mjs +123 -0
  7. package/esm2022/lib/fv-entry-field/fv-entry-field.component.mjs +13 -3
  8. package/esm2022/lib/fv-esi-field/fv-esi-field.component.mjs +13 -3
  9. package/esm2022/lib/fv-file-selector/fv-file-selector.component.mjs +13 -3
  10. package/esm2022/lib/fv-iban-field/fv-iban-field.component.mjs +13 -3
  11. package/esm2022/lib/fv-ifsc-field/fv-ifsc-field.component.mjs +3 -3
  12. package/esm2022/lib/fv-image-selector/fv-image-selector.component.mjs +3 -3
  13. package/esm2022/lib/fv-micr-field/fv-micr-field.component.mjs +3 -3
  14. package/esm2022/lib/fv-month-year-field/fv-month-year-field.component.mjs +39 -3
  15. package/esm2022/lib/fv-name-code/fv-name-code.component.mjs +73 -38
  16. package/esm2022/lib/fv-number-field/fv-number-field.component.mjs +13 -3
  17. package/esm2022/lib/fv-password-field/fv-password-field.component.mjs +118 -0
  18. package/esm2022/lib/fv-pf-field/fv-pf-field.component.mjs +46 -4
  19. package/esm2022/lib/fv-phone-field/fv-phone-field.component.mjs +13 -3
  20. package/esm2022/lib/fv-radio-group/fv-radio-group.component.mjs +13 -3
  21. package/esm2022/lib/fv-rich-text-editor/fv-rich-text-editor.component.mjs +4 -4
  22. package/esm2022/lib/fv-uan-field/fv-uan-field.component.mjs +13 -3
  23. package/esm2022/lib/query-form/query-form.component.mjs +58 -3
  24. package/esm2022/public-api.mjs +3 -1
  25. package/fesm2022/fovestta2-web-angular.mjs +870 -249
  26. package/fesm2022/fovestta2-web-angular.mjs.map +1 -1
  27. package/lib/add-update-form/add-update-form.component.d.ts +4 -2
  28. package/lib/fv-checkbox/fv-checkbox.component.d.ts +3 -2
  29. package/lib/fv-controls.module.d.ts +4 -1
  30. package/lib/fv-date-field/fv-date-field.component.d.ts +3 -2
  31. package/lib/fv-dropdown/fv-dropdown.component.d.ts +3 -0
  32. package/lib/fv-email-field/fv-email-field.component.d.ts +27 -0
  33. package/lib/fv-entry-field/fv-entry-field.component.d.ts +3 -1
  34. package/lib/fv-esi-field/fv-esi-field.component.d.ts +3 -2
  35. package/lib/fv-file-selector/fv-file-selector.component.d.ts +3 -2
  36. package/lib/fv-iban-field/fv-iban-field.component.d.ts +3 -2
  37. package/lib/fv-month-year-field/fv-month-year-field.component.d.ts +6 -2
  38. package/lib/fv-name-code/fv-name-code.component.d.ts +3 -0
  39. package/lib/fv-number-field/fv-number-field.component.d.ts +3 -2
  40. package/lib/fv-password-field/fv-password-field.component.d.ts +29 -0
  41. package/lib/fv-pf-field/fv-pf-field.component.d.ts +4 -2
  42. package/lib/fv-phone-field/fv-phone-field.component.d.ts +3 -2
  43. package/lib/fv-radio-group/fv-radio-group.component.d.ts +3 -2
  44. package/lib/fv-rich-text-editor/fv-rich-text-editor.component.d.ts +1 -1
  45. package/lib/fv-uan-field/fv-uan-field.component.d.ts +3 -2
  46. package/lib/query-form/query-form.component.d.ts +1 -1
  47. package/package.json +2 -2
  48. package/public-api.d.ts +2 -0
@@ -6,7 +6,6 @@ import * as i2 from '@angular/forms';
6
6
  import { ReactiveFormsModule, FormControl, NG_VALUE_ACCESSOR, FormsModule, Validators } from '@angular/forms';
7
7
  import { Validator } from '@fovestta2/validation-engine';
8
8
  import * as i1$1 from '@angular/platform-browser';
9
- import { Validator as Validator$1 } from '@fovestta/validation-engine';
10
9
  import { distinctUntilChanged } from 'rxjs/operators';
11
10
 
12
11
  class FvEntryFieldComponent {
@@ -46,6 +45,16 @@ class FvEntryFieldComponent {
46
45
  ngOnDestroy() {
47
46
  this.subscription?.unsubscribe();
48
47
  }
48
+ ngOnChanges(changes) {
49
+ if (changes['disabled'] && this.control) {
50
+ if (this.disabled) {
51
+ this.control.disable({ emitEvent: false });
52
+ }
53
+ else {
54
+ this.control.enable({ emitEvent: false });
55
+ }
56
+ }
57
+ }
49
58
  validateValue(value) {
50
59
  if (!this.schema)
51
60
  return;
@@ -103,11 +112,11 @@ class FvEntryFieldComponent {
103
112
  return errorMessages[this.errorMessage] || this.errorMessage;
104
113
  }
105
114
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEntryFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
106
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvEntryFieldComponent, isStandalone: true, selector: "fv-entry-field", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", type: "type", allowAlphabetsOnly: "allowAlphabetsOnly", maxLength: "maxLength" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-entry-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\" [class.fv-label-required]=\"isRequired()\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <input [type]=\"type\" [formControl]=\"control\" [placeholder]=\"placeholder\" [disabled]=\"disabled\" [readonly]=\"readonly\"\r\n (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" (input)=\"onInput($event)\" [attr.maxlength]=\"maxLength\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" [class.fv-input-disabled]=\"disabled\" />\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </span>\r\n</div>", styles: [".fv-entry-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:500;color:var(--fv-text-primary, #333333);display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:var(--fv-error-color, #dc3545);font-weight:700}.fv-input{padding:10px 12px;border:1px solid var(--fv-border-default, #cccccc);border-radius:4px;font-size:14px;font-family:inherit;transition:all .2s ease-in-out;background-color:var(--fv-background-default, #ffffff);color:var(--fv-text-primary, #333333)}.fv-input:focus{outline:none;border-color:var(--fv-border-focus, #007bff);box-shadow:0 0 0 3px var(--fv-focus-shadow, rgba(0, 123, 255, .1))}.fv-input:hover:not(:disabled):not(:focus){border-color:var(--fv-border-hover, #999999)}.fv-input-error{border-color:var(--fv-border-error, #dc3545)!important}.fv-input-error:focus{box-shadow:0 0 0 3px var(--fv-error-shadow, rgba(220, 53, 69, .1))}.fv-input-disabled{background-color:var(--fv-background-disabled, #f5f5f5);cursor:not-allowed;opacity:.6}.fv-input::placeholder{color:var(--fv-text-placeholder, #999999);opacity:1}.fv-error-message{margin-top:4px;font-size:12px;color:var(--fv-error-color, #dc3545);display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
115
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvEntryFieldComponent, isStandalone: true, selector: "fv-entry-field", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", type: "type", allowAlphabetsOnly: "allowAlphabetsOnly", maxLength: "maxLength" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-entry-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\" [class.fv-label-required]=\"isRequired()\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <input [type]=\"type\" [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\"\r\n (focus)=\"onFocus($event)\" (input)=\"onInput($event)\" [attr.maxlength]=\"maxLength\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage && control.touched\" [class.fv-input-disabled]=\"disabled\" />\r\n\r\n <span *ngIf=\"errorMessage && control.touched\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-entry-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:600;color:#151d48;display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:#e74c3c;font-weight:700}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;font-family:Poppins,sans-serif;transition:all .2s ease-in-out;background-color:#fff;color:#1f2b41;box-sizing:border-box;height:34px;width:100%;min-width:0}.fv-input:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input:hover:not(:disabled):not(:focus){border-color:#3498db}.fv-input-error{border-color:#dc3545!important}.fv-input-error:focus{box-shadow:0 0 0 3px #dc35451a}.fv-input-disabled{background-color:#ecf0f1;cursor:not-allowed;opacity:.6}.fv-input::placeholder{color:#999;opacity:1}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
107
116
  }
108
117
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEntryFieldComponent, decorators: [{
109
118
  type: Component,
110
- args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-entry-field', template: "<div class=\"fv-entry-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\" [class.fv-label-required]=\"isRequired()\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <input [type]=\"type\" [formControl]=\"control\" [placeholder]=\"placeholder\" [disabled]=\"disabled\" [readonly]=\"readonly\"\r\n (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" (input)=\"onInput($event)\" [attr.maxlength]=\"maxLength\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" [class.fv-input-disabled]=\"disabled\" />\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </span>\r\n</div>", styles: [".fv-entry-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:500;color:var(--fv-text-primary, #333333);display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:var(--fv-error-color, #dc3545);font-weight:700}.fv-input{padding:10px 12px;border:1px solid var(--fv-border-default, #cccccc);border-radius:4px;font-size:14px;font-family:inherit;transition:all .2s ease-in-out;background-color:var(--fv-background-default, #ffffff);color:var(--fv-text-primary, #333333)}.fv-input:focus{outline:none;border-color:var(--fv-border-focus, #007bff);box-shadow:0 0 0 3px var(--fv-focus-shadow, rgba(0, 123, 255, .1))}.fv-input:hover:not(:disabled):not(:focus){border-color:var(--fv-border-hover, #999999)}.fv-input-error{border-color:var(--fv-border-error, #dc3545)!important}.fv-input-error:focus{box-shadow:0 0 0 3px var(--fv-error-shadow, rgba(220, 53, 69, .1))}.fv-input-disabled{background-color:var(--fv-background-disabled, #f5f5f5);cursor:not-allowed;opacity:.6}.fv-input::placeholder{color:var(--fv-text-placeholder, #999999);opacity:1}.fv-error-message{margin-top:4px;font-size:12px;color:var(--fv-error-color, #dc3545);display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"] }]
119
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-entry-field', template: "<div class=\"fv-entry-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\" [class.fv-label-required]=\"isRequired()\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <input [type]=\"type\" [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\"\r\n (focus)=\"onFocus($event)\" (input)=\"onInput($event)\" [attr.maxlength]=\"maxLength\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage && control.touched\" [class.fv-input-disabled]=\"disabled\" />\r\n\r\n <span *ngIf=\"errorMessage && control.touched\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-entry-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:600;color:#151d48;display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:#e74c3c;font-weight:700}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;font-family:Poppins,sans-serif;transition:all .2s ease-in-out;background-color:#fff;color:#1f2b41;box-sizing:border-box;height:34px;width:100%;min-width:0}.fv-input:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input:hover:not(:disabled):not(:focus){border-color:#3498db}.fv-input-error{border-color:#dc3545!important}.fv-input-error:focus{box-shadow:0 0 0 3px #dc35451a}.fv-input-disabled{background-color:#ecf0f1;cursor:not-allowed;opacity:.6}.fv-input::placeholder{color:#999;opacity:1}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"] }]
111
120
  }], propDecorators: { label: [{
112
121
  type: Input
113
122
  }], placeholder: [{
@@ -168,6 +177,16 @@ class FvDateFieldComponent {
168
177
  ngOnDestroy() {
169
178
  this.subscription?.unsubscribe();
170
179
  }
180
+ ngOnChanges(changes) {
181
+ if (changes['disabled'] && this.control) {
182
+ if (this.disabled) {
183
+ this.control.disable({ emitEvent: false });
184
+ }
185
+ else {
186
+ this.control.enable({ emitEvent: false });
187
+ }
188
+ }
189
+ }
171
190
  extractConstraintsFromSchema() {
172
191
  if (!this.schema?.rules)
173
192
  return;
@@ -225,11 +244,11 @@ class FvDateFieldComponent {
225
244
  return errorMessages[this.errorMessage] || this.errorMessage;
226
245
  }
227
246
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvDateFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
228
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvDateFieldComponent, isStandalone: true, selector: "fv-date-field", inputs: { label: "label", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", min: "min", max: "max" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <input type=\"date\" [formControl]=\"control\" class=\"fv-input\" [class.error]=\"!!errorMessage\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:1rem}.fv-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:#374151}.required{color:#ef4444}.fv-input{padding:.5rem .75rem;border:1px solid #d1d5db;border-radius:.375rem;font-size:1rem;line-height:1.5;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.fv-input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.fv-input.error{border-color:#ef4444}.fv-input.error:focus{box-shadow:0 0 0 3px #ef44441a}.fv-error-message{margin-top:.25rem;font-size:.75rem;color:#ef4444}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
247
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvDateFieldComponent, isStandalone: true, selector: "fv-date-field", inputs: { label: "label", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", min: "min", max: "max" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <input type=\"date\" [formControl]=\"control\" class=\"fv-input\" [class.error]=\"!!errorMessage\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-date-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:600;color:#151d48;display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:#e74c3c;font-weight:700}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;font-family:Poppins,sans-serif;transition:all .2s ease-in-out;background-color:#fff;color:#1f2b41;box-sizing:border-box;width:100%;height:34px;min-width:0}.fv-input:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input:hover:not(:disabled):not(:focus){border-color:#3498db}.fv-input-error{border-color:#dc3545!important}.fv-input-error:focus{box-shadow:0 0 0 3px #dc35451a}.fv-input-disabled{background-color:#ecf0f1;cursor:not-allowed;opacity:.6}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
229
248
  }
230
249
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvDateFieldComponent, decorators: [{
231
250
  type: Component,
232
- args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-date-field', template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <input type=\"date\" [formControl]=\"control\" class=\"fv-input\" [class.error]=\"!!errorMessage\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:1rem}.fv-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:#374151}.required{color:#ef4444}.fv-input{padding:.5rem .75rem;border:1px solid #d1d5db;border-radius:.375rem;font-size:1rem;line-height:1.5;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.fv-input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.fv-input.error{border-color:#ef4444}.fv-input.error:focus{box-shadow:0 0 0 3px #ef44441a}.fv-error-message{margin-top:.25rem;font-size:.75rem;color:#ef4444}\n"] }]
251
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-date-field', template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <input type=\"date\" [formControl]=\"control\" class=\"fv-input\" [class.error]=\"!!errorMessage\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-date-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:600;color:#151d48;display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:#e74c3c;font-weight:700}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;font-family:Poppins,sans-serif;transition:all .2s ease-in-out;background-color:#fff;color:#1f2b41;box-sizing:border-box;width:100%;height:34px;min-width:0}.fv-input:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input:hover:not(:disabled):not(:focus){border-color:#3498db}.fv-input-error{border-color:#dc3545!important}.fv-input-error:focus{box-shadow:0 0 0 3px #dc35451a}.fv-input-disabled{background-color:#ecf0f1;cursor:not-allowed;opacity:.6}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"] }]
233
252
  }], propDecorators: { label: [{
234
253
  type: Input
235
254
  }], schema: [{
@@ -264,6 +283,7 @@ class FvMonthYearFieldComponent {
264
283
  blur = new EventEmitter();
265
284
  focus = new EventEmitter();
266
285
  errorMessage = null;
286
+ displayValue = '';
267
287
  subscription;
268
288
  ngOnInit() {
269
289
  if (!this.control) {
@@ -273,15 +293,27 @@ class FvMonthYearFieldComponent {
273
293
  this.extractConstraintsFromSchema();
274
294
  this.subscription = this.control.valueChanges.subscribe((value) => {
275
295
  this.validateValue(value);
296
+ this.updateDisplayValue(value);
276
297
  this.valueChange.emit(value);
277
298
  });
278
299
  if (this.control.value) {
279
300
  this.validateValue(this.control.value);
301
+ this.updateDisplayValue(this.control.value);
280
302
  }
281
303
  }
282
304
  ngOnDestroy() {
283
305
  this.subscription?.unsubscribe();
284
306
  }
307
+ ngOnChanges(changes) {
308
+ if (changes['disabled'] && this.control) {
309
+ if (this.disabled) {
310
+ this.control.disable({ emitEvent: false });
311
+ }
312
+ else {
313
+ this.control.enable({ emitEvent: false });
314
+ }
315
+ }
316
+ }
285
317
  extractConstraintsFromSchema() {
286
318
  if (!this.schema?.rules)
287
319
  return;
@@ -337,12 +369,35 @@ class FvMonthYearFieldComponent {
337
369
  };
338
370
  return errorMessages[this.errorMessage] || this.errorMessage;
339
371
  }
372
+ updateDisplayValue(value) {
373
+ if (!value) {
374
+ this.displayValue = '';
375
+ return;
376
+ }
377
+ const date = new Date(value + '-01'); // Ensure it's treated as YYYY-MM-01
378
+ if (isNaN(date.getTime())) {
379
+ this.displayValue = value;
380
+ return;
381
+ }
382
+ const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
383
+ this.displayValue = `${monthNames[date.getMonth()]} ${date.getFullYear()}`;
384
+ }
385
+ openPicker(picker) {
386
+ if (this.disabled || this.readonly)
387
+ return;
388
+ if (picker.showPicker) {
389
+ picker.showPicker();
390
+ }
391
+ else {
392
+ picker.click();
393
+ }
394
+ }
340
395
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvMonthYearFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
341
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvMonthYearFieldComponent, isStandalone: true, selector: "fv-month-year-field", inputs: { label: "label", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", min: "min", max: "max" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <input type=\"month\" [formControl]=\"control\" class=\"fv-input\" [class.error]=\"!!errorMessage\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:1rem}.fv-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:#374151}.required{color:#ef4444}.fv-input{padding:.5rem .75rem;border:1px solid #d1d5db;border-radius:.375rem;font-size:1rem;line-height:1.5;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.fv-input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.fv-input.error{border-color:#ef4444}.fv-input.error:focus{box-shadow:0 0 0 3px #ef44441a}.fv-error-message{margin-top:.25rem;font-size:.75rem;color:#ef4444}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
396
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvMonthYearFieldComponent, isStandalone: true, selector: "fv-month-year-field", inputs: { label: "label", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", min: "min", max: "max" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-input-wrapper\" (click)=\"openPicker(monthPicker)\">\r\n <input type=\"text\" [value]=\"displayValue\" class=\"fv-input\" [class.error]=\"!!errorMessage\"\r\n placeholder=\"Select Month\" readonly />\r\n <input #monthPicker type=\"month\" [formControl]=\"control\" class=\"fv-hidden-picker\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n <span class=\"fv-calendar-icon\">\r\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"></rect>\r\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"></line>\r\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"></line>\r\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"></line>\r\n </svg>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 35px 5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px;min-width:0;cursor:pointer}.fv-input-wrapper{position:relative;width:100%;cursor:pointer}.fv-hidden-picker{position:absolute;opacity:0;width:0;height:0;pointer-events:none}.fv-calendar-icon{position:absolute;right:10px;top:50%;transform:translateY(-50%);color:#666;pointer-events:none;display:flex;align-items:center}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input.error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
342
397
  }
343
398
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvMonthYearFieldComponent, decorators: [{
344
399
  type: Component,
345
- args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-month-year-field', template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <input type=\"month\" [formControl]=\"control\" class=\"fv-input\" [class.error]=\"!!errorMessage\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:1rem}.fv-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:#374151}.required{color:#ef4444}.fv-input{padding:.5rem .75rem;border:1px solid #d1d5db;border-radius:.375rem;font-size:1rem;line-height:1.5;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.fv-input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.fv-input.error{border-color:#ef4444}.fv-input.error:focus{box-shadow:0 0 0 3px #ef44441a}.fv-error-message{margin-top:.25rem;font-size:.75rem;color:#ef4444}\n"] }]
400
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-month-year-field', template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-input-wrapper\" (click)=\"openPicker(monthPicker)\">\r\n <input type=\"text\" [value]=\"displayValue\" class=\"fv-input\" [class.error]=\"!!errorMessage\"\r\n placeholder=\"Select Month\" readonly />\r\n <input #monthPicker type=\"month\" [formControl]=\"control\" class=\"fv-hidden-picker\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n <span class=\"fv-calendar-icon\">\r\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"></rect>\r\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"></line>\r\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"></line>\r\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"></line>\r\n </svg>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 35px 5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px;min-width:0;cursor:pointer}.fv-input-wrapper{position:relative;width:100%;cursor:pointer}.fv-hidden-picker{position:absolute;opacity:0;width:0;height:0;pointer-events:none}.fv-calendar-icon{position:absolute;right:10px;top:50%;transform:translateY(-50%);color:#666;pointer-events:none;display:flex;align-items:center}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input.error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
346
401
  }], propDecorators: { label: [{
347
402
  type: Input
348
403
  }], schema: [{
@@ -400,6 +455,16 @@ class FvNumberFieldComponent {
400
455
  ngOnDestroy() {
401
456
  this.subscription?.unsubscribe();
402
457
  }
458
+ ngOnChanges(changes) {
459
+ if (changes['disabled'] && this.control) {
460
+ if (this.disabled) {
461
+ this.control.disable({ emitEvent: false });
462
+ }
463
+ else {
464
+ this.control.enable({ emitEvent: false });
465
+ }
466
+ }
467
+ }
403
468
  validateValue(value) {
404
469
  if (!this.schema)
405
470
  return;
@@ -435,11 +500,11 @@ class FvNumberFieldComponent {
435
500
  return errorMessages[this.errorMessage] || this.errorMessage;
436
501
  }
437
502
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvNumberFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
438
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvNumberFieldComponent, isStandalone: true, selector: "fv-number-field", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", min: "min", max: "max", step: "step" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-number-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <input type=\"number\" [formControl]=\"control\" [placeholder]=\"placeholder\" [disabled]=\"disabled\" [readonly]=\"readonly\"\r\n [min]=\"min\" [max]=\"max\" [step]=\"step\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage\" [class.fv-input-disabled]=\"disabled\" />\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </span>\r\n</div>", styles: [".fv-number-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:500;color:var(--fv-text-primary, #333333);display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:var(--fv-error-color, #dc3545);font-weight:700}.fv-input{padding:10px 12px;border:1px solid var(--fv-border-default, #cccccc);border-radius:4px;font-size:14px;font-family:inherit;transition:all .2s ease-in-out;background-color:var(--fv-background-default, #ffffff);color:var(--fv-text-primary, #333333)}.fv-input:focus{outline:none;border-color:var(--fv-border-focus, #007bff);box-shadow:0 0 0 3px var(--fv-focus-shadow, rgba(0, 123, 255, .1))}.fv-input:hover:not(:disabled):not(:focus){border-color:var(--fv-border-hover, #999999)}.fv-input-error{border-color:var(--fv-border-error, #dc3545)!important}.fv-input-error:focus{box-shadow:0 0 0 3px var(--fv-error-shadow, rgba(220, 53, 69, .1))}.fv-input-disabled{background-color:var(--fv-background-disabled, #f5f5f5);cursor:not-allowed;opacity:.6}.fv-error-message{margin-top:4px;font-size:12px;color:var(--fv-error-color, #dc3545);display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}.fv-input::-webkit-inner-spin-button,.fv-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.fv-input[type=number]{-moz-appearance:textfield}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
503
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvNumberFieldComponent, isStandalone: true, selector: "fv-number-field", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", min: "min", max: "max", step: "step" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-number-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <input type=\"number\" [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\" [min]=\"min\" [max]=\"max\"\r\n [step]=\"step\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\"\r\n [class.fv-input-disabled]=\"disabled\" />\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-number-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:600;color:#151d48;display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:#e74c3c;font-weight:700}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;font-family:Poppins,sans-serif;transition:all .2s ease-in-out;background-color:#fff;color:#1f2b41;box-sizing:border-box;height:34px;width:100%;min-width:0}.fv-input:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input:hover:not(:disabled):not(:focus){border-color:#3498db}.fv-input-error{border-color:#dc3545!important}.fv-input-error:focus{box-shadow:0 0 0 3px #dc35451a}.fv-input-disabled{background-color:#ecf0f1;cursor:not-allowed;opacity:.6}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}.fv-input::-webkit-inner-spin-button,.fv-input::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none;margin:0}.fv-input[type=number]{-moz-appearance:textfield;appearance:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
439
504
  }
440
505
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvNumberFieldComponent, decorators: [{
441
506
  type: Component,
442
- args: [{ selector: 'fv-number-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-number-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <input type=\"number\" [formControl]=\"control\" [placeholder]=\"placeholder\" [disabled]=\"disabled\" [readonly]=\"readonly\"\r\n [min]=\"min\" [max]=\"max\" [step]=\"step\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage\" [class.fv-input-disabled]=\"disabled\" />\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </span>\r\n</div>", styles: [".fv-number-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:500;color:var(--fv-text-primary, #333333);display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:var(--fv-error-color, #dc3545);font-weight:700}.fv-input{padding:10px 12px;border:1px solid var(--fv-border-default, #cccccc);border-radius:4px;font-size:14px;font-family:inherit;transition:all .2s ease-in-out;background-color:var(--fv-background-default, #ffffff);color:var(--fv-text-primary, #333333)}.fv-input:focus{outline:none;border-color:var(--fv-border-focus, #007bff);box-shadow:0 0 0 3px var(--fv-focus-shadow, rgba(0, 123, 255, .1))}.fv-input:hover:not(:disabled):not(:focus){border-color:var(--fv-border-hover, #999999)}.fv-input-error{border-color:var(--fv-border-error, #dc3545)!important}.fv-input-error:focus{box-shadow:0 0 0 3px var(--fv-error-shadow, rgba(220, 53, 69, .1))}.fv-input-disabled{background-color:var(--fv-background-disabled, #f5f5f5);cursor:not-allowed;opacity:.6}.fv-error-message{margin-top:4px;font-size:12px;color:var(--fv-error-color, #dc3545);display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}.fv-input::-webkit-inner-spin-button,.fv-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.fv-input[type=number]{-moz-appearance:textfield}\n"] }]
507
+ args: [{ selector: 'fv-number-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-number-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <input type=\"number\" [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\" [min]=\"min\" [max]=\"max\"\r\n [step]=\"step\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\"\r\n [class.fv-input-disabled]=\"disabled\" />\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-number-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{margin-bottom:6px;font-size:14px;font-weight:600;color:#151d48;display:flex;align-items:center;gap:4px}.fv-required-asterisk{color:#e74c3c;font-weight:700}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;font-family:Poppins,sans-serif;transition:all .2s ease-in-out;background-color:#fff;color:#1f2b41;box-sizing:border-box;height:34px;width:100%;min-width:0}.fv-input:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input:hover:not(:disabled):not(:focus){border-color:#3498db}.fv-input-error{border-color:#dc3545!important}.fv-input-error:focus{box-shadow:0 0 0 3px #dc35451a}.fv-input-disabled{background-color:#ecf0f1;cursor:not-allowed;opacity:.6}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}.fv-input::-webkit-inner-spin-button,.fv-input::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none;margin:0}.fv-input[type=number]{-moz-appearance:textfield;appearance:none}\n"] }]
443
508
  }], propDecorators: { label: [{
444
509
  type: Input
445
510
  }], placeholder: [{
@@ -477,17 +542,27 @@ class FvCheckboxComponent {
477
542
  console.error('FvCheckbox: control is required');
478
543
  }
479
544
  }
545
+ ngOnChanges(changes) {
546
+ if (changes['disabled'] && this.control) {
547
+ if (this.disabled) {
548
+ this.control.disable({ emitEvent: false });
549
+ }
550
+ else {
551
+ this.control.enable({ emitEvent: false });
552
+ }
553
+ }
554
+ }
480
555
  onChange(event) {
481
556
  const checked = event.target.checked;
482
557
  this.control.setValue(checked);
483
558
  this.valueChange.emit(checked);
484
559
  }
485
560
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
486
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvCheckboxComponent, isStandalone: true, selector: "fv-checkbox", inputs: { label: "label", control: "control", disabled: "disabled", required: "required" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"fv-checkbox-container\">\r\n <label class=\"fv-checkbox-label\">\r\n <input type=\"checkbox\" [formControl]=\"control\" [disabled]=\"disabled\" (change)=\"onChange($event)\"\r\n class=\"fv-checkbox-input\" />\r\n <span class=\"fv-checkbox-custom\"></span>\r\n <span class=\"fv-checkbox-text\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"fv-required-asterisk\">*</span>\r\n </span>\r\n </label>\r\n</div>", styles: [".fv-checkbox-container{margin-bottom:12px}.fv-checkbox-label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;padding-left:32px;min-height:24px}.fv-checkbox-input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.fv-checkbox-custom{position:absolute;left:0;top:0;height:20px;width:20px;background-color:var(--fv-background-default, #ffffff);border:2px solid var(--fv-border-default, #cccccc);border-radius:4px;transition:all .2s}.fv-checkbox-label:hover .fv-checkbox-custom{border-color:var(--fv-border-hover, #999999)}.fv-checkbox-input:checked~.fv-checkbox-custom{background-color:var(--fv-border-focus, #667eea);border-color:var(--fv-border-focus, #667eea)}.fv-checkbox-custom:after{content:\"\";position:absolute;display:none;left:6px;top:2px;width:5px;height:10px;border:solid white;border-width:0 2px 2px 0;transform:rotate(45deg)}.fv-checkbox-input:checked~.fv-checkbox-custom:after{display:block}.fv-checkbox-input:disabled~.fv-checkbox-custom{background-color:var(--fv-background-disabled, #f5f5f5);cursor:not-allowed;opacity:.6}.fv-checkbox-text{font-size:14px;color:var(--fv-text-primary, #333333)}.fv-required-asterisk{color:var(--fv-error-color, #dc3545);margin-left:4px;font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
561
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvCheckboxComponent, isStandalone: true, selector: "fv-checkbox", inputs: { label: "label", control: "control", disabled: "disabled", required: "required" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-checkbox-container\">\r\n <label class=\"fv-checkbox-label\">\r\n <input type=\"checkbox\" [formControl]=\"control\" [disabled]=\"disabled\" (change)=\"onChange($event)\"\r\n class=\"fv-checkbox-input\" />\r\n <span class=\"fv-checkbox-custom\"></span>\r\n <span class=\"fv-checkbox-text\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"fv-required-asterisk\">*</span>\r\n </span>\r\n </label>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-checkbox-container{margin-bottom:12px}.fv-checkbox-label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;padding-left:32px;min-height:24px}.fv-checkbox-input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.fv-checkbox-custom{position:absolute;left:0;top:0;height:18px;width:18px;background-color:#fff;border:1px solid #8CBBA8;border-radius:4px;transition:all .2s}.fv-checkbox-label:hover .fv-checkbox-custom{border-color:#3498db}.fv-checkbox-input:checked~.fv-checkbox-custom{background-color:#3498db;border-color:#3498db}.fv-checkbox-custom:after{content:\"\";position:absolute;display:none;left:5px;top:1px;width:5px;height:10px;border:solid white;border-width:0 2px 2px 0;transform:rotate(45deg)}.fv-checkbox-input:checked~.fv-checkbox-custom:after{display:block}.fv-checkbox-input:disabled~.fv-checkbox-custom{background-color:#ecf0f1;cursor:not-allowed;opacity:.6}.fv-checkbox-text{font-size:14px;font-weight:600;color:#151d48}.fv-required-asterisk{color:#e74c3c;margin-left:4px;font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
487
562
  }
488
563
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvCheckboxComponent, decorators: [{
489
564
  type: Component,
490
- args: [{ selector: 'fv-checkbox', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-checkbox-container\">\r\n <label class=\"fv-checkbox-label\">\r\n <input type=\"checkbox\" [formControl]=\"control\" [disabled]=\"disabled\" (change)=\"onChange($event)\"\r\n class=\"fv-checkbox-input\" />\r\n <span class=\"fv-checkbox-custom\"></span>\r\n <span class=\"fv-checkbox-text\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"fv-required-asterisk\">*</span>\r\n </span>\r\n </label>\r\n</div>", styles: [".fv-checkbox-container{margin-bottom:12px}.fv-checkbox-label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;padding-left:32px;min-height:24px}.fv-checkbox-input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.fv-checkbox-custom{position:absolute;left:0;top:0;height:20px;width:20px;background-color:var(--fv-background-default, #ffffff);border:2px solid var(--fv-border-default, #cccccc);border-radius:4px;transition:all .2s}.fv-checkbox-label:hover .fv-checkbox-custom{border-color:var(--fv-border-hover, #999999)}.fv-checkbox-input:checked~.fv-checkbox-custom{background-color:var(--fv-border-focus, #667eea);border-color:var(--fv-border-focus, #667eea)}.fv-checkbox-custom:after{content:\"\";position:absolute;display:none;left:6px;top:2px;width:5px;height:10px;border:solid white;border-width:0 2px 2px 0;transform:rotate(45deg)}.fv-checkbox-input:checked~.fv-checkbox-custom:after{display:block}.fv-checkbox-input:disabled~.fv-checkbox-custom{background-color:var(--fv-background-disabled, #f5f5f5);cursor:not-allowed;opacity:.6}.fv-checkbox-text{font-size:14px;color:var(--fv-text-primary, #333333)}.fv-required-asterisk{color:var(--fv-error-color, #dc3545);margin-left:4px;font-weight:700}\n"] }]
565
+ args: [{ selector: 'fv-checkbox', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-checkbox-container\">\r\n <label class=\"fv-checkbox-label\">\r\n <input type=\"checkbox\" [formControl]=\"control\" [disabled]=\"disabled\" (change)=\"onChange($event)\"\r\n class=\"fv-checkbox-input\" />\r\n <span class=\"fv-checkbox-custom\"></span>\r\n <span class=\"fv-checkbox-text\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"fv-required-asterisk\">*</span>\r\n </span>\r\n </label>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-checkbox-container{margin-bottom:12px}.fv-checkbox-label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;padding-left:32px;min-height:24px}.fv-checkbox-input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.fv-checkbox-custom{position:absolute;left:0;top:0;height:18px;width:18px;background-color:#fff;border:1px solid #8CBBA8;border-radius:4px;transition:all .2s}.fv-checkbox-label:hover .fv-checkbox-custom{border-color:#3498db}.fv-checkbox-input:checked~.fv-checkbox-custom{background-color:#3498db;border-color:#3498db}.fv-checkbox-custom:after{content:\"\";position:absolute;display:none;left:5px;top:1px;width:5px;height:10px;border:solid white;border-width:0 2px 2px 0;transform:rotate(45deg)}.fv-checkbox-input:checked~.fv-checkbox-custom:after{display:block}.fv-checkbox-input:disabled~.fv-checkbox-custom{background-color:#ecf0f1;cursor:not-allowed;opacity:.6}.fv-checkbox-text{font-size:14px;font-weight:600;color:#151d48}.fv-required-asterisk{color:#e74c3c;margin-left:4px;font-weight:700}\n"] }]
491
566
  }], propDecorators: { label: [{
492
567
  type: Input
493
568
  }], control: [{
@@ -513,6 +588,16 @@ class FvRadioGroupComponent {
513
588
  console.error('FvRadioGroup: control is required');
514
589
  }
515
590
  }
591
+ ngOnChanges(changes) {
592
+ if (changes['disabled'] && this.control) {
593
+ if (this.disabled) {
594
+ this.control.disable({ emitEvent: false });
595
+ }
596
+ else {
597
+ this.control.enable({ emitEvent: false });
598
+ }
599
+ }
600
+ }
516
601
  onChange(value) {
517
602
  this.control.setValue(value);
518
603
  this.valueChange.emit(value);
@@ -521,11 +606,11 @@ class FvRadioGroupComponent {
521
606
  return this.control.value === value;
522
607
  }
523
608
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvRadioGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
524
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvRadioGroupComponent, isStandalone: true, selector: "fv-radio-group", inputs: { label: "label", control: "control", options: "options", disabled: "disabled", required: "required", name: "name" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"fv-radio-group-container\">\r\n <label *ngIf=\"label\" class=\"fv-group-label\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n \r\n <div class=\"fv-radio-options\">\r\n <label \r\n *ngFor=\"let option of options\" \r\n class=\"fv-radio-label\"\r\n [class.fv-radio-disabled]=\"disabled || option.disabled\">\r\n <input\r\n type=\"radio\"\r\n [name]=\"name\"\r\n [value]=\"option.value\"\r\n [checked]=\"isSelected(option.value)\"\r\n [disabled]=\"disabled || option.disabled\"\r\n (change)=\"onChange(option.value)\"\r\n class=\"fv-radio-input\"\r\n />\r\n <span class=\"fv-radio-custom\"></span>\r\n <span class=\"fv-radio-text\">{{ option.label }}</span>\r\n </label>\r\n </div>\r\n</div>", styles: [".fv-radio-group-container{margin-bottom:16px}.fv-group-label{display:block;margin-bottom:10px;font-size:14px;font-weight:500;color:var(--fv-text-primary, #333333)}.fv-required-asterisk{color:var(--fv-error-color, #dc3545);margin-left:4px;font-weight:700}.fv-radio-options{display:flex;flex-direction:column;gap:12px}.fv-radio-label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;padding-left:32px;min-height:24px}.fv-radio-input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.fv-radio-custom{position:absolute;left:0;top:0;height:20px;width:20px;background-color:var(--fv-background-default, #ffffff);border:2px solid var(--fv-border-default, #cccccc);border-radius:50%;transition:all .2s}.fv-radio-label:hover .fv-radio-custom{border-color:var(--fv-border-hover, #999999)}.fv-radio-input:checked~.fv-radio-custom{border-color:var(--fv-border-focus, #667eea)}.fv-radio-custom:after{content:\"\";position:absolute;display:none;top:4px;left:4px;width:13px;height:13px;border-radius:50%;background:var(--fv-border-focus, #667eea)}.fv-radio-input:checked~.fv-radio-custom:after{display:block}.fv-radio-disabled{opacity:.6;cursor:not-allowed}.fv-radio-disabled .fv-radio-custom{background-color:var(--fv-background-disabled, #f5f5f5)}.fv-radio-text{font-size:14px;color:var(--fv-text-primary, #333333)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
609
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvRadioGroupComponent, isStandalone: true, selector: "fv-radio-group", inputs: { label: "label", control: "control", options: "options", disabled: "disabled", required: "required", name: "name" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-radio-group-container\">\r\n <label *ngIf=\"label\" class=\"fv-group-label\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n \r\n <div class=\"fv-radio-options\">\r\n <label \r\n *ngFor=\"let option of options\" \r\n class=\"fv-radio-label\"\r\n [class.fv-radio-disabled]=\"disabled || option.disabled\">\r\n <input\r\n type=\"radio\"\r\n [name]=\"name\"\r\n [value]=\"option.value\"\r\n [checked]=\"isSelected(option.value)\"\r\n [disabled]=\"disabled || option.disabled\"\r\n (change)=\"onChange(option.value)\"\r\n class=\"fv-radio-input\"\r\n />\r\n <span class=\"fv-radio-custom\"></span>\r\n <span class=\"fv-radio-text\">{{ option.label }}</span>\r\n </label>\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-radio-group-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-group-label{display:block;margin-bottom:6px;font-size:14px;font-weight:600;color:#151d48}.fv-required-asterisk{color:#e74c3c;margin-left:4px;font-weight:700}.fv-radio-options{display:flex;flex-direction:column;gap:12px}.fv-radio-label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;padding-left:32px;min-height:24px}.fv-radio-input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.fv-radio-custom{position:absolute;left:0;top:0;height:18px;width:18px;background-color:#fff;border:1px solid #8CBBA8;border-radius:50%;transition:all .2s}.fv-radio-label:hover .fv-radio-custom{border-color:#3498db}.fv-radio-input:checked~.fv-radio-custom{border-color:#3498db}.fv-radio-custom:after{content:\"\";position:absolute;display:none;top:3px;left:3px;width:10px;height:10px;border-radius:50%;background:#3498db}.fv-radio-input:checked~.fv-radio-custom:after{display:block}.fv-radio-disabled{opacity:.6;cursor:not-allowed}.fv-radio-disabled .fv-radio-custom{background-color:#ecf0f1}.fv-radio-text{font-size:14px;font-weight:400;color:#1f2b41}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
525
610
  }
526
611
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvRadioGroupComponent, decorators: [{
527
612
  type: Component,
528
- args: [{ selector: 'fv-radio-group', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-radio-group-container\">\r\n <label *ngIf=\"label\" class=\"fv-group-label\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n \r\n <div class=\"fv-radio-options\">\r\n <label \r\n *ngFor=\"let option of options\" \r\n class=\"fv-radio-label\"\r\n [class.fv-radio-disabled]=\"disabled || option.disabled\">\r\n <input\r\n type=\"radio\"\r\n [name]=\"name\"\r\n [value]=\"option.value\"\r\n [checked]=\"isSelected(option.value)\"\r\n [disabled]=\"disabled || option.disabled\"\r\n (change)=\"onChange(option.value)\"\r\n class=\"fv-radio-input\"\r\n />\r\n <span class=\"fv-radio-custom\"></span>\r\n <span class=\"fv-radio-text\">{{ option.label }}</span>\r\n </label>\r\n </div>\r\n</div>", styles: [".fv-radio-group-container{margin-bottom:16px}.fv-group-label{display:block;margin-bottom:10px;font-size:14px;font-weight:500;color:var(--fv-text-primary, #333333)}.fv-required-asterisk{color:var(--fv-error-color, #dc3545);margin-left:4px;font-weight:700}.fv-radio-options{display:flex;flex-direction:column;gap:12px}.fv-radio-label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;padding-left:32px;min-height:24px}.fv-radio-input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.fv-radio-custom{position:absolute;left:0;top:0;height:20px;width:20px;background-color:var(--fv-background-default, #ffffff);border:2px solid var(--fv-border-default, #cccccc);border-radius:50%;transition:all .2s}.fv-radio-label:hover .fv-radio-custom{border-color:var(--fv-border-hover, #999999)}.fv-radio-input:checked~.fv-radio-custom{border-color:var(--fv-border-focus, #667eea)}.fv-radio-custom:after{content:\"\";position:absolute;display:none;top:4px;left:4px;width:13px;height:13px;border-radius:50%;background:var(--fv-border-focus, #667eea)}.fv-radio-input:checked~.fv-radio-custom:after{display:block}.fv-radio-disabled{opacity:.6;cursor:not-allowed}.fv-radio-disabled .fv-radio-custom{background-color:var(--fv-background-disabled, #f5f5f5)}.fv-radio-text{font-size:14px;color:var(--fv-text-primary, #333333)}\n"] }]
613
+ args: [{ selector: 'fv-radio-group', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-radio-group-container\">\r\n <label *ngIf=\"label\" class=\"fv-group-label\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n \r\n <div class=\"fv-radio-options\">\r\n <label \r\n *ngFor=\"let option of options\" \r\n class=\"fv-radio-label\"\r\n [class.fv-radio-disabled]=\"disabled || option.disabled\">\r\n <input\r\n type=\"radio\"\r\n [name]=\"name\"\r\n [value]=\"option.value\"\r\n [checked]=\"isSelected(option.value)\"\r\n [disabled]=\"disabled || option.disabled\"\r\n (change)=\"onChange(option.value)\"\r\n class=\"fv-radio-input\"\r\n />\r\n <span class=\"fv-radio-custom\"></span>\r\n <span class=\"fv-radio-text\">{{ option.label }}</span>\r\n </label>\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-radio-group-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-group-label{display:block;margin-bottom:6px;font-size:14px;font-weight:600;color:#151d48}.fv-required-asterisk{color:#e74c3c;margin-left:4px;font-weight:700}.fv-radio-options{display:flex;flex-direction:column;gap:12px}.fv-radio-label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;padding-left:32px;min-height:24px}.fv-radio-input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.fv-radio-custom{position:absolute;left:0;top:0;height:18px;width:18px;background-color:#fff;border:1px solid #8CBBA8;border-radius:50%;transition:all .2s}.fv-radio-label:hover .fv-radio-custom{border-color:#3498db}.fv-radio-input:checked~.fv-radio-custom{border-color:#3498db}.fv-radio-custom:after{content:\"\";position:absolute;display:none;top:3px;left:3px;width:10px;height:10px;border-radius:50%;background:#3498db}.fv-radio-input:checked~.fv-radio-custom:after{display:block}.fv-radio-disabled{opacity:.6;cursor:not-allowed}.fv-radio-disabled .fv-radio-custom{background-color:#ecf0f1}.fv-radio-text{font-size:14px;font-weight:400;color:#1f2b41}\n"] }]
529
614
  }], propDecorators: { label: [{
530
615
  type: Input
531
616
  }], control: [{
@@ -559,6 +644,7 @@ class FvDropdownComponent {
559
644
  subscription;
560
645
  searchControl = new FormControl('');
561
646
  filteredOptions = [];
647
+ highlightedIndex = -1;
562
648
  constructor(el) {
563
649
  this.el = el;
564
650
  }
@@ -633,10 +719,12 @@ class FvDropdownComponent {
633
719
  filterOptions(term) {
634
720
  if (!term) {
635
721
  this.filteredOptions = this.options;
636
- return;
637
722
  }
638
- const lower = term.toLowerCase();
639
- this.filteredOptions = this.options.filter(opt => opt.label.toLowerCase().includes(lower));
723
+ else {
724
+ const lower = term.toLowerCase();
725
+ this.filteredOptions = this.options.filter(opt => opt.label.toLowerCase().includes(lower));
726
+ }
727
+ this.highlightedIndex = this.filteredOptions.length === 1 ? 0 : -1;
640
728
  }
641
729
  toggleDropdown() {
642
730
  if (!this.disabled) {
@@ -654,6 +742,7 @@ class FvDropdownComponent {
654
742
  this.focus.emit();
655
743
  // Filter based on current text, do not reset blindly
656
744
  this.filterOptions(this.searchControl.value || '');
745
+ this.highlightedIndex = this.filteredOptions.length === 1 ? 0 : -1;
657
746
  }
658
747
  }
659
748
  onContainerClick(event) {
@@ -670,6 +759,7 @@ class FvDropdownComponent {
670
759
  }
671
760
  closeDropdown() {
672
761
  this.isOpen = false;
762
+ this.highlightedIndex = -1;
673
763
  // Restore label
674
764
  const selected = this.options.find(opt => opt.value === this.control.value);
675
765
  if (selected) {
@@ -681,12 +771,65 @@ class FvDropdownComponent {
681
771
  }
682
772
  }
683
773
  selectOption(option) {
774
+ if (!option)
775
+ return;
684
776
  this.control.setValue(option.value);
685
777
  this.searchControl.setValue(option.label, { emitEvent: false });
686
778
  this.isOpen = false;
779
+ this.highlightedIndex = -1;
687
780
  this.searchInput.nativeElement.blur(); // Remove focus from input
688
781
  this.blur.emit();
689
782
  }
783
+ onKeyDown(event) {
784
+ if (!this.isOpen && (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter')) {
785
+ this.openDropdown();
786
+ event.preventDefault();
787
+ return;
788
+ }
789
+ if (!this.isOpen)
790
+ return;
791
+ switch (event.key) {
792
+ case 'ArrowDown':
793
+ event.preventDefault();
794
+ this.highlightedIndex = (this.highlightedIndex + 1) % this.filteredOptions.length;
795
+ this.scrollToHighlighted();
796
+ break;
797
+ case 'ArrowUp':
798
+ event.preventDefault();
799
+ this.highlightedIndex = (this.highlightedIndex - 1 + this.filteredOptions.length) % this.filteredOptions.length;
800
+ this.scrollToHighlighted();
801
+ break;
802
+ case 'Enter':
803
+ event.preventDefault();
804
+ if (this.filteredOptions.length === 1) {
805
+ this.selectOption(this.filteredOptions[0]);
806
+ }
807
+ else if (this.highlightedIndex >= 0 && this.highlightedIndex < this.filteredOptions.length) {
808
+ this.selectOption(this.filteredOptions[this.highlightedIndex]);
809
+ }
810
+ break;
811
+ case 'Escape':
812
+ this.closeDropdown();
813
+ break;
814
+ case 'Tab':
815
+ this.closeDropdown();
816
+ break;
817
+ }
818
+ }
819
+ scrollToHighlighted() {
820
+ const list = document.querySelector('.fv-dropdown-options');
821
+ const item = document.querySelectorAll('.fv-dropdown-option')[this.highlightedIndex];
822
+ if (list && item) {
823
+ const listRect = list.getBoundingClientRect();
824
+ const itemRect = item.getBoundingClientRect();
825
+ if (itemRect.bottom > listRect.bottom) {
826
+ list.scrollTop += (itemRect.bottom - listRect.bottom);
827
+ }
828
+ else if (itemRect.top < listRect.top) {
829
+ list.scrollTop -= (listRect.top - itemRect.top);
830
+ }
831
+ }
832
+ }
690
833
  onBlur() {
691
834
  // Validation handled on closeDropdown
692
835
  }
@@ -724,11 +867,11 @@ class FvDropdownComponent {
724
867
  return option.value === this.control?.value;
725
868
  }
726
869
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvDropdownComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
727
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvDropdownComponent, isStandalone: true, selector: "fv-dropdown", inputs: { label: "label", placeholder: "placeholder", options: "options", schema: "schema", control: "control", disabled: "disabled" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-dropdown-container\">\r\n <label *ngIf=\"label\" class=\"fv-dropdown-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-dropdown-wrapper\">\r\n <div class=\"fv-dropdown\" [class.fv-dropdown-error]=\"errorMessage\" [class.fv-dropdown-disabled]=\"disabled\"\r\n [class.fv-dropdown-open]=\"isOpen\" (click)=\"onContainerClick($event)\">\r\n <input #searchInput type=\"text\" class=\"fv-dropdown-input\" [formControl]=\"searchControl\"\r\n [placeholder]=\"placeholder\" (focus)=\"onInputFocus()\" (click)=\"$event.stopPropagation()\"\r\n autocomplete=\"off\">\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\" (click)=\"toggleDropdown()\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <div *ngFor=\"let option of filteredOptions\" class=\"fv-dropdown-option\"\r\n [class.fv-dropdown-option-selected]=\"isSelected(option)\" (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"selectOption(option)\">\r\n {{ option.label }}\r\n </div>\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"fv-dropdown-option fv-no-results\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-dropdown-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-dropdown-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-dropdown-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-dropdown-wrapper{position:relative}.fv-dropdown{padding:10px;border:1px solid #cccccc;border-radius:4px;background-color:#fff;cursor:pointer;display:flex;justify-content:space-between;align-items:center;transition:border-color .2s;outline:none}.fv-dropdown:hover:not(.fv-dropdown-disabled){border-color:#007bff}.fv-dropdown:focus:not(.fv-dropdown-disabled){border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-dropdown-error{border-color:#dc3545!important}.fv-dropdown-disabled{background-color:#f5f5f5;opacity:.6;cursor:not-allowed}.fv-dropdown-open{border-color:#007bff}.fv-dropdown-selected{font-size:14px;color:#333;flex:1}.fv-dropdown-placeholder{color:#999}.fv-dropdown-arrow{font-size:10px;color:#666;margin-left:8px;margin-right:5px;transition:transform .2s}.arrow-up{transform:rotate(180deg)}.fv-dropdown-options{position:absolute;top:100%;left:0;right:0;margin-top:4px;background-color:#fff;border:1px solid #cccccc;border-radius:4px;max-height:300px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px #0000001a}.fv-dropdown-option{padding:12px 16px;font-size:14px;color:#333;cursor:pointer;transition:background-color .2s;border-bottom:1px solid #eeeeee}.fv-dropdown-option:last-child{border-bottom:none}.fv-dropdown-option:hover{background-color:#f8f9fa}.fv-dropdown-option-selected{background-color:#e7f3ff;color:#007bff;font-weight:600}.fv-dropdown-error-message{margin-top:4px;font-size:12px;color:#dc3545}.fv-dropdown-input{border:none;outline:none;background:transparent;flex:1;width:auto;font-size:14px;color:#333;padding:0;margin:0;cursor:text;z-index:2;position:relative;pointer-events:auto;height:100%}.fv-dropdown-input::placeholder{color:#999}.fv-no-results{color:#999;font-style:italic;cursor:default;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
870
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvDropdownComponent, isStandalone: true, selector: "fv-dropdown", inputs: { label: "label", placeholder: "placeholder", options: "options", schema: "schema", control: "control", disabled: "disabled" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, host: { listeners: { "keydown": "onKeyDown($event)", "document:click": "onClickOutside($event)" } }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-dropdown-container\">\r\n <label *ngIf=\"label\" class=\"fv-dropdown-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-dropdown-wrapper\">\r\n <div class=\"fv-dropdown\" [class.fv-dropdown-error]=\"errorMessage\" [class.fv-dropdown-disabled]=\"disabled\"\r\n [class.fv-dropdown-open]=\"isOpen\" (click)=\"onContainerClick($event)\">\r\n <input #searchInput type=\"text\" class=\"fv-dropdown-input\" [formControl]=\"searchControl\"\r\n [placeholder]=\"placeholder\" (focus)=\"onInputFocus()\" (click)=\"$event.stopPropagation()\"\r\n autocomplete=\"off\">\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\" (click)=\"toggleDropdown()\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <div *ngFor=\"let option of filteredOptions; let i = index\" class=\"fv-dropdown-option\"\r\n [class.fv-dropdown-option-selected]=\"isSelected(option)\"\r\n [class.fv-dropdown-option-highlighted]=\"i === highlightedIndex\" (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"selectOption(option)\">\r\n {{ option.label }}\r\n </div>\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"fv-dropdown-option fv-no-results\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-dropdown-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.material-icons{font-family:Material Icons!important}.fv-dropdown-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-dropdown-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-dropdown-wrapper{position:relative}.fv-dropdown{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;background-color:#fff;cursor:pointer;display:flex;justify-content:space-between;align-items:center;transition:border-color .2s;outline:none;font-size:14px;font-weight:400;color:#1f2b41;box-sizing:border-box;height:34px}.fv-dropdown:hover:not(.fv-dropdown-disabled){border-color:#3498db}.fv-dropdown:focus-within:not(.fv-dropdown-disabled){border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-dropdown-error{border-color:#dc3545!important}.fv-dropdown-disabled{background-color:#ecf0f1;opacity:.6;cursor:not-allowed}.fv-dropdown-open{border-color:#3498db}.fv-dropdown-selected{font-size:14px;font-weight:400;color:#1f2b41;flex:1}.fv-dropdown-placeholder{color:#999}.fv-dropdown-arrow{font-size:10px;color:#666;margin-left:8px;margin-right:5px;transition:transform .2s}.arrow-up{transform:rotate(180deg)}.fv-dropdown-options{position:absolute;top:100%;left:0;right:0;margin-top:4px;background-color:#fff;border:1px solid #cccccc;border-radius:4px;max-height:300px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px #0000001a}.fv-dropdown-option{padding:12px 16px;font-size:14px;color:#333;cursor:pointer;transition:background-color .2s;border-bottom:1px solid #eeeeee}.fv-dropdown-option:last-child{border-bottom:none}.fv-dropdown-option:hover,.fv-dropdown-option-highlighted{background-color:#f8f9fa}.fv-dropdown-option-selected{background-color:#e7f3ff;color:#007bff;font-weight:600}.fv-dropdown-error-message{margin-top:4px;font-size:12px;color:#dc3545}.fv-dropdown-input{border:none!important;outline:none!important;box-shadow:none!important;background:transparent;flex:1;width:100%;min-width:0;appearance:none;-webkit-appearance:none;font-size:14px;color:#1f2b41;padding:0;margin:0;cursor:text;z-index:2;position:relative;pointer-events:auto;height:100%}.fv-dropdown-input::placeholder{color:#999}.fv-no-results{color:#999;font-style:italic;cursor:default;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
728
871
  }
729
872
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvDropdownComponent, decorators: [{
730
873
  type: Component,
731
- args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-dropdown', template: "<div class=\"fv-dropdown-container\">\r\n <label *ngIf=\"label\" class=\"fv-dropdown-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-dropdown-wrapper\">\r\n <div class=\"fv-dropdown\" [class.fv-dropdown-error]=\"errorMessage\" [class.fv-dropdown-disabled]=\"disabled\"\r\n [class.fv-dropdown-open]=\"isOpen\" (click)=\"onContainerClick($event)\">\r\n <input #searchInput type=\"text\" class=\"fv-dropdown-input\" [formControl]=\"searchControl\"\r\n [placeholder]=\"placeholder\" (focus)=\"onInputFocus()\" (click)=\"$event.stopPropagation()\"\r\n autocomplete=\"off\">\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\" (click)=\"toggleDropdown()\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <div *ngFor=\"let option of filteredOptions\" class=\"fv-dropdown-option\"\r\n [class.fv-dropdown-option-selected]=\"isSelected(option)\" (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"selectOption(option)\">\r\n {{ option.label }}\r\n </div>\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"fv-dropdown-option fv-no-results\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-dropdown-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-dropdown-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-dropdown-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-dropdown-wrapper{position:relative}.fv-dropdown{padding:10px;border:1px solid #cccccc;border-radius:4px;background-color:#fff;cursor:pointer;display:flex;justify-content:space-between;align-items:center;transition:border-color .2s;outline:none}.fv-dropdown:hover:not(.fv-dropdown-disabled){border-color:#007bff}.fv-dropdown:focus:not(.fv-dropdown-disabled){border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-dropdown-error{border-color:#dc3545!important}.fv-dropdown-disabled{background-color:#f5f5f5;opacity:.6;cursor:not-allowed}.fv-dropdown-open{border-color:#007bff}.fv-dropdown-selected{font-size:14px;color:#333;flex:1}.fv-dropdown-placeholder{color:#999}.fv-dropdown-arrow{font-size:10px;color:#666;margin-left:8px;margin-right:5px;transition:transform .2s}.arrow-up{transform:rotate(180deg)}.fv-dropdown-options{position:absolute;top:100%;left:0;right:0;margin-top:4px;background-color:#fff;border:1px solid #cccccc;border-radius:4px;max-height:300px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px #0000001a}.fv-dropdown-option{padding:12px 16px;font-size:14px;color:#333;cursor:pointer;transition:background-color .2s;border-bottom:1px solid #eeeeee}.fv-dropdown-option:last-child{border-bottom:none}.fv-dropdown-option:hover{background-color:#f8f9fa}.fv-dropdown-option-selected{background-color:#e7f3ff;color:#007bff;font-weight:600}.fv-dropdown-error-message{margin-top:4px;font-size:12px;color:#dc3545}.fv-dropdown-input{border:none;outline:none;background:transparent;flex:1;width:auto;font-size:14px;color:#333;padding:0;margin:0;cursor:text;z-index:2;position:relative;pointer-events:auto;height:100%}.fv-dropdown-input::placeholder{color:#999}.fv-no-results{color:#999;font-style:italic;cursor:default;text-align:center}\n"] }]
874
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-dropdown', template: "<div class=\"fv-dropdown-container\">\r\n <label *ngIf=\"label\" class=\"fv-dropdown-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-dropdown-wrapper\">\r\n <div class=\"fv-dropdown\" [class.fv-dropdown-error]=\"errorMessage\" [class.fv-dropdown-disabled]=\"disabled\"\r\n [class.fv-dropdown-open]=\"isOpen\" (click)=\"onContainerClick($event)\">\r\n <input #searchInput type=\"text\" class=\"fv-dropdown-input\" [formControl]=\"searchControl\"\r\n [placeholder]=\"placeholder\" (focus)=\"onInputFocus()\" (click)=\"$event.stopPropagation()\"\r\n autocomplete=\"off\">\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\" (click)=\"toggleDropdown()\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <div *ngFor=\"let option of filteredOptions; let i = index\" class=\"fv-dropdown-option\"\r\n [class.fv-dropdown-option-selected]=\"isSelected(option)\"\r\n [class.fv-dropdown-option-highlighted]=\"i === highlightedIndex\" (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"selectOption(option)\">\r\n {{ option.label }}\r\n </div>\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"fv-dropdown-option fv-no-results\">\r\n No options found\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-dropdown-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.material-icons{font-family:Material Icons!important}.fv-dropdown-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-dropdown-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-dropdown-wrapper{position:relative}.fv-dropdown{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;background-color:#fff;cursor:pointer;display:flex;justify-content:space-between;align-items:center;transition:border-color .2s;outline:none;font-size:14px;font-weight:400;color:#1f2b41;box-sizing:border-box;height:34px}.fv-dropdown:hover:not(.fv-dropdown-disabled){border-color:#3498db}.fv-dropdown:focus-within:not(.fv-dropdown-disabled){border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-dropdown-error{border-color:#dc3545!important}.fv-dropdown-disabled{background-color:#ecf0f1;opacity:.6;cursor:not-allowed}.fv-dropdown-open{border-color:#3498db}.fv-dropdown-selected{font-size:14px;font-weight:400;color:#1f2b41;flex:1}.fv-dropdown-placeholder{color:#999}.fv-dropdown-arrow{font-size:10px;color:#666;margin-left:8px;margin-right:5px;transition:transform .2s}.arrow-up{transform:rotate(180deg)}.fv-dropdown-options{position:absolute;top:100%;left:0;right:0;margin-top:4px;background-color:#fff;border:1px solid #cccccc;border-radius:4px;max-height:300px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px #0000001a}.fv-dropdown-option{padding:12px 16px;font-size:14px;color:#333;cursor:pointer;transition:background-color .2s;border-bottom:1px solid #eeeeee}.fv-dropdown-option:last-child{border-bottom:none}.fv-dropdown-option:hover,.fv-dropdown-option-highlighted{background-color:#f8f9fa}.fv-dropdown-option-selected{background-color:#e7f3ff;color:#007bff;font-weight:600}.fv-dropdown-error-message{margin-top:4px;font-size:12px;color:#dc3545}.fv-dropdown-input{border:none!important;outline:none!important;box-shadow:none!important;background:transparent;flex:1;width:100%;min-width:0;appearance:none;-webkit-appearance:none;font-size:14px;color:#1f2b41;padding:0;margin:0;cursor:text;z-index:2;position:relative;pointer-events:auto;height:100%}.fv-dropdown-input::placeholder{color:#999}.fv-no-results{color:#999;font-style:italic;cursor:default;text-align:center}\n"] }]
732
875
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { label: [{
733
876
  type: Input
734
877
  }], placeholder: [{
@@ -750,6 +893,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
750
893
  }], searchInput: [{
751
894
  type: ViewChild,
752
895
  args: ['searchInput']
896
+ }], onKeyDown: [{
897
+ type: HostListener,
898
+ args: ['keydown', ['$event']]
753
899
  }], onClickOutside: [{
754
900
  type: HostListener,
755
901
  args: ['document:click', ['$event']]
@@ -792,6 +938,16 @@ class FvFileSelectorComponent {
792
938
  ngOnDestroy() {
793
939
  this.subscription?.unsubscribe();
794
940
  }
941
+ ngOnChanges(changes) {
942
+ if (changes['disabled'] && this.control) {
943
+ if (this.disabled) {
944
+ this.control.disable({ emitEvent: false });
945
+ }
946
+ else {
947
+ this.control.enable({ emitEvent: false });
948
+ }
949
+ }
950
+ }
795
951
  validateValue(value) {
796
952
  if (!this.schema)
797
953
  return;
@@ -860,11 +1016,11 @@ class FvFileSelectorComponent {
860
1016
  return errorMessages[this.errorMessage] || this.errorMessage;
861
1017
  }
862
1018
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvFileSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
863
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvFileSelectorComponent, isStandalone: true, selector: "fv-file-selector", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", accept: "accept", maxSize: "maxSize" }, outputs: { valueChange: "valueChange", blur: "blur" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"fv-file-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <button type=\"button\" class=\"fv-file-selector-button\" [class.fv-file-selector-button-error]=\"errorMessage\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n {{ placeholder }}\r\n </button>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-file-info\">\r\n <div class=\"fv-file-details\">\r\n <div class=\"fv-file-name\">\uD83D\uDCC4 {{ selectedFile.name }}</div>\r\n <div class=\"fv-file-size\">{{ formatFileSize(selectedFile.size) }}</div>\r\n </div>\r\n <button type=\"button\" class=\"fv-file-remove\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n \u2715\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-file-selector-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-file-selector-button{padding:10px;border:1px solid #007bff;border-radius:4px;background-color:#007bff;color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;text-align:center}.fv-file-selector-button:hover:not(:disabled){background-color:#0056b3;border-color:#0056b3}.fv-file-selector-button-error{border-color:#dc3545;background-color:#dc3545}.fv-file-selector-button-error:hover:not(:disabled){background-color:#c82333;border-color:#c82333}.fv-file-selector-button-disabled{background-color:#ccc;border-color:#ccc;opacity:.6;cursor:not-allowed}.fv-file-info{display:flex;align-items:center;margin-top:8px;padding:10px;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:4px}.fv-file-details{flex:1}.fv-file-name{font-size:14px;color:#333;margin-bottom:4px;word-break:break-all}.fv-file-size{font-size:12px;color:#6c757d}.fv-file-remove{padding:4px 8px;margin-left:8px;background:none;border:none;font-size:18px;color:#dc3545;font-weight:700;cursor:pointer;transition:color .2s}.fv-file-remove:hover:not(:disabled){color:#c82333}.fv-file-remove:disabled{opacity:.5;cursor:not-allowed}.fv-file-selector-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
1019
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvFileSelectorComponent, isStandalone: true, selector: "fv-file-selector", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", accept: "accept", maxSize: "maxSize" }, outputs: { valueChange: "valueChange", blur: "blur" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-file-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <button type=\"button\" class=\"fv-file-selector-button\" [class.fv-file-selector-button-error]=\"errorMessage\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n {{ placeholder }}\r\n </button>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-file-info\">\r\n <div class=\"fv-file-details\">\r\n <div class=\"fv-file-name\">\uD83D\uDCC4 {{ selectedFile.name }}</div>\r\n <div class=\"fv-file-size\">{{ formatFileSize(selectedFile.size) }}</div>\r\n </div>\r\n <button type=\"button\" class=\"fv-file-remove\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n \u2715\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-file-selector-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-file-selector-button{padding:8px 16px;border:1px solid #3498db;border-radius:8px;background-color:#3498db;color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;text-align:center}.fv-file-selector-button:hover:not(:disabled){background-color:#2980b9;border-color:#2980b9}.fv-file-selector-button-error{border-color:#e74c3c;background-color:#e74c3c}.fv-file-selector-button-error:hover:not(:disabled){background-color:#c0392b;border-color:#c0392b}.fv-file-selector-button-disabled{background-color:#ecf0f1;border-color:#ecf0f1;color:#7f8c8d;opacity:.6;cursor:not-allowed}.fv-file-info{display:flex;align-items:center;margin-top:8px;padding:10px;background-color:#f8f9fa;border:1px solid #8CBBA8;border-radius:8px}.fv-file-details{flex:1}.fv-file-name{font-size:14px;color:#1f2b41;margin-bottom:4px;word-break:break-all}.fv-file-size{font-size:12px;color:#6c757d}.fv-file-remove{padding:4px 8px;margin-left:8px;background:none;border:none;font-size:18px;color:#e74c3c;font-weight:700;cursor:pointer;transition:color .2s}.fv-file-remove:hover:not(:disabled){color:#c0392b}.fv-file-remove:disabled{opacity:.5;cursor:not-allowed}.fv-file-selector-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
864
1020
  }
865
1021
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvFileSelectorComponent, decorators: [{
866
1022
  type: Component,
867
- args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-file-selector', template: "<div class=\"fv-file-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <button type=\"button\" class=\"fv-file-selector-button\" [class.fv-file-selector-button-error]=\"errorMessage\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n {{ placeholder }}\r\n </button>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-file-info\">\r\n <div class=\"fv-file-details\">\r\n <div class=\"fv-file-name\">\uD83D\uDCC4 {{ selectedFile.name }}</div>\r\n <div class=\"fv-file-size\">{{ formatFileSize(selectedFile.size) }}</div>\r\n </div>\r\n <button type=\"button\" class=\"fv-file-remove\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n \u2715\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-file-selector-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-file-selector-button{padding:10px;border:1px solid #007bff;border-radius:4px;background-color:#007bff;color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;text-align:center}.fv-file-selector-button:hover:not(:disabled){background-color:#0056b3;border-color:#0056b3}.fv-file-selector-button-error{border-color:#dc3545;background-color:#dc3545}.fv-file-selector-button-error:hover:not(:disabled){background-color:#c82333;border-color:#c82333}.fv-file-selector-button-disabled{background-color:#ccc;border-color:#ccc;opacity:.6;cursor:not-allowed}.fv-file-info{display:flex;align-items:center;margin-top:8px;padding:10px;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:4px}.fv-file-details{flex:1}.fv-file-name{font-size:14px;color:#333;margin-bottom:4px;word-break:break-all}.fv-file-size{font-size:12px;color:#6c757d}.fv-file-remove{padding:4px 8px;margin-left:8px;background:none;border:none;font-size:18px;color:#dc3545;font-weight:700;cursor:pointer;transition:color .2s}.fv-file-remove:hover:not(:disabled){color:#c82333}.fv-file-remove:disabled{opacity:.5;cursor:not-allowed}.fv-file-selector-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
1023
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-file-selector', template: "<div class=\"fv-file-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <button type=\"button\" class=\"fv-file-selector-button\" [class.fv-file-selector-button-error]=\"errorMessage\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n {{ placeholder }}\r\n </button>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-file-info\">\r\n <div class=\"fv-file-details\">\r\n <div class=\"fv-file-name\">\uD83D\uDCC4 {{ selectedFile.name }}</div>\r\n <div class=\"fv-file-size\">{{ formatFileSize(selectedFile.size) }}</div>\r\n </div>\r\n <button type=\"button\" class=\"fv-file-remove\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n \u2715\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-file-selector-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-file-selector-button{padding:8px 16px;border:1px solid #3498db;border-radius:8px;background-color:#3498db;color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;text-align:center}.fv-file-selector-button:hover:not(:disabled){background-color:#2980b9;border-color:#2980b9}.fv-file-selector-button-error{border-color:#e74c3c;background-color:#e74c3c}.fv-file-selector-button-error:hover:not(:disabled){background-color:#c0392b;border-color:#c0392b}.fv-file-selector-button-disabled{background-color:#ecf0f1;border-color:#ecf0f1;color:#7f8c8d;opacity:.6;cursor:not-allowed}.fv-file-info{display:flex;align-items:center;margin-top:8px;padding:10px;background-color:#f8f9fa;border:1px solid #8CBBA8;border-radius:8px}.fv-file-details{flex:1}.fv-file-name{font-size:14px;color:#1f2b41;margin-bottom:4px;word-break:break-all}.fv-file-size{font-size:12px;color:#6c757d}.fv-file-remove{padding:4px 8px;margin-left:8px;background:none;border:none;font-size:18px;color:#e74c3c;font-weight:700;cursor:pointer;transition:color .2s}.fv-file-remove:hover:not(:disabled){color:#c0392b}.fv-file-remove:disabled{opacity:.5;cursor:not-allowed}.fv-file-selector-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
868
1024
  }], propDecorators: { label: [{
869
1025
  type: Input
870
1026
  }], placeholder: [{
@@ -1011,11 +1167,11 @@ class FvImageSelectorComponent {
1011
1167
  return errorMessages[this.errorMessage] || this.errorMessage;
1012
1168
  }
1013
1169
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvImageSelectorComponent, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
1014
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvImageSelectorComponent, isStandalone: true, selector: "fv-image-selector", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", maxSize: "maxSize" }, outputs: { valueChange: "valueChange", blur: "blur" }, viewQueries: [{ propertyName: "imageInput", first: true, predicate: ["imageInput"], descendants: true }], ngImport: i0, template: "<div class=\"fv-image-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-image-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #imageInput type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedImage; else previewTemplate\">\r\n <button type=\"button\" class=\"fv-image-selector-button\" [class.fv-image-selector-button-error]=\"errorMessage\"\r\n [class.fv-image-selector-button-disabled]=\"disabled\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n \uD83D\uDCF7 {{ placeholder }}\r\n </button>\r\n </div>\r\n\r\n <ng-template #previewTemplate>\r\n <div class=\"fv-image-preview-container\">\r\n <img [src]=\"selectedImage!.url\" class=\"fv-image-preview\" alt=\"Selected image\" />\r\n <div class=\"fv-image-actions\">\r\n <button type=\"button\" class=\"fv-image-change-button\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n Change\r\n </button>\r\n <button type=\"button\" class=\"fv-image-remove-button\" (click)=\"removeImage()\" [disabled]=\"disabled\">\r\n Remove\r\n </button>\r\n </div>\r\n <div class=\"fv-image-info\">\r\n {{ selectedImage!.width }} \u00D7 {{ selectedImage!.height }} \u2022\r\n {{ formatFileSize(selectedImage!.size) }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-image-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-image-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-image-selector-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-image-selector-button{padding:40px;border:2px dashed #007bff;border-radius:8px;background-color:#f8f9fa;color:#007bff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;width:100%;text-align:center}.fv-image-selector-button:hover:not(:disabled){background-color:#e7f3ff}.fv-image-selector-button-error{border-color:#dc3545;color:#dc3545}.fv-image-selector-button-disabled{border-color:#ccc;background-color:#f5f5f5;color:#ccc;opacity:.6;cursor:not-allowed}.fv-image-preview-container{display:flex;flex-direction:column;align-items:center}.fv-image-preview{width:100%;max-width:600px;height:200px;object-fit:cover;border-radius:8px;background-color:#f0f0f0;margin-bottom:8px}.fv-image-actions{display:flex;gap:8px;margin-bottom:4px}.fv-image-change-button{padding:8px 16px;background-color:#007bff;color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-change-button:hover:not(:disabled){background-color:#0056b3}.fv-image-change-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-remove-button{padding:8px 16px;background-color:#dc3545;color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-remove-button:hover:not(:disabled){background-color:#c82333}.fv-image-remove-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-info{font-size:12px;color:#6c757d;text-align:center}.fv-image-selector-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
1170
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvImageSelectorComponent, isStandalone: true, selector: "fv-image-selector", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", maxSize: "maxSize" }, outputs: { valueChange: "valueChange", blur: "blur" }, viewQueries: [{ propertyName: "imageInput", first: true, predicate: ["imageInput"], descendants: true }], ngImport: i0, template: "<div class=\"fv-image-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-image-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #imageInput type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedImage; else previewTemplate\">\r\n <button type=\"button\" class=\"fv-image-selector-button\" [class.fv-image-selector-button-error]=\"errorMessage\"\r\n [class.fv-image-selector-button-disabled]=\"disabled\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n \uD83D\uDCF7 {{ placeholder }}\r\n </button>\r\n </div>\r\n\r\n <ng-template #previewTemplate>\r\n <div class=\"fv-image-preview-container\">\r\n <img [src]=\"selectedImage!.url\" class=\"fv-image-preview\" alt=\"Selected image\" />\r\n <div class=\"fv-image-actions\">\r\n <button type=\"button\" class=\"fv-image-change-button\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n Change\r\n </button>\r\n <button type=\"button\" class=\"fv-image-remove-button\" (click)=\"removeImage()\" [disabled]=\"disabled\">\r\n Remove\r\n </button>\r\n </div>\r\n <div class=\"fv-image-info\">\r\n {{ selectedImage!.width }} \u00D7 {{ selectedImage!.height }} \u2022\r\n {{ formatFileSize(selectedImage!.size) }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-image-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-image-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-image-selector-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-image-selector-button{padding:40px;border:2px dashed #3498db;border-radius:8px;background-color:#f8f9fa;color:#3498db;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;width:100%;text-align:center;box-sizing:border-box}.fv-image-selector-button:hover:not(:disabled){background-color:#e7f3ff}.fv-image-selector-button-error{border-color:#e74c3c;color:#e74c3c}.fv-image-selector-button-disabled{border-color:#ccc;background-color:#f5f5f5;color:#ccc;opacity:.6;cursor:not-allowed}.fv-image-preview-container{display:flex;flex-direction:column;align-items:center}.fv-image-preview{width:100%;max-width:600px;height:200px;object-fit:cover;border-radius:8px;background-color:#f0f0f0;margin-bottom:8px}.fv-image-actions{display:flex;gap:8px;margin-bottom:4px}.fv-image-change-button{padding:8px 16px;background-color:#3498db;color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-change-button:hover:not(:disabled){background-color:#2980b9}.fv-image-change-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-remove-button{padding:8px 16px;background-color:#e74c3c;color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-remove-button:hover:not(:disabled){background-color:#c0392b}.fv-image-remove-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-info{font-size:12px;color:#6c757d;text-align:center}.fv-image-selector-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
1015
1171
  }
1016
1172
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvImageSelectorComponent, decorators: [{
1017
1173
  type: Component,
1018
- args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-image-selector', template: "<div class=\"fv-image-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-image-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #imageInput type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedImage; else previewTemplate\">\r\n <button type=\"button\" class=\"fv-image-selector-button\" [class.fv-image-selector-button-error]=\"errorMessage\"\r\n [class.fv-image-selector-button-disabled]=\"disabled\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n \uD83D\uDCF7 {{ placeholder }}\r\n </button>\r\n </div>\r\n\r\n <ng-template #previewTemplate>\r\n <div class=\"fv-image-preview-container\">\r\n <img [src]=\"selectedImage!.url\" class=\"fv-image-preview\" alt=\"Selected image\" />\r\n <div class=\"fv-image-actions\">\r\n <button type=\"button\" class=\"fv-image-change-button\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n Change\r\n </button>\r\n <button type=\"button\" class=\"fv-image-remove-button\" (click)=\"removeImage()\" [disabled]=\"disabled\">\r\n Remove\r\n </button>\r\n </div>\r\n <div class=\"fv-image-info\">\r\n {{ selectedImage!.width }} \u00D7 {{ selectedImage!.height }} \u2022\r\n {{ formatFileSize(selectedImage!.size) }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-image-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-image-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-image-selector-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-image-selector-button{padding:40px;border:2px dashed #007bff;border-radius:8px;background-color:#f8f9fa;color:#007bff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;width:100%;text-align:center}.fv-image-selector-button:hover:not(:disabled){background-color:#e7f3ff}.fv-image-selector-button-error{border-color:#dc3545;color:#dc3545}.fv-image-selector-button-disabled{border-color:#ccc;background-color:#f5f5f5;color:#ccc;opacity:.6;cursor:not-allowed}.fv-image-preview-container{display:flex;flex-direction:column;align-items:center}.fv-image-preview{width:100%;max-width:600px;height:200px;object-fit:cover;border-radius:8px;background-color:#f0f0f0;margin-bottom:8px}.fv-image-actions{display:flex;gap:8px;margin-bottom:4px}.fv-image-change-button{padding:8px 16px;background-color:#007bff;color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-change-button:hover:not(:disabled){background-color:#0056b3}.fv-image-change-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-remove-button{padding:8px 16px;background-color:#dc3545;color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-remove-button:hover:not(:disabled){background-color:#c82333}.fv-image-remove-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-info{font-size:12px;color:#6c757d;text-align:center}.fv-image-selector-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
1174
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-image-selector', template: "<div class=\"fv-image-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-image-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #imageInput type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedImage; else previewTemplate\">\r\n <button type=\"button\" class=\"fv-image-selector-button\" [class.fv-image-selector-button-error]=\"errorMessage\"\r\n [class.fv-image-selector-button-disabled]=\"disabled\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n \uD83D\uDCF7 {{ placeholder }}\r\n </button>\r\n </div>\r\n\r\n <ng-template #previewTemplate>\r\n <div class=\"fv-image-preview-container\">\r\n <img [src]=\"selectedImage!.url\" class=\"fv-image-preview\" alt=\"Selected image\" />\r\n <div class=\"fv-image-actions\">\r\n <button type=\"button\" class=\"fv-image-change-button\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n Change\r\n </button>\r\n <button type=\"button\" class=\"fv-image-remove-button\" (click)=\"removeImage()\" [disabled]=\"disabled\">\r\n Remove\r\n </button>\r\n </div>\r\n <div class=\"fv-image-info\">\r\n {{ selectedImage!.width }} \u00D7 {{ selectedImage!.height }} \u2022\r\n {{ formatFileSize(selectedImage!.size) }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-image-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-image-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-image-selector-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-image-selector-button{padding:40px;border:2px dashed #3498db;border-radius:8px;background-color:#f8f9fa;color:#3498db;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;width:100%;text-align:center;box-sizing:border-box}.fv-image-selector-button:hover:not(:disabled){background-color:#e7f3ff}.fv-image-selector-button-error{border-color:#e74c3c;color:#e74c3c}.fv-image-selector-button-disabled{border-color:#ccc;background-color:#f5f5f5;color:#ccc;opacity:.6;cursor:not-allowed}.fv-image-preview-container{display:flex;flex-direction:column;align-items:center}.fv-image-preview{width:100%;max-width:600px;height:200px;object-fit:cover;border-radius:8px;background-color:#f0f0f0;margin-bottom:8px}.fv-image-actions{display:flex;gap:8px;margin-bottom:4px}.fv-image-change-button{padding:8px 16px;background-color:#3498db;color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-change-button:hover:not(:disabled){background-color:#2980b9}.fv-image-change-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-remove-button{padding:8px 16px;background-color:#e74c3c;color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-remove-button:hover:not(:disabled){background-color:#c0392b}.fv-image-remove-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-info{font-size:12px;color:#6c757d;text-align:center}.fv-image-selector-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1019
1175
  }], ctorParameters: () => [{ type: i1$1.DomSanitizer }], propDecorators: { label: [{
1020
1176
  type: Input
1021
1177
  }], placeholder: [{
@@ -1078,7 +1234,7 @@ class FvRichTextEditorComponent {
1078
1234
  validateValue(value) {
1079
1235
  if (!this.schema)
1080
1236
  return;
1081
- const result = Validator$1.validate(value, this.schema);
1237
+ const result = Validator.validate(value, this.schema);
1082
1238
  this.errorMessage = result.errorKey;
1083
1239
  if (!result.isValid && result.errorKey) {
1084
1240
  this.control.setErrors({ [result.errorKey]: true });
@@ -1161,11 +1317,11 @@ class FvRichTextEditorComponent {
1161
1317
  return text.trim() ? text.trim().split(/\s+/).length : 0;
1162
1318
  }
1163
1319
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvRichTextEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1164
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvRichTextEditorComponent, isStandalone: true, selector: "fv-rich-text-editor", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", minHeight: "minHeight", showToolbar: "showToolbar" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true }], ngImport: i0, template: "<div class=\"fv-rich-text-editor-container\">\r\n <label *ngIf=\"label\" class=\"fv-rich-text-editor-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div *ngIf=\"showToolbar && !disabled && !readonly\" class=\"fv-rich-text-toolbar\">\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('**', '**')\" title=\"Bold\">\r\n <strong>B</strong>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('*', '*')\" title=\"Italic\">\r\n <em>I</em>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('__', '__')\" title=\"Underline\">\r\n <u>U</u>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('~~', '~~')\" title=\"Strikethrough\">\r\n <s>S</s>\r\n </button>\r\n\r\n <div class=\"fv-toolbar-divider\"></div>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"handleBulletList()\" title=\"Bullet List\">\r\n \u2022 List\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"handleNumberedList()\" title=\"Numbered List\">\r\n 1. List\r\n </button>\r\n\r\n <div class=\"fv-toolbar-divider\"></div>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button fv-toolbar-button-danger\" (click)=\"handleClear()\" title=\"Clear\">\r\n Clear\r\n </button>\r\n </div>\r\n\r\n <textarea #editor class=\"fv-rich-text-editor\" [class.fv-rich-text-editor-error]=\"errorMessage\"\r\n [class.fv-rich-text-editor-disabled]=\"disabled\" [class.fv-rich-text-editor-focused]=\"isFocused\"\r\n [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\" [disabled]=\"disabled\"\r\n [style.min-height.px]=\"minHeight\" (blur)=\"onBlur()\" (focus)=\"onFocus()\"></textarea>\r\n\r\n <div class=\"fv-rich-text-footer\">\r\n <div class=\"fv-rich-text-stats\">\r\n {{ getCharacterCount() }} characters \u2022 {{ getWordCount() }} words\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-rich-text-editor-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-rich-text-editor-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-rich-text-editor-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-rich-text-toolbar{display:flex;align-items:center;gap:4px;padding:4px;margin-bottom:8px;border:1px solid #dee2e6;border-radius:4px;background-color:#f8f9fa;flex-wrap:wrap}.fv-toolbar-button{padding:6px 10px;background-color:#fff;border:1px solid #dee2e6;border-radius:4px;font-size:14px;font-weight:500;color:#333;cursor:pointer;transition:background-color .2s,border-color .2s}.fv-toolbar-button:hover{background-color:#e7f3ff;border-color:#007bff}.fv-toolbar-button-danger{color:#dc3545}.fv-toolbar-button-danger:hover{background-color:#ffe0e0;border-color:#dc3545}.fv-toolbar-divider{width:1px;height:24px;background-color:#dee2e6;margin:0 4px}.fv-rich-text-editor{padding:10px;border:1px solid #cccccc;border-radius:4px;font-size:14px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;background-color:#fff;color:#333;resize:vertical;transition:border-color .2s,box-shadow .2s;outline:none}.fv-rich-text-editor::placeholder{color:#999}.fv-rich-text-editor:focus:not(:disabled):not([readonly]){border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-rich-text-editor-error{border-color:#dc3545}.fv-rich-text-editor-disabled,.fv-rich-text-editor[readonly]{background-color:#f5f5f5;opacity:.6;cursor:not-allowed}.fv-rich-text-editor-focused{border-color:#007bff;border-width:2px;padding:9px}.fv-rich-text-footer{display:flex;justify-content:flex-end;margin-top:4px}.fv-rich-text-stats{font-size:12px;color:#6c757d}.fv-rich-text-editor-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1320
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvRichTextEditorComponent, isStandalone: true, selector: "fv-rich-text-editor", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", minHeight: "minHeight", showToolbar: "showToolbar" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true }], ngImport: i0, template: "<div class=\"fv-rich-text-editor-container\">\r\n <label *ngIf=\"label\" class=\"fv-rich-text-editor-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div *ngIf=\"showToolbar && !disabled && !readonly\" class=\"fv-rich-text-toolbar\">\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('**', '**')\" title=\"Bold\">\r\n <strong>B</strong>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('*', '*')\" title=\"Italic\">\r\n <em>I</em>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('__', '__')\" title=\"Underline\">\r\n <u>U</u>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('~~', '~~')\" title=\"Strikethrough\">\r\n <s>S</s>\r\n </button>\r\n\r\n <div class=\"fv-toolbar-divider\"></div>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"handleBulletList()\" title=\"Bullet List\">\r\n \u2022 List\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"handleNumberedList()\" title=\"Numbered List\">\r\n 1. List\r\n </button>\r\n\r\n <div class=\"fv-toolbar-divider\"></div>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button fv-toolbar-button-danger\" (click)=\"handleClear()\" title=\"Clear\">\r\n Clear\r\n </button>\r\n </div>\r\n\r\n <textarea #editor class=\"fv-rich-text-editor\" [class.fv-rich-text-editor-error]=\"errorMessage\"\r\n [class.fv-rich-text-editor-disabled]=\"disabled\" [class.fv-rich-text-editor-focused]=\"isFocused\"\r\n [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\" [disabled]=\"disabled\"\r\n [style.min-height.px]=\"minHeight\" (blur)=\"onBlur()\" (focus)=\"onFocus()\"></textarea>\r\n\r\n <div class=\"fv-rich-text-footer\">\r\n <div class=\"fv-rich-text-stats\">\r\n {{ getCharacterCount() }} characters \u2022 {{ getWordCount() }} words\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-rich-text-editor-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-rich-text-editor-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-rich-text-editor-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-rich-text-toolbar{display:flex;align-items:center;gap:4px;padding:4px;margin-bottom:8px;border:1px solid #dee2e6;border-radius:8px;background-color:#f8f9fa;flex-wrap:wrap}.fv-toolbar-button{padding:6px 10px;background-color:#fff;border:1px solid #dee2e6;border-radius:8px;font-size:14px;font-weight:500;color:#1f2b41;cursor:pointer;transition:background-color .2s,border-color .2s}.fv-toolbar-button:hover{background-color:#e7f3ff;border-color:#3498db}.fv-toolbar-button-danger{color:#e74c3c}.fv-toolbar-button-danger:hover{background-color:#ffe0e0;border-color:#e74c3c}.fv-toolbar-divider{width:1px;height:24px;background-color:#dee2e6;margin:0 4px}.fv-rich-text-editor{padding:10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;font-family:Poppins,sans-serif;background-color:#fff;color:#1f2b41;resize:vertical;transition:border-color .2s,box-shadow .2s;outline:none;box-sizing:border-box;width:100%}.fv-rich-text-editor::placeholder{color:#999}.fv-rich-text-editor:focus:not(:disabled):not([readonly]){border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-rich-text-editor-error{border-color:#e74c3c}.fv-rich-text-editor-disabled,.fv-rich-text-editor[readonly]{background-color:#ecf0f1;opacity:.6;cursor:not-allowed}.fv-rich-text-editor-focused{border-color:#3498db;border-width:1px}.fv-rich-text-footer{display:flex;justify-content:flex-end;margin-top:4px}.fv-rich-text-stats{font-size:12px;color:#6c757d}.fv-rich-text-editor-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1165
1321
  }
1166
1322
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvRichTextEditorComponent, decorators: [{
1167
1323
  type: Component,
1168
- args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-rich-text-editor', template: "<div class=\"fv-rich-text-editor-container\">\r\n <label *ngIf=\"label\" class=\"fv-rich-text-editor-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div *ngIf=\"showToolbar && !disabled && !readonly\" class=\"fv-rich-text-toolbar\">\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('**', '**')\" title=\"Bold\">\r\n <strong>B</strong>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('*', '*')\" title=\"Italic\">\r\n <em>I</em>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('__', '__')\" title=\"Underline\">\r\n <u>U</u>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('~~', '~~')\" title=\"Strikethrough\">\r\n <s>S</s>\r\n </button>\r\n\r\n <div class=\"fv-toolbar-divider\"></div>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"handleBulletList()\" title=\"Bullet List\">\r\n \u2022 List\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"handleNumberedList()\" title=\"Numbered List\">\r\n 1. List\r\n </button>\r\n\r\n <div class=\"fv-toolbar-divider\"></div>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button fv-toolbar-button-danger\" (click)=\"handleClear()\" title=\"Clear\">\r\n Clear\r\n </button>\r\n </div>\r\n\r\n <textarea #editor class=\"fv-rich-text-editor\" [class.fv-rich-text-editor-error]=\"errorMessage\"\r\n [class.fv-rich-text-editor-disabled]=\"disabled\" [class.fv-rich-text-editor-focused]=\"isFocused\"\r\n [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\" [disabled]=\"disabled\"\r\n [style.min-height.px]=\"minHeight\" (blur)=\"onBlur()\" (focus)=\"onFocus()\"></textarea>\r\n\r\n <div class=\"fv-rich-text-footer\">\r\n <div class=\"fv-rich-text-stats\">\r\n {{ getCharacterCount() }} characters \u2022 {{ getWordCount() }} words\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-rich-text-editor-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-rich-text-editor-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-rich-text-editor-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-rich-text-toolbar{display:flex;align-items:center;gap:4px;padding:4px;margin-bottom:8px;border:1px solid #dee2e6;border-radius:4px;background-color:#f8f9fa;flex-wrap:wrap}.fv-toolbar-button{padding:6px 10px;background-color:#fff;border:1px solid #dee2e6;border-radius:4px;font-size:14px;font-weight:500;color:#333;cursor:pointer;transition:background-color .2s,border-color .2s}.fv-toolbar-button:hover{background-color:#e7f3ff;border-color:#007bff}.fv-toolbar-button-danger{color:#dc3545}.fv-toolbar-button-danger:hover{background-color:#ffe0e0;border-color:#dc3545}.fv-toolbar-divider{width:1px;height:24px;background-color:#dee2e6;margin:0 4px}.fv-rich-text-editor{padding:10px;border:1px solid #cccccc;border-radius:4px;font-size:14px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;background-color:#fff;color:#333;resize:vertical;transition:border-color .2s,box-shadow .2s;outline:none}.fv-rich-text-editor::placeholder{color:#999}.fv-rich-text-editor:focus:not(:disabled):not([readonly]){border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-rich-text-editor-error{border-color:#dc3545}.fv-rich-text-editor-disabled,.fv-rich-text-editor[readonly]{background-color:#f5f5f5;opacity:.6;cursor:not-allowed}.fv-rich-text-editor-focused{border-color:#007bff;border-width:2px;padding:9px}.fv-rich-text-footer{display:flex;justify-content:flex-end;margin-top:4px}.fv-rich-text-stats{font-size:12px;color:#6c757d}.fv-rich-text-editor-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
1324
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-rich-text-editor', template: "<div class=\"fv-rich-text-editor-container\">\r\n <label *ngIf=\"label\" class=\"fv-rich-text-editor-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <div *ngIf=\"showToolbar && !disabled && !readonly\" class=\"fv-rich-text-toolbar\">\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('**', '**')\" title=\"Bold\">\r\n <strong>B</strong>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('*', '*')\" title=\"Italic\">\r\n <em>I</em>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('__', '__')\" title=\"Underline\">\r\n <u>U</u>\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"insertText('~~', '~~')\" title=\"Strikethrough\">\r\n <s>S</s>\r\n </button>\r\n\r\n <div class=\"fv-toolbar-divider\"></div>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"handleBulletList()\" title=\"Bullet List\">\r\n \u2022 List\r\n </button>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button\" (click)=\"handleNumberedList()\" title=\"Numbered List\">\r\n 1. List\r\n </button>\r\n\r\n <div class=\"fv-toolbar-divider\"></div>\r\n\r\n <button type=\"button\" class=\"fv-toolbar-button fv-toolbar-button-danger\" (click)=\"handleClear()\" title=\"Clear\">\r\n Clear\r\n </button>\r\n </div>\r\n\r\n <textarea #editor class=\"fv-rich-text-editor\" [class.fv-rich-text-editor-error]=\"errorMessage\"\r\n [class.fv-rich-text-editor-disabled]=\"disabled\" [class.fv-rich-text-editor-focused]=\"isFocused\"\r\n [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\" [disabled]=\"disabled\"\r\n [style.min-height.px]=\"minHeight\" (blur)=\"onBlur()\" (focus)=\"onFocus()\"></textarea>\r\n\r\n <div class=\"fv-rich-text-footer\">\r\n <div class=\"fv-rich-text-stats\">\r\n {{ getCharacterCount() }} characters \u2022 {{ getWordCount() }} words\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-rich-text-editor-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-rich-text-editor-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-rich-text-editor-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px;display:block}.required-asterisk{color:#e74c3c;font-weight:700}.fv-rich-text-toolbar{display:flex;align-items:center;gap:4px;padding:4px;margin-bottom:8px;border:1px solid #dee2e6;border-radius:8px;background-color:#f8f9fa;flex-wrap:wrap}.fv-toolbar-button{padding:6px 10px;background-color:#fff;border:1px solid #dee2e6;border-radius:8px;font-size:14px;font-weight:500;color:#1f2b41;cursor:pointer;transition:background-color .2s,border-color .2s}.fv-toolbar-button:hover{background-color:#e7f3ff;border-color:#3498db}.fv-toolbar-button-danger{color:#e74c3c}.fv-toolbar-button-danger:hover{background-color:#ffe0e0;border-color:#e74c3c}.fv-toolbar-divider{width:1px;height:24px;background-color:#dee2e6;margin:0 4px}.fv-rich-text-editor{padding:10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;font-family:Poppins,sans-serif;background-color:#fff;color:#1f2b41;resize:vertical;transition:border-color .2s,box-shadow .2s;outline:none;box-sizing:border-box;width:100%}.fv-rich-text-editor::placeholder{color:#999}.fv-rich-text-editor:focus:not(:disabled):not([readonly]){border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-rich-text-editor-error{border-color:#e74c3c}.fv-rich-text-editor-disabled,.fv-rich-text-editor[readonly]{background-color:#ecf0f1;opacity:.6;cursor:not-allowed}.fv-rich-text-editor-focused{border-color:#3498db;border-width:1px}.fv-rich-text-footer{display:flex;justify-content:flex-end;margin-top:4px}.fv-rich-text-stats{font-size:12px;color:#6c757d}.fv-rich-text-editor-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1169
1325
  }], propDecorators: { label: [{
1170
1326
  type: Input
1171
1327
  }], placeholder: [{
@@ -1198,31 +1354,21 @@ class FvNameCodeComponent {
1198
1354
  placeholder = '';
1199
1355
  options = [];
1200
1356
  schema;
1201
- control; // Alternative to formControlName
1357
+ control;
1202
1358
  disabled = false;
1203
1359
  selectionChange = new EventEmitter();
1204
1360
  searchControl = new FormControl('');
1205
1361
  filteredOptions = [];
1206
1362
  isOpen = false;
1207
- // Implementation of ControlValueAccessor
1363
+ highlightedIndex = -1;
1208
1364
  onChange = () => { };
1209
1365
  onTouched = () => { };
1210
1366
  value = null;
1211
1367
  ngOnInit() {
1212
1368
  this.filteredOptions = this.options;
1213
- // Setup search filter
1214
1369
  this.searchControl.valueChanges.subscribe(term => {
1215
1370
  this.filterOptions(term || '');
1216
- if (!term && this.value) {
1217
- // If user clears search but had a value, we might want to keep the value or clear it?
1218
- // Usually search box is separate from value display.
1219
- // But here the input acts as both display and search.
1220
- // If user types, value is technically unset until selection?
1221
- // Let's assume typing clears the current selection if it doesn't match?
1222
- // For now, simple behavior: typing filters list. Selection sets value and display text.
1223
- }
1224
1371
  });
1225
- // If control is passed directly
1226
1372
  if (this.control) {
1227
1373
  if (this.control.value) {
1228
1374
  this.writeValue(this.control.value);
@@ -1230,7 +1376,6 @@ class FvNameCodeComponent {
1230
1376
  this.control.valueChanges.subscribe(val => {
1231
1377
  this.writeValue(val);
1232
1378
  });
1233
- // Sync disabled state
1234
1379
  if (this.control.disabled !== this.disabled) {
1235
1380
  this.setDisabledState(this.control.disabled);
1236
1381
  }
@@ -1249,6 +1394,7 @@ class FvNameCodeComponent {
1249
1394
  if (!this.disabled) {
1250
1395
  this.isOpen = true;
1251
1396
  this.filterOptions(this.searchControl.value || '');
1397
+ this.highlightedIndex = this.filteredOptions.length === 1 ? 0 : -1;
1252
1398
  }
1253
1399
  }
1254
1400
  onBlur() {
@@ -1256,14 +1402,12 @@ class FvNameCodeComponent {
1256
1402
  }
1257
1403
  closeDropdown() {
1258
1404
  this.isOpen = false;
1259
- // Restore display text if not selected?
1405
+ this.highlightedIndex = -1;
1260
1406
  const selectedOption = this.options.find(o => o.value === this.value);
1261
1407
  if (selectedOption) {
1262
1408
  this.searchControl.setValue(`${selectedOption.code} - ${selectedOption.name}`, { emitEvent: false });
1263
1409
  }
1264
1410
  else {
1265
- // If no valid value, clear text? or keep partial text?
1266
- // Usually better to clear if no selection made
1267
1411
  if (!this.value) {
1268
1412
  this.searchControl.setValue('', { emitEvent: false });
1269
1413
  }
@@ -1271,11 +1415,14 @@ class FvNameCodeComponent {
1271
1415
  this.onTouched();
1272
1416
  }
1273
1417
  selectOption(option) {
1418
+ if (!option)
1419
+ return;
1274
1420
  this.value = option.value;
1275
1421
  this.onChange(this.value);
1276
1422
  this.searchControl.setValue(`${option.code} - ${option.name}`, { emitEvent: false });
1277
1423
  this.selectionChange.emit(this.value);
1278
1424
  this.isOpen = false;
1425
+ this.highlightedIndex = -1;
1279
1426
  }
1280
1427
  writeValue(value) {
1281
1428
  this.value = value;
@@ -1315,18 +1462,12 @@ class FvNameCodeComponent {
1315
1462
  if (!this.control || !this.control.errors || !this.schema)
1316
1463
  return '';
1317
1464
  for (const errorKey of this.schema.errorPriority) {
1318
- if (this.control.hasError(errorKey)) { // This matches how typical validators set errors (e.g. required: true)
1319
- // However, our validation engine might set explicit keys.
1320
- // Standard angular validators use 'required', 'minlength', etc.
1321
- // Our schema maps 'required' -> 'ERR_REQUIRED'.
1322
- // We need to fetch the message based on rules.
1323
- // For simplicity in this demo, return generic or mapped string.
1324
- const rule = this.schema.rules.find(r => r.name === (errorKey === 'required' ? 'required' : errorKey)); // simplified logic
1465
+ if (this.control.hasError(errorKey)) {
1466
+ const rule = this.schema.rules.find(r => r.name === (errorKey === 'required' ? 'required' : errorKey));
1325
1467
  if (rule)
1326
- return this.getReadableError(rule.errorKey);
1468
+ return this.getReadableError(rule.errorKey || '');
1327
1469
  }
1328
1470
  }
1329
- // Fallback for standard angular errors
1330
1471
  if (this.control.hasError('required'))
1331
1472
  return 'This field is required';
1332
1473
  return 'Invalid value';
@@ -1335,27 +1476,74 @@ class FvNameCodeComponent {
1335
1476
  const map = {
1336
1477
  'ERR_REQUIRED': 'This field is required',
1337
1478
  'ERR_MIN_LENGTH': 'Value is too short',
1338
- // Add others as needed
1339
1479
  };
1340
1480
  return map[key] || 'Invalid value';
1341
1481
  }
1342
1482
  onClickOutside(event) {
1343
- const element = event.target;
1344
- // Check if click is inside component
1345
1483
  const clickedInside = event.target.closest('.fv-name-code-container');
1346
1484
  if (!clickedInside) {
1347
1485
  this.closeDropdown();
1348
1486
  }
1349
1487
  }
1488
+ onKeyDown(event) {
1489
+ if (!this.isOpen && (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter')) {
1490
+ this.openDropdown();
1491
+ event.preventDefault();
1492
+ return;
1493
+ }
1494
+ if (!this.isOpen)
1495
+ return;
1496
+ switch (event.key) {
1497
+ case 'ArrowDown':
1498
+ event.preventDefault();
1499
+ this.highlightedIndex = (this.highlightedIndex + 1) % this.filteredOptions.length;
1500
+ this.scrollToHighlighted();
1501
+ break;
1502
+ case 'ArrowUp':
1503
+ event.preventDefault();
1504
+ this.highlightedIndex = (this.highlightedIndex - 1 + this.filteredOptions.length) % this.filteredOptions.length;
1505
+ this.scrollToHighlighted();
1506
+ break;
1507
+ case 'Enter':
1508
+ event.preventDefault();
1509
+ if (this.filteredOptions.length === 1) {
1510
+ this.selectOption(this.filteredOptions[0]);
1511
+ }
1512
+ else if (this.highlightedIndex >= 0 && this.highlightedIndex < this.filteredOptions.length) {
1513
+ this.selectOption(this.filteredOptions[this.highlightedIndex]);
1514
+ }
1515
+ break;
1516
+ case 'Escape':
1517
+ this.closeDropdown();
1518
+ break;
1519
+ case 'Tab':
1520
+ this.closeDropdown();
1521
+ break;
1522
+ }
1523
+ }
1524
+ scrollToHighlighted() {
1525
+ const list = document.querySelector('.dropdown-list');
1526
+ const item = document.querySelectorAll('.dropdown-item')[this.highlightedIndex];
1527
+ if (list && item) {
1528
+ const listRect = list.getBoundingClientRect();
1529
+ const itemRect = item.getBoundingClientRect();
1530
+ if (itemRect.bottom > listRect.bottom) {
1531
+ list.scrollTop += (itemRect.bottom - listRect.bottom);
1532
+ }
1533
+ else if (itemRect.top < listRect.top) {
1534
+ list.scrollTop -= (listRect.top - itemRect.top);
1535
+ }
1536
+ }
1537
+ }
1350
1538
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvNameCodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1351
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvNameCodeComponent, isStandalone: true, selector: "fv-name-code", inputs: { label: "label", placeholder: "placeholder", options: "options", schema: "schema", control: "control", disabled: "disabled" }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, providers: [
1539
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvNameCodeComponent, isStandalone: true, selector: "fv-name-code", inputs: { label: "label", placeholder: "placeholder", options: "options", schema: "schema", control: "control", disabled: "disabled" }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "document:click": "onClickOutside($event)", "keydown": "onKeyDown($event)" } }, providers: [
1352
1540
  {
1353
1541
  provide: NG_VALUE_ACCESSOR,
1354
1542
  useExisting: forwardRef(() => FvNameCodeComponent),
1355
1543
  multi: true
1356
1544
  }
1357
1545
  ], ngImport: i0, template: `
1358
- <div class="fv-name-code-container" (clickOutside)="closeDropdown()">
1546
+ <div class="fv-name-code-container">
1359
1547
  <label *ngIf="label" class="fv-label">
1360
1548
  {{ label }}
1361
1549
  <span *ngIf="isRequired()" class="required-asterisk">*</span>
@@ -1370,14 +1558,14 @@ class FvNameCodeComponent {
1370
1558
  (focus)="openDropdown()"
1371
1559
  (blur)="onBlur()"
1372
1560
  [class.error]="isInvalid()"
1373
- [attr.disabled]="disabled ? true : null"
1374
1561
  />
1375
1562
  </div>
1376
1563
 
1377
1564
  <div class="dropdown-list" *ngIf="isOpen && !disabled">
1378
1565
  <div
1379
1566
  class="dropdown-item"
1380
- *ngFor="let option of filteredOptions"
1567
+ *ngFor="let option of filteredOptions; let i = index"
1568
+ [class.highlighted]="i === highlightedIndex"
1381
1569
  (click)="selectOption(option)"
1382
1570
  >
1383
1571
  <span class="code">{{ option.code }}</span>
@@ -1392,12 +1580,12 @@ class FvNameCodeComponent {
1392
1580
  {{ getErrorMessage() }}
1393
1581
  </div>
1394
1582
  </div>
1395
- `, isInline: true, styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-name-code-container{position:relative;width:100%;margin-bottom:15px}.fv-label{display:block;font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required-asterisk{color:#e74c3c;margin-left:2px}.search-box-wrapper{position:relative;display:flex;align-items:center}.fv-input{width:100%;padding:10px 12px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;color:#303030;outline:none;transition:all .2s;background-color:#fff}.fv-input:focus{border-color:#006aff;box-shadow:0 0 0 2px #006aff1a}.fv-input.error{border-color:#e74c3c}.fv-input:disabled{background-color:#f5f5f5;cursor:not-allowed}.dropdown-list{position:absolute;top:100%;left:0;right:0;background:#fff;border:1px solid #ddd;border-radius:8px;margin-top:4px;max-height:200px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px #0000001a}.dropdown-item{padding:10px 12px;display:flex;justify-content:space-between;cursor:pointer;border-bottom:1px solid #f0f0f0}.dropdown-item:last-child{border-bottom:none}.dropdown-item:hover{background-color:#f9f9f9}.code{color:#0056b3;font-weight:600;font-size:14px}.name{color:#333;font-size:14px}.no-results{padding:10px;color:#999;text-align:center;font-size:13px}.error-message{color:#e74c3c;font-size:12px;margin-top:4px;display:flex;align-items:center;gap:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1583
+ `, isInline: true, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-name-code-container{position:relative;width:100%;margin-bottom:0}.fv-label{display:block;font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required-asterisk{color:#e74c3c;margin-left:2px}.search-box-wrapper{position:relative;display:flex;align-items:center}.fv-input{width:100%;padding:5px 10px;height:34px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;color:#1f2b41;outline:none;transition:all .2s;background-color:#fff;box-sizing:border-box;font-family:Poppins,sans-serif;min-width:0}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input.error{border-color:#e74c3c}.fv-input:disabled{background-color:#f5f5f5;cursor:not-allowed}.dropdown-list{position:absolute;top:100%;left:0;min-width:100%;width:max-content;max-width:300px;background:#fff;border:1px solid #ddd;border-radius:8px;margin-top:4px;max-height:200px;overflow-y:auto;overflow-x:hidden;z-index:1000;box-shadow:0 4px 6px #0000001a}.dropdown-item{padding:10px 12px;display:flex;justify-content:space-between;align-items:center;cursor:pointer;border-bottom:1px solid #f0f0f0;gap:12px}.dropdown-item:last-child{border-bottom:none}.dropdown-item:hover,.dropdown-item.highlighted{background-color:#f0f7ff}.code{color:#0056b3;font-weight:600;font-size:14px;white-space:nowrap}.name{color:#333;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:right}.no-results{padding:10px;color:#999;text-align:center;font-size:13px}.error-message{color:#e74c3c;font-size:12px;margin-top:4px;display:flex;align-items:center;gap:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1396
1584
  }
1397
1585
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvNameCodeComponent, decorators: [{
1398
1586
  type: Component,
1399
1587
  args: [{ selector: 'fv-name-code', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: `
1400
- <div class="fv-name-code-container" (clickOutside)="closeDropdown()">
1588
+ <div class="fv-name-code-container">
1401
1589
  <label *ngIf="label" class="fv-label">
1402
1590
  {{ label }}
1403
1591
  <span *ngIf="isRequired()" class="required-asterisk">*</span>
@@ -1412,14 +1600,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1412
1600
  (focus)="openDropdown()"
1413
1601
  (blur)="onBlur()"
1414
1602
  [class.error]="isInvalid()"
1415
- [attr.disabled]="disabled ? true : null"
1416
1603
  />
1417
1604
  </div>
1418
1605
 
1419
1606
  <div class="dropdown-list" *ngIf="isOpen && !disabled">
1420
1607
  <div
1421
1608
  class="dropdown-item"
1422
- *ngFor="let option of filteredOptions"
1609
+ *ngFor="let option of filteredOptions; let i = index"
1610
+ [class.highlighted]="i === highlightedIndex"
1423
1611
  (click)="selectOption(option)"
1424
1612
  >
1425
1613
  <span class="code">{{ option.code }}</span>
@@ -1440,7 +1628,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1440
1628
  useExisting: forwardRef(() => FvNameCodeComponent),
1441
1629
  multi: true
1442
1630
  }
1443
- ], styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-name-code-container{position:relative;width:100%;margin-bottom:15px}.fv-label{display:block;font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required-asterisk{color:#e74c3c;margin-left:2px}.search-box-wrapper{position:relative;display:flex;align-items:center}.fv-input{width:100%;padding:10px 12px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;color:#303030;outline:none;transition:all .2s;background-color:#fff}.fv-input:focus{border-color:#006aff;box-shadow:0 0 0 2px #006aff1a}.fv-input.error{border-color:#e74c3c}.fv-input:disabled{background-color:#f5f5f5;cursor:not-allowed}.dropdown-list{position:absolute;top:100%;left:0;right:0;background:#fff;border:1px solid #ddd;border-radius:8px;margin-top:4px;max-height:200px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px #0000001a}.dropdown-item{padding:10px 12px;display:flex;justify-content:space-between;cursor:pointer;border-bottom:1px solid #f0f0f0}.dropdown-item:last-child{border-bottom:none}.dropdown-item:hover{background-color:#f9f9f9}.code{color:#0056b3;font-weight:600;font-size:14px}.name{color:#333;font-size:14px}.no-results{padding:10px;color:#999;text-align:center;font-size:13px}.error-message{color:#e74c3c;font-size:12px;margin-top:4px;display:flex;align-items:center;gap:4px}\n"] }]
1631
+ ], styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-name-code-container{position:relative;width:100%;margin-bottom:0}.fv-label{display:block;font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required-asterisk{color:#e74c3c;margin-left:2px}.search-box-wrapper{position:relative;display:flex;align-items:center}.fv-input{width:100%;padding:5px 10px;height:34px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;color:#1f2b41;outline:none;transition:all .2s;background-color:#fff;box-sizing:border-box;font-family:Poppins,sans-serif;min-width:0}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input.error{border-color:#e74c3c}.fv-input:disabled{background-color:#f5f5f5;cursor:not-allowed}.dropdown-list{position:absolute;top:100%;left:0;min-width:100%;width:max-content;max-width:300px;background:#fff;border:1px solid #ddd;border-radius:8px;margin-top:4px;max-height:200px;overflow-y:auto;overflow-x:hidden;z-index:1000;box-shadow:0 4px 6px #0000001a}.dropdown-item{padding:10px 12px;display:flex;justify-content:space-between;align-items:center;cursor:pointer;border-bottom:1px solid #f0f0f0;gap:12px}.dropdown-item:last-child{border-bottom:none}.dropdown-item:hover,.dropdown-item.highlighted{background-color:#f0f7ff}.code{color:#0056b3;font-weight:600;font-size:14px;white-space:nowrap}.name{color:#333;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:right}.no-results{padding:10px;color:#999;text-align:center;font-size:13px}.error-message{color:#e74c3c;font-size:12px;margin-top:4px;display:flex;align-items:center;gap:4px}\n"] }]
1444
1632
  }], propDecorators: { label: [{
1445
1633
  type: Input
1446
1634
  }], placeholder: [{
@@ -1458,6 +1646,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1458
1646
  }], onClickOutside: [{
1459
1647
  type: HostListener,
1460
1648
  args: ['document:click', ['$event']]
1649
+ }], onKeyDown: [{
1650
+ type: HostListener,
1651
+ args: ['keydown', ['$event']]
1461
1652
  }] } });
1462
1653
 
1463
1654
  class FvPhoneFieldComponent {
@@ -1502,6 +1693,16 @@ class FvPhoneFieldComponent {
1502
1693
  ngOnDestroy() {
1503
1694
  this.subscription?.unsubscribe();
1504
1695
  }
1696
+ ngOnChanges(changes) {
1697
+ if (changes['disabled'] && this.control) {
1698
+ if (this.disabled) {
1699
+ this.control.disable({ emitEvent: false });
1700
+ }
1701
+ else {
1702
+ this.control.enable({ emitEvent: false });
1703
+ }
1704
+ }
1705
+ }
1505
1706
  onInput(event) {
1506
1707
  const input = event.target;
1507
1708
  let value = input.value;
@@ -1539,11 +1740,11 @@ class FvPhoneFieldComponent {
1539
1740
  return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false;
1540
1741
  }
1541
1742
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvPhoneFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1542
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvPhoneFieldComponent, isStandalone: true, selector: "fv-phone-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-phone-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-phone-input-group\">\r\n <div class=\"fv-select-wrapper\">\r\n <select class=\"fv-country-code-select\" [disabled]=\"disabled\" [(ngModel)]=\"countryCode\">\r\n <option *ngFor=\"let code of countryCodes\" [value]=\"code\">{{code}}</option>\r\n </select>\r\n <i class=\"material-icons fv-select-arrow\">arrow_drop_down</i>\r\n </div>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" (blur)=\"onBlur()\"\r\n (focus)=\"onFocus()\" placeholder=\"10 digit mobile number\" class=\"fv-input fv-phone-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n </div>\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ errorMessage }}\r\n </span>\r\n</div>", styles: [".fv-phone-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-phone-input-group{display:flex;align-items:center}.fv-country-code-select{padding:10px 24px 10px 8px;border:1px solid #cccccc;border-radius:4px 0 0 4px;background-color:#f8f9fa;border-right:none;outline:none;cursor:pointer;font-size:14px;color:#333;height:42px;width:60px;box-sizing:border-box;appearance:none;-webkit-appearance:none;-moz-appearance:none}.fv-select-wrapper{position:relative;display:flex;align-items:center}.fv-select-arrow{position:absolute;right:4px;top:50%;transform:translateY(-50%);pointer-events:none;color:#666;font-size:20px}.fv-phone-input{flex:1;border-radius:0 4px 4px 0!important}.fv-input{padding:10px;border:1px solid #cccccc;border-radius:4px;font-size:14px;outline:none;transition:border-color .2s;width:100%;box-sizing:border-box;height:42px}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
1743
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvPhoneFieldComponent, isStandalone: true, selector: "fv-phone-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-phone-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-phone-input-group\">\r\n <div class=\"fv-select-wrapper\">\r\n <select class=\"fv-country-code-select\" [disabled]=\"disabled\" [(ngModel)]=\"countryCode\">\r\n <option *ngFor=\"let code of countryCodes\" [value]=\"code\">{{code}}</option>\r\n </select>\r\n <i class=\"material-icons fv-select-arrow\">arrow_drop_down</i>\r\n </div>\r\n <input type=\"text\" [formControl]=\"control\" (input)=\"onInput($event)\" (blur)=\"onBlur()\" (focus)=\"onFocus()\"\r\n placeholder=\"10 digit mobile number\" class=\"fv-input fv-phone-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n </div>\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ errorMessage }}\r\n </span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.material-icons{font-family:Material Icons!important}.fv-phone-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-phone-input-group{display:flex;align-items:center}.fv-country-code-select{padding:5px 24px 5px 8px;border:1px solid #8CBBA8;border-radius:8px 0 0 8px;background-color:#f8f9fa;border-right:none;outline:none;cursor:pointer;font-size:14px;font-weight:400;color:#1f2b41;height:34px;width:60px;box-sizing:border-box;appearance:none;-webkit-appearance:none;-moz-appearance:none}.fv-select-wrapper{position:relative;display:flex;align-items:center}.fv-select-arrow{position:absolute;right:4px;top:50%;transform:translateY(-50%);pointer-events:none;color:#666;font-size:20px}.fv-phone-input{flex:1;border-radius:0 8px 8px 0!important}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;transition:border-color .2s;width:100%;box-sizing:border-box;height:34px;background-color:#fff;color:#1f2b41;min-width:0}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
1543
1744
  }
1544
1745
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvPhoneFieldComponent, decorators: [{
1545
1746
  type: Component,
1546
- args: [{ selector: 'fv-phone-field', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule], template: "<div class=\"fv-phone-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-phone-input-group\">\r\n <div class=\"fv-select-wrapper\">\r\n <select class=\"fv-country-code-select\" [disabled]=\"disabled\" [(ngModel)]=\"countryCode\">\r\n <option *ngFor=\"let code of countryCodes\" [value]=\"code\">{{code}}</option>\r\n </select>\r\n <i class=\"material-icons fv-select-arrow\">arrow_drop_down</i>\r\n </div>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" (blur)=\"onBlur()\"\r\n (focus)=\"onFocus()\" placeholder=\"10 digit mobile number\" class=\"fv-input fv-phone-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n </div>\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ errorMessage }}\r\n </span>\r\n</div>", styles: [".fv-phone-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-phone-input-group{display:flex;align-items:center}.fv-country-code-select{padding:10px 24px 10px 8px;border:1px solid #cccccc;border-radius:4px 0 0 4px;background-color:#f8f9fa;border-right:none;outline:none;cursor:pointer;font-size:14px;color:#333;height:42px;width:60px;box-sizing:border-box;appearance:none;-webkit-appearance:none;-moz-appearance:none}.fv-select-wrapper{position:relative;display:flex;align-items:center}.fv-select-arrow{position:absolute;right:4px;top:50%;transform:translateY(-50%);pointer-events:none;color:#666;font-size:20px}.fv-phone-input{flex:1;border-radius:0 4px 4px 0!important}.fv-input{padding:10px;border:1px solid #cccccc;border-radius:4px;font-size:14px;outline:none;transition:border-color .2s;width:100%;box-sizing:border-box;height:42px}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
1747
+ args: [{ selector: 'fv-phone-field', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule], template: "<div class=\"fv-phone-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-phone-input-group\">\r\n <div class=\"fv-select-wrapper\">\r\n <select class=\"fv-country-code-select\" [disabled]=\"disabled\" [(ngModel)]=\"countryCode\">\r\n <option *ngFor=\"let code of countryCodes\" [value]=\"code\">{{code}}</option>\r\n </select>\r\n <i class=\"material-icons fv-select-arrow\">arrow_drop_down</i>\r\n </div>\r\n <input type=\"text\" [formControl]=\"control\" (input)=\"onInput($event)\" (blur)=\"onBlur()\" (focus)=\"onFocus()\"\r\n placeholder=\"10 digit mobile number\" class=\"fv-input fv-phone-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n </div>\r\n\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ errorMessage }}\r\n </span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.material-icons{font-family:Material Icons!important}.fv-phone-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-phone-input-group{display:flex;align-items:center}.fv-country-code-select{padding:5px 24px 5px 8px;border:1px solid #8CBBA8;border-radius:8px 0 0 8px;background-color:#f8f9fa;border-right:none;outline:none;cursor:pointer;font-size:14px;font-weight:400;color:#1f2b41;height:34px;width:60px;box-sizing:border-box;appearance:none;-webkit-appearance:none;-moz-appearance:none}.fv-select-wrapper{position:relative;display:flex;align-items:center}.fv-select-arrow{position:absolute;right:4px;top:50%;transform:translateY(-50%);pointer-events:none;color:#666;font-size:20px}.fv-phone-input{flex:1;border-radius:0 8px 8px 0!important}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;transition:border-color .2s;width:100%;box-sizing:border-box;height:34px;background-color:#fff;color:#1f2b41;min-width:0}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1547
1748
  }], propDecorators: { label: [{
1548
1749
  type: Input
1549
1750
  }], control: [{
@@ -1573,6 +1774,16 @@ class FvUanFieldComponent {
1573
1774
  this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1574
1775
  }
1575
1776
  ngOnDestroy() { this.subscription?.unsubscribe(); }
1777
+ ngOnChanges(changes) {
1778
+ if (changes['disabled'] && this.control) {
1779
+ if (this.disabled) {
1780
+ this.control.disable({ emitEvent: false });
1781
+ }
1782
+ else {
1783
+ this.control.enable({ emitEvent: false });
1784
+ }
1785
+ }
1786
+ }
1576
1787
  onInput(event) {
1577
1788
  const input = event.target;
1578
1789
  let value = input.value;
@@ -1597,11 +1808,11 @@ class FvUanFieldComponent {
1597
1808
  return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false;
1598
1809
  }
1599
1810
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvUanFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1600
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvUanFieldComponent, isStandalone: true, selector: "fv-uan-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"12 digit UAN\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1811
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvUanFieldComponent, isStandalone: true, selector: "fv-uan-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" (input)=\"onInput($event)\" placeholder=\"12 digit UAN\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1601
1812
  }
1602
1813
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvUanFieldComponent, decorators: [{
1603
1814
  type: Component,
1604
- args: [{ selector: 'fv-uan-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"12 digit UAN\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
1815
+ args: [{ selector: 'fv-uan-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" (input)=\"onInput($event)\" placeholder=\"12 digit UAN\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1605
1816
  }], propDecorators: { label: [{
1606
1817
  type: Input
1607
1818
  }], control: [{
@@ -1626,9 +1837,41 @@ class FvPfFieldComponent {
1626
1837
  errorMessage = null;
1627
1838
  subscription;
1628
1839
  ngOnInit() {
1629
- if (!this.control)
1840
+ if (!this.control) {
1841
+ console.error('FvPfField: control is required');
1630
1842
  return;
1843
+ }
1844
+ // Default PF Schema
1845
+ if (!this.schema) {
1846
+ this.schema = {
1847
+ controlType: 'PfField',
1848
+ errorPriority: ['required', 'regex'],
1849
+ rules: [
1850
+ {
1851
+ name: 'regex',
1852
+ params: {
1853
+ pattern: '^[A-Z]{2}/[A-Z]{3}/[0-9]{7}/[0-9]{3}/[0-9]{7}$'
1854
+ },
1855
+ errorKey: 'ERR_PF_INVALID'
1856
+ }
1857
+ ]
1858
+ };
1859
+ }
1631
1860
  this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1861
+ // Initial validation
1862
+ if (this.control.value) {
1863
+ this.validateValue(this.control.value);
1864
+ }
1865
+ }
1866
+ ngOnChanges(changes) {
1867
+ if (changes['disabled'] && this.control) {
1868
+ if (this.disabled) {
1869
+ this.control.disable({ emitEvent: false });
1870
+ }
1871
+ else {
1872
+ this.control.enable({ emitEvent: false });
1873
+ }
1874
+ }
1632
1875
  }
1633
1876
  ngOnDestroy() { this.subscription?.unsubscribe(); }
1634
1877
  onInput(event) {
@@ -1652,12 +1895,22 @@ class FvPfFieldComponent {
1652
1895
  this.control.setErrors(null);
1653
1896
  }
1654
1897
  isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1898
+ getErrorMessage() {
1899
+ if (!this.errorMessage)
1900
+ return '';
1901
+ const errorMessages = {
1902
+ ERR_REQUIRED: 'PF Number is required',
1903
+ ERR_PF_INVALID: 'Invalid PF Number format (e.g. AA/AAA/0000000/000/0000000)',
1904
+ ERR_REGEX_MISMATCH: 'Invalid PF Number format'
1905
+ };
1906
+ return errorMessages[this.errorMessage] || this.errorMessage;
1907
+ }
1655
1908
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvPfFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1656
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvPfFieldComponent, isStandalone: true, selector: "fv-pf-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" placeholder=\"PF Number\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1909
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvPfFieldComponent, isStandalone: true, selector: "fv-pf-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"AA/AAA/0000000/000/0000000\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage && control.touched\" />\r\n <span *ngIf=\"errorMessage && control.touched\" class=\"fv-error-message\">{{ getErrorMessage() }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1657
1910
  }
1658
1911
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvPfFieldComponent, decorators: [{
1659
1912
  type: Component,
1660
- args: [{ selector: 'fv-pf-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" placeholder=\"PF Number\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
1913
+ args: [{ selector: 'fv-pf-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"AA/AAA/0000000/000/0000000\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage && control.touched\" />\r\n <span *ngIf=\"errorMessage && control.touched\" class=\"fv-error-message\">{{ getErrorMessage() }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1661
1914
  }], propDecorators: { label: [{
1662
1915
  type: Input
1663
1916
  }], control: [{
@@ -1687,6 +1940,16 @@ class FvEsiFieldComponent {
1687
1940
  this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1688
1941
  }
1689
1942
  ngOnDestroy() { this.subscription?.unsubscribe(); }
1943
+ ngOnChanges(changes) {
1944
+ if (changes['disabled'] && this.control) {
1945
+ if (this.disabled) {
1946
+ this.control.disable({ emitEvent: false });
1947
+ }
1948
+ else {
1949
+ this.control.enable({ emitEvent: false });
1950
+ }
1951
+ }
1952
+ }
1690
1953
  onInput(event) {
1691
1954
  const input = event.target;
1692
1955
  let value = input.value;
@@ -1709,11 +1972,11 @@ class FvEsiFieldComponent {
1709
1972
  }
1710
1973
  isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1711
1974
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEsiFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1712
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvEsiFieldComponent, isStandalone: true, selector: "fv-esi-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"17 digit ESI\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1975
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvEsiFieldComponent, isStandalone: true, selector: "fv-esi-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" (input)=\"onInput($event)\" placeholder=\"17 digit ESI\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1713
1976
  }
1714
1977
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEsiFieldComponent, decorators: [{
1715
1978
  type: Component,
1716
- args: [{ selector: 'fv-esi-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"17 digit ESI\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
1979
+ args: [{ selector: 'fv-esi-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" (input)=\"onInput($event)\" placeholder=\"17 digit ESI\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1717
1980
  }], propDecorators: { label: [{
1718
1981
  type: Input
1719
1982
  }], control: [{
@@ -1765,11 +2028,11 @@ class FvIfscFieldComponent {
1765
2028
  }
1766
2029
  isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1767
2030
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvIfscFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1768
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvIfscFieldComponent, isStandalone: true, selector: "fv-ifsc-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" placeholder=\"IFSC Code\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
2031
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvIfscFieldComponent, isStandalone: true, selector: "fv-ifsc-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" placeholder=\"IFSC Code\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1769
2032
  }
1770
2033
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvIfscFieldComponent, decorators: [{
1771
2034
  type: Component,
1772
- args: [{ selector: 'fv-ifsc-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" placeholder=\"IFSC Code\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
2035
+ args: [{ selector: 'fv-ifsc-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" placeholder=\"IFSC Code\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1773
2036
  }], propDecorators: { label: [{
1774
2037
  type: Input
1775
2038
  }], control: [{
@@ -1821,11 +2084,11 @@ class FvMicrFieldComponent {
1821
2084
  }
1822
2085
  isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1823
2086
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvMicrFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1824
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvMicrFieldComponent, isStandalone: true, selector: "fv-micr-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"9 digit MICR\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
2087
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvMicrFieldComponent, isStandalone: true, selector: "fv-micr-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"9 digit MICR\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-micr-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1825
2088
  }
1826
2089
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvMicrFieldComponent, decorators: [{
1827
2090
  type: Component,
1828
- args: [{ selector: 'fv-micr-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"9 digit MICR\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
2091
+ args: [{ selector: 'fv-micr-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\"\r\n placeholder=\"9 digit MICR\" class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-micr-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1829
2092
  }], propDecorators: { label: [{
1830
2093
  type: Input
1831
2094
  }], control: [{
@@ -1855,6 +2118,16 @@ class FvIbanFieldComponent {
1855
2118
  this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1856
2119
  }
1857
2120
  ngOnDestroy() { this.subscription?.unsubscribe(); }
2121
+ ngOnChanges(changes) {
2122
+ if (changes['disabled'] && this.control) {
2123
+ if (this.disabled) {
2124
+ this.control.disable({ emitEvent: false });
2125
+ }
2126
+ else {
2127
+ this.control.enable({ emitEvent: false });
2128
+ }
2129
+ }
2130
+ }
1858
2131
  onInput(event) {
1859
2132
  const input = event.target;
1860
2133
  let value = input.value;
@@ -1877,11 +2150,11 @@ class FvIbanFieldComponent {
1877
2150
  }
1878
2151
  isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1879
2152
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvIbanFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1880
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvIbanFieldComponent, isStandalone: true, selector: "fv-iban-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" placeholder=\"IBAN\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
2153
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvIbanFieldComponent, isStandalone: true, selector: "fv-iban-field", inputs: { label: "label", control: "control", disabled: "disabled", schema: "schema" }, outputs: { blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" (input)=\"onInput($event)\" placeholder=\"IBAN\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-iban-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
1881
2154
  }
1882
2155
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvIbanFieldComponent, decorators: [{
1883
2156
  type: Component,
1884
- args: [{ selector: 'fv-iban-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" [disabled]=\"disabled\" (input)=\"onInput($event)\" placeholder=\"IBAN\"\r\n class=\"fv-input\" [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px}.fv-required-asterisk{color:#dc3545;margin-left:2px}.fv-input{padding:10px;border:1px solid #ccc;border-radius:4px;font-size:14px;outline:none;width:100%;box-sizing:border-box}.fv-input:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
2157
+ args: [{ selector: 'fv-iban-field', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"fv-required-asterisk\">*</span>\r\n </label>\r\n <input type=\"text\" [formControl]=\"control\" (input)=\"onInput($event)\" placeholder=\"IBAN\" class=\"fv-input\"\r\n [class.fv-input-error]=\"errorMessage\" />\r\n <span *ngIf=\"errorMessage\" class=\"fv-error-message\">{{ errorMessage }}</span>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";*{font-family:Poppins,sans-serif}.fv-iban-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.fv-required-asterisk{color:#e74c3c;margin-left:2px}.fv-input{padding:5px 10px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:border-color .2s;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input-error{border-color:#dc3545!important}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c}\n"] }]
1885
2158
  }], propDecorators: { label: [{
1886
2159
  type: Input
1887
2160
  }], control: [{
@@ -1896,76 +2169,303 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1896
2169
  type: Output
1897
2170
  }] } });
1898
2171
 
1899
- // add-update-form.component.ts
1900
- class AddUpdateFormComponent {
1901
- fb;
1902
- hostRef;
1903
- config;
1904
- validationError = new EventEmitter();
1905
- form;
1906
- submitted = false;
1907
- filePreviews = new Map();
1908
- fileNames = new Map();
1909
- valueChangeSubscriptions = [];
1910
- passwordVisibility = new Map();
1911
- searchQueries = new Map();
1912
- constructor(fb, hostRef) {
1913
- this.fb = fb;
1914
- this.hostRef = hostRef;
1915
- }
2172
+ class FvEmailFieldComponent {
2173
+ label = 'Email Address';
2174
+ placeholder = 'e.g. john@example.com';
2175
+ schema;
2176
+ control;
2177
+ disabled = false;
2178
+ readonly = false;
2179
+ valueChange = new EventEmitter();
2180
+ blur = new EventEmitter();
2181
+ focus = new EventEmitter();
2182
+ errorMessage = null;
2183
+ subscription;
1916
2184
  ngOnInit() {
1917
- this.initializeForm();
2185
+ if (!this.control) {
2186
+ console.error('FvEmailField: control is required');
2187
+ return;
2188
+ }
2189
+ // Default email schema if not provided
2190
+ if (!this.schema) {
2191
+ this.schema = {
2192
+ controlType: 'EntryField',
2193
+ errorPriority: ['required', 'regex'],
2194
+ rules: [
2195
+ {
2196
+ name: 'regex',
2197
+ params: {
2198
+ pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
2199
+ },
2200
+ errorKey: 'ERR_EMAIL_INVALID',
2201
+ },
2202
+ ],
2203
+ };
2204
+ }
2205
+ // Subscribe to value changes
2206
+ this.subscription = this.control.valueChanges.subscribe((value) => {
2207
+ this.validateValue(value);
2208
+ this.valueChange.emit(value);
2209
+ });
2210
+ // Validate initial value
2211
+ if (this.control.value) {
2212
+ this.validateValue(this.control.value);
2213
+ }
1918
2214
  }
1919
- ngAfterViewInit() {
1920
- // Lifecycle hook - can be used for datepicker initialization if needed
2215
+ ngOnDestroy() {
2216
+ this.subscription?.unsubscribe();
1921
2217
  }
1922
- getColumnWidth(column) {
1923
- const maxCols = this.config.maxColsPerRow || 5;
1924
- const colSpan = Math.min(column.colSpan || 1, maxCols);
1925
- return `calc(${(colSpan / maxCols) * 100}% - 16px)`;
2218
+ ngOnChanges(changes) {
2219
+ if (changes['disabled'] && this.control) {
2220
+ if (this.disabled) {
2221
+ this.control.disable({ emitEvent: false });
2222
+ }
2223
+ else {
2224
+ this.control.enable({ emitEvent: false });
2225
+ }
2226
+ }
1926
2227
  }
1927
- getControl(name) {
1928
- return this.form.get(name);
2228
+ validateValue(value) {
2229
+ if (!this.schema)
2230
+ return;
2231
+ const result = Validator.validate(value, this.schema);
2232
+ this.errorMessage = result.errorKey;
2233
+ if (!result.isValid && result.errorKey) {
2234
+ this.control.setErrors({ [result.errorKey]: true });
2235
+ }
2236
+ else {
2237
+ this.control.setErrors(null);
2238
+ }
1929
2239
  }
1930
- // 2. HELPER: Convert your FieldValidation[] to the library's ValidationSchema
1931
- getSchema(column) {
1932
- const rules = [];
1933
- const errorPriority = [];
1934
- if (column.validations) {
1935
- column.validations.forEach((v) => {
1936
- switch (v.type) {
1937
- case 'required':
1938
- rules.push({
1939
- name: 'required',
1940
- params: { enabled: true },
1941
- errorKey: 'ERR_REQUIRED',
1942
- });
1943
- errorPriority.push('required');
1944
- break;
1945
- case 'email':
1946
- rules.push({
1947
- name: 'regex',
1948
- params: {
1949
- pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
1950
- },
1951
- errorKey: 'ERR_REGEX_MISMATCH',
1952
- });
1953
- errorPriority.push('regex');
1954
- break;
1955
- case 'minLength':
1956
- rules.push({
1957
- name: 'minLength',
1958
- params: { value: v.value },
1959
- errorKey: 'ERR_MIN_LENGTH',
1960
- });
1961
- errorPriority.push('minLength');
1962
- break;
1963
- case 'maxLength':
1964
- rules.push({
1965
- name: 'maxLength',
1966
- params: { value: v.value },
1967
- errorKey: 'ERR_MAX_LENGTH',
1968
- });
2240
+ onBlur(event) {
2241
+ if (this.control && this.schema) {
2242
+ this.validateValue(this.control.value);
2243
+ }
2244
+ this.blur.emit();
2245
+ }
2246
+ onFocus(event) {
2247
+ this.focus.emit();
2248
+ }
2249
+ isRequired() {
2250
+ return (this.schema?.rules?.some((r) => r.name === 'required' && r.params?.['enabled']) || false);
2251
+ }
2252
+ getErrorMessage() {
2253
+ if (!this.errorMessage)
2254
+ return '';
2255
+ const errorMessages = {
2256
+ ERR_REQUIRED: 'Email is required',
2257
+ ERR_EMAIL_INVALID: 'Invalid email format',
2258
+ ERR_REGEX_MISMATCH: 'Invalid email format',
2259
+ };
2260
+ return errorMessages[this.errorMessage] || this.errorMessage;
2261
+ }
2262
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEmailFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2263
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvEmailFieldComponent, isStandalone: true, selector: "fv-email-field", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-input-wrapper\">\r\n <input type=\"email\" [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\"\r\n (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" class=\"fv-input\"\r\n [class.error]=\"!!errorMessage && control.touched\" />\r\n <span class=\"fv-field-icon\">\r\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z\"></path>\r\n <polyline points=\"22,6 12,13 2,6\"></polyline>\r\n </svg>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control.touched\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";.fv-field-container,.fv-field-container *{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required{color:#e74c3c;margin-left:2px}.fv-input-wrapper{position:relative;width:100%}.fv-input{padding:5px 35px 5px 12px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:all .2s ease-in-out;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input.error{border-color:#dc3545!important}.fv-field-icon{position:absolute;right:12px;top:50%;transform:translateY(-50%);color:#666;display:flex;align-items:center;pointer-events:none}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
2264
+ }
2265
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEmailFieldComponent, decorators: [{
2266
+ type: Component,
2267
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-email-field', template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-input-wrapper\">\r\n <input type=\"email\" [formControl]=\"control\" [placeholder]=\"placeholder\" [readonly]=\"readonly\"\r\n (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" class=\"fv-input\"\r\n [class.error]=\"!!errorMessage && control.touched\" />\r\n <span class=\"fv-field-icon\">\r\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z\"></path>\r\n <polyline points=\"22,6 12,13 2,6\"></polyline>\r\n </svg>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control.touched\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";.fv-field-container,.fv-field-container *{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required{color:#e74c3c;margin-left:2px}.fv-input-wrapper{position:relative;width:100%}.fv-input{padding:5px 35px 5px 12px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:all .2s ease-in-out;height:34px}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input.error{border-color:#dc3545!important}.fv-field-icon{position:absolute;right:12px;top:50%;transform:translateY(-50%);color:#666;display:flex;align-items:center;pointer-events:none}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"] }]
2268
+ }], propDecorators: { label: [{
2269
+ type: Input
2270
+ }], placeholder: [{
2271
+ type: Input
2272
+ }], schema: [{
2273
+ type: Input
2274
+ }], control: [{
2275
+ type: Input
2276
+ }], disabled: [{
2277
+ type: Input
2278
+ }], readonly: [{
2279
+ type: Input
2280
+ }], valueChange: [{
2281
+ type: Output
2282
+ }], blur: [{
2283
+ type: Output
2284
+ }], focus: [{
2285
+ type: Output
2286
+ }] } });
2287
+
2288
+ class FvPasswordFieldComponent {
2289
+ label = 'Password';
2290
+ placeholder = '••••••••';
2291
+ schema;
2292
+ control;
2293
+ disabled = false;
2294
+ readonly = false;
2295
+ valueChange = new EventEmitter();
2296
+ blur = new EventEmitter();
2297
+ focus = new EventEmitter();
2298
+ errorMessage = null;
2299
+ showPassword = false;
2300
+ subscription;
2301
+ ngOnInit() {
2302
+ if (!this.control) {
2303
+ console.error('FvPasswordField: control is required');
2304
+ return;
2305
+ }
2306
+ // Subscribe to value changes
2307
+ this.subscription = this.control.valueChanges.subscribe((value) => {
2308
+ this.validateValue(value);
2309
+ this.valueChange.emit(value);
2310
+ });
2311
+ // Validate initial value
2312
+ if (this.control.value) {
2313
+ this.validateValue(this.control.value);
2314
+ }
2315
+ }
2316
+ ngOnDestroy() {
2317
+ this.subscription?.unsubscribe();
2318
+ }
2319
+ ngOnChanges(changes) {
2320
+ if (changes['disabled'] && this.control) {
2321
+ if (this.disabled) {
2322
+ this.control.disable({ emitEvent: false });
2323
+ }
2324
+ else {
2325
+ this.control.enable({ emitEvent: false });
2326
+ }
2327
+ }
2328
+ }
2329
+ validateValue(value) {
2330
+ if (!this.schema)
2331
+ return;
2332
+ const result = Validator.validate(value, this.schema);
2333
+ this.errorMessage = result.errorKey;
2334
+ if (!result.isValid && result.errorKey) {
2335
+ this.control.setErrors({ [result.errorKey]: true });
2336
+ }
2337
+ else {
2338
+ this.control.setErrors(null);
2339
+ }
2340
+ }
2341
+ toggleVisibility() {
2342
+ if (this.disabled)
2343
+ return;
2344
+ this.showPassword = !this.showPassword;
2345
+ }
2346
+ onBlur(event) {
2347
+ if (this.control && this.schema) {
2348
+ this.validateValue(this.control.value);
2349
+ }
2350
+ this.blur.emit();
2351
+ }
2352
+ onFocus(event) {
2353
+ this.focus.emit();
2354
+ }
2355
+ isRequired() {
2356
+ return (this.schema?.rules?.some((r) => r.name === 'required' && r.params?.['enabled']) || false);
2357
+ }
2358
+ getErrorMessage() {
2359
+ if (!this.errorMessage)
2360
+ return '';
2361
+ const errorMessages = {
2362
+ ERR_REQUIRED: 'Password is required',
2363
+ ERR_MIN_LENGTH: 'Password is too short',
2364
+ ERR_REGEX_MISMATCH: 'Invalid password format',
2365
+ ERR_PASSWORD_TOO_SHORT: 'Password must be at least 8 characters',
2366
+ ERR_PASSWORD_MISSING_UPPERCASE: 'Uppercase letter missing',
2367
+ ERR_PASSWORD_MISSING_LOWERCASE: 'Lowercase letter missing',
2368
+ ERR_PASSWORD_MISSING_NUMBER: 'At least one number missing',
2369
+ ERR_PASSWORD_MISSING_SPECIAL_CHAR: 'Special character missing',
2370
+ };
2371
+ return errorMessages[this.errorMessage] || this.errorMessage;
2372
+ }
2373
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvPasswordFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2374
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvPasswordFieldComponent, isStandalone: true, selector: "fv-password-field", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-input-wrapper\">\r\n <input [type]=\"showPassword ? 'text' : 'password'\" [formControl]=\"control\" [placeholder]=\"placeholder\"\r\n [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" class=\"fv-input\"\r\n [class.error]=\"!!errorMessage && control.touched\" />\r\n <button type=\"button\" class=\"fv-visibility-toggle\" (click)=\"toggleVisibility()\" [disabled]=\"disabled\">\r\n <svg *ngIf=\"!showPassword\" viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <svg *ngIf=\"showPassword\" viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path\r\n d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\">\r\n </path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control.touched\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";.fv-field-container,.fv-field-container *{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required{color:#e74c3c;margin-left:2px}.fv-input-wrapper{position:relative;width:100%}.fv-input{padding:5px 40px 5px 12px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:all .2s ease-in-out;height:34px}:host ::ng-deep input::-ms-reveal,:host ::ng-deep input::-ms-clear,:host ::ng-deep input::-webkit-contacts-auto-fill-button,:host ::ng-deep input::-webkit-credentials-auto-fill-button,:host ::ng-deep input::-webkit-password-reveal-button{display:none!important;width:0!important;height:0!important}.fv-input::-ms-reveal,.fv-input::-ms-clear,.fv-input::-webkit-contacts-auto-fill-button,.fv-input::-webkit-credentials-auto-fill-button{display:none!important}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input.error{border-color:#dc3545!important}.fv-visibility-toggle{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:transparent;border:none;cursor:pointer;padding:6px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:2}.fv-visibility-toggle:hover:not(:disabled){color:#3498db}.fv-visibility-toggle:disabled{cursor:not-allowed;opacity:.5}.fv-visibility-toggle svg{display:block}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
2375
+ }
2376
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvPasswordFieldComponent, decorators: [{
2377
+ type: Component,
2378
+ args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-password-field', template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <div class=\"fv-input-wrapper\">\r\n <input [type]=\"showPassword ? 'text' : 'password'\" [formControl]=\"control\" [placeholder]=\"placeholder\"\r\n [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" class=\"fv-input\"\r\n [class.error]=\"!!errorMessage && control.touched\" />\r\n <button type=\"button\" class=\"fv-visibility-toggle\" (click)=\"toggleVisibility()\" [disabled]=\"disabled\">\r\n <svg *ngIf=\"!showPassword\" viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <svg *ngIf=\"showPassword\" viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path\r\n d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\">\r\n </path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage && control.touched\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";.fv-field-container,.fv-field-container *{font-family:Poppins,sans-serif}.fv-field-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-label{font-size:14px;font-weight:600;color:#151d48;margin-bottom:6px}.required{color:#e74c3c;margin-left:2px}.fv-input-wrapper{position:relative;width:100%}.fv-input{padding:5px 40px 5px 12px;border:1px solid #8CBBA8;border-radius:8px;font-size:14px;font-weight:400;outline:none;width:100%;box-sizing:border-box;background-color:#fff;color:#1f2b41;transition:all .2s ease-in-out;height:34px}:host ::ng-deep input::-ms-reveal,:host ::ng-deep input::-ms-clear,:host ::ng-deep input::-webkit-contacts-auto-fill-button,:host ::ng-deep input::-webkit-credentials-auto-fill-button,:host ::ng-deep input::-webkit-password-reveal-button{display:none!important;width:0!important;height:0!important}.fv-input::-ms-reveal,.fv-input::-ms-clear,.fv-input::-webkit-contacts-auto-fill-button,.fv-input::-webkit-credentials-auto-fill-button{display:none!important}.fv-input:focus{border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.fv-input.error{border-color:#dc3545!important}.fv-visibility-toggle{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:transparent;border:none;cursor:pointer;padding:6px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:2}.fv-visibility-toggle:hover:not(:disabled){color:#3498db}.fv-visibility-toggle:disabled{cursor:not-allowed;opacity:.5}.fv-visibility-toggle svg{display:block}.fv-error-message{margin-top:4px;font-size:12px;color:#e74c3c;display:flex;align-items:center;gap:4px}.fv-error-message:before{content:\"\\26a0\";font-size:14px}\n"] }]
2379
+ }], propDecorators: { label: [{
2380
+ type: Input
2381
+ }], placeholder: [{
2382
+ type: Input
2383
+ }], schema: [{
2384
+ type: Input
2385
+ }], control: [{
2386
+ type: Input
2387
+ }], disabled: [{
2388
+ type: Input
2389
+ }], readonly: [{
2390
+ type: Input
2391
+ }], valueChange: [{
2392
+ type: Output
2393
+ }], blur: [{
2394
+ type: Output
2395
+ }], focus: [{
2396
+ type: Output
2397
+ }] } });
2398
+
2399
+ // add-update-form.component.ts
2400
+ class AddUpdateFormComponent {
2401
+ fb;
2402
+ hostRef;
2403
+ config;
2404
+ validationError = new EventEmitter();
2405
+ form;
2406
+ submitted = false;
2407
+ filePreviews = new Map();
2408
+ fileNames = new Map();
2409
+ valueChangeSubscriptions = [];
2410
+ passwordVisibility = new Map();
2411
+ searchQueries = new Map();
2412
+ constructor(fb, hostRef) {
2413
+ this.fb = fb;
2414
+ this.hostRef = hostRef;
2415
+ }
2416
+ ngOnInit() {
2417
+ this.initializeForm();
2418
+ }
2419
+ ngAfterViewInit() {
2420
+ // Lifecycle hook - can be used for datepicker initialization if needed
2421
+ }
2422
+ getColumnWidth(column) {
2423
+ const maxCols = this.config.maxColsPerRow || 5;
2424
+ const colSpan = Math.min(column.colSpan || 1, maxCols);
2425
+ return `calc(${(colSpan / maxCols) * 100}% - 16px)`;
2426
+ }
2427
+ getControl(name) {
2428
+ return this.form.get(name);
2429
+ }
2430
+ // 2. HELPER: Convert your FieldValidation[] to the library's ValidationSchema
2431
+ getSchema(column) {
2432
+ const rules = [];
2433
+ const errorPriority = [];
2434
+ if (column.validations) {
2435
+ column.validations.forEach((v) => {
2436
+ switch (v.type) {
2437
+ case 'required':
2438
+ rules.push({
2439
+ name: 'required',
2440
+ params: { enabled: true },
2441
+ errorKey: 'ERR_REQUIRED',
2442
+ });
2443
+ errorPriority.push('required');
2444
+ break;
2445
+ case 'email':
2446
+ rules.push({
2447
+ name: 'regex',
2448
+ params: {
2449
+ pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
2450
+ },
2451
+ errorKey: 'ERR_REGEX_MISMATCH',
2452
+ });
2453
+ errorPriority.push('regex');
2454
+ break;
2455
+ case 'minLength':
2456
+ rules.push({
2457
+ name: 'minLength',
2458
+ params: { value: v.value },
2459
+ errorKey: 'ERR_MIN_LENGTH',
2460
+ });
2461
+ errorPriority.push('minLength');
2462
+ break;
2463
+ case 'maxLength':
2464
+ rules.push({
2465
+ name: 'maxLength',
2466
+ params: { value: v.value },
2467
+ errorKey: 'ERR_MAX_LENGTH',
2468
+ });
1969
2469
  errorPriority.push('maxLength');
1970
2470
  break;
1971
2471
  case 'pattern':
@@ -1976,6 +2476,20 @@ class AddUpdateFormComponent {
1976
2476
  });
1977
2477
  errorPriority.push('regex');
1978
2478
  break;
2479
+ case 'passwordComplexity':
2480
+ rules.push({
2481
+ name: 'passwordComplexity',
2482
+ params: v.params || {
2483
+ requireUppercase: true,
2484
+ requireLowercase: true,
2485
+ requireNumber: true,
2486
+ requireSpecialChar: true,
2487
+ minLength: 8
2488
+ },
2489
+ errorKey: v.errorKey || 'ERR_PASSWORD_COMPLEXITY_INVALID',
2490
+ });
2491
+ errorPriority.push('passwordComplexity');
2492
+ break;
1979
2493
  case 'min':
1980
2494
  rules.push({
1981
2495
  name: 'min',
@@ -2444,21 +2958,12 @@ class AddUpdateFormComponent {
2444
2958
  [style.grid-column]="'span ' + (column.colSpan || 1)"
2445
2959
  >
2446
2960
  <ng-container
2447
- *ngIf="
2448
- ['text', 'email', 'password'].includes(column.type) &&
2449
- !column.hidden
2450
- "
2961
+ *ngIf="column.type === 'text' && !column.hidden"
2451
2962
  >
2452
2963
  <fv-entry-field
2453
2964
  [label]="column.label"
2454
2965
  [placeholder]="column.placeholder || ''"
2455
- [type]="
2456
- column.type === 'password'
2457
- ? 'password'
2458
- : column.type === 'email'
2459
- ? 'email'
2460
- : 'text'
2461
- "
2966
+ type="text"
2462
2967
  [control]="getControl(column.name)"
2463
2968
  [schema]="getSchema(column)"
2464
2969
  [disabled]="column.disabled || false"
@@ -2470,6 +2975,34 @@ class AddUpdateFormComponent {
2470
2975
  </fv-entry-field>
2471
2976
  </ng-container>
2472
2977
 
2978
+ <ng-container
2979
+ *ngIf="column.type === 'email' && !column.hidden"
2980
+ >
2981
+ <fv-email-field
2982
+ [label]="column.label"
2983
+ [placeholder]="column.placeholder || ''"
2984
+ [control]="getControl(column.name)"
2985
+ [schema]="getSchema(column)"
2986
+ [disabled]="column.disabled || false"
2987
+ (valueChange)="handleFieldChange(column.name, $event)"
2988
+ >
2989
+ </fv-email-field>
2990
+ </ng-container>
2991
+
2992
+ <ng-container
2993
+ *ngIf="column.type === 'password' && !column.hidden"
2994
+ >
2995
+ <fv-password-field
2996
+ [label]="column.label"
2997
+ [placeholder]="column.placeholder || ''"
2998
+ [control]="getControl(column.name)"
2999
+ [schema]="getSchema(column)"
3000
+ [disabled]="column.disabled || false"
3001
+ (valueChange)="handleFieldChange(column.name, $event)"
3002
+ >
3003
+ </fv-password-field>
3004
+ </ng-container>
3005
+
2473
3006
  <ng-container
2474
3007
  *ngIf="column.type === 'number' && !column.hidden"
2475
3008
  >
@@ -2652,7 +3185,7 @@ class AddUpdateFormComponent {
2652
3185
  </div>
2653
3186
  </form>
2654
3187
  </div>
2655
- `, isInline: true, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*{font-family:Poppins!important}.form-container{background:#f5f5f5;padding:10px;border-radius:8px;margin:0 auto;max-width:100%;box-sizing:border-box}.error-border{border-color:red!important}.hidden{display:none!important}.form-header{margin-bottom:10px}.form-header h2{margin:0;font-size:20px;font-weight:700;color:#303030}.dynamic-form{background:#fff;padding:10px;border-radius:6px;box-shadow:0 1px 3px #0000001a;max-width:100%;box-sizing:border-box}.form-section{margin-bottom:10px}.section-title{font-size:16px;font-weight:700;color:#303030;margin:0 0 16px;text-transform:uppercase;letter-spacing:.5px}.fields-row{display:grid;grid-template-columns:repeat(5,1fr);gap:16px;width:100%;box-sizing:border-box;overflow:visible}.form-field-wrapper{display:flex;position:relative;flex-direction:column;min-width:0;width:100%;box-sizing:border-box;overflow:visible}.password-toggle-btn{position:absolute;right:10px;top:32px;background:none;border:none;cursor:pointer;padding:4px;color:#666}.password-toggle-btn:hover{color:#333}.password-toggle-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}@media (min-width: 1200px) and (max-width: 1400px){.fields-row{grid-template-columns:repeat(5,1fr)}.form-control{width:180px;max-width:180px}}@media (max-width: 1200px){.fields-row{grid-template-columns:repeat(3,1fr)}.form-control{width:100%;max-width:100%}}@media (max-width: 992px){.fields-row{grid-template-columns:repeat(2,1fr);gap:12px}}@media (max-width: 768px){.fields-row{grid-template-columns:repeat(2,1fr);gap:10px}}@media (max-width: 640px){.fields-row{grid-template-columns:1fr;gap:12px}.form-field-wrapper{width:100%}}label{font-weight:600;margin-bottom:6px;color:#151d48;font-size:14px}.required{color:#e74c3c;margin-left:2px}.form-control{padding:5px 10px;width:100%;max-width:100%;border:1px solid #8CBBA8;border-radius:8px;background-color:#fff;font-size:14px;font-weight:400;font-family:inherit;color:#1f2b41;transition:border-color .2s,box-shadow .2s;box-sizing:border-box}.form-control:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.form-control:disabled{background-color:#ecf0f1;cursor:not-allowed}textarea.form-control{resize:vertical;min-height:100px}select.form-control{cursor:pointer;appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23333' d='M6 9L1 4h10z'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 8px center;padding-right:40px}.checkbox-wrapper{display:flex;align-items:center;gap:8px}input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-label{cursor:pointer;margin:0}.file-upload-container{display:flex;align-items:center;gap:20px;padding:20px;background:#fff;max-width:100%;box-sizing:border-box;flex-wrap:wrap}.material-icons{font-family:Material Icons!important;border-radius:4px;display:inline-block;width:40px;padding:8px;height:40px}.file-field-wrapper{width:100%;margin-top:16px;max-width:100%;box-sizing:border-box}.photo-preview-circle{width:100px;height:100px;border-radius:50%;overflow:hidden;border:2px solid #ddd;cursor:pointer;transition:border-color .2s}.photo-preview-circle:hover{border-color:#3498db}.preview-image,.default-photo{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.preview-image img{width:100%;height:100%;object-fit:cover}.default-photo{background:#f0f0f0;color:#999;font-size:40px}.file-info{display:flex;flex-direction:column;gap:8px}.btn-delete{border:none;border-radius:4px;cursor:pointer;font-size:14px;padding:0}.upload-btn-group{display:flex;align-items:center;border:1px solid #d3d3d3;border-radius:8px;background:#fff;overflow:hidden;width:fit-content}.btn-upload{background:#fff;color:#222;border:none;padding:0 18px;font-size:16px;border-right:1px solid #e0e0e0;border-radius:8px 0 0 8px;outline:none;box-shadow:none;cursor:pointer;height:40px;transition:background .2s}.btn-upload-icon{background:#f5f5f5;border:none;border-radius:0 8px 8px 0;display:flex;align-items:center;justify-content:center;width:48px;height:40px;cursor:pointer;transition:background .2s}.btn-upload-icon i.material-icons{font-size:22px;color:#222}.btn-upload:hover,.btn-upload-icon:hover{background:#f0f0f0}.btn-delete{background:#fff;color:red}.btn-delete:hover{background:#f0f0f0}.file-name{font-size:12px;color:#666;margin:10px 8px 8px}.file-label{font-weight:600;margin-bottom:6px;color:#151d48;font-size:14px;display:block}.radio-label{font-weight:600;margin-bottom:15px;color:#151d48;font-size:14px;display:block}.radio-group{display:flex;gap:20px;align-items:center}.radio-item{display:flex;align-items:center;gap:6px}input[type=radio]{width:18px;height:18px;cursor:pointer;accent-color:#3498db}.radio-option-label{cursor:pointer;margin:0;font-weight:400}.hint{font-size:12px;color:#7f8c8d;margin-top:4px}.error-message{color:#e74c3c;font-size:12px;margin-top:4px}.form-actions{display:flex;gap:8px;align-items:center;justify-content:space-between;gap:12px;padding-top:5px}.btn{padding:8px 20px;border:none;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s}.btn-primary{background-color:#006aff;color:#fff}.btn-primary:hover:not(:disabled){background-color:#2980b9}.btn-primary:disabled{background-color:#bdc3c7;cursor:not-allowed}.btn-secondary{background-color:#95a5a6;color:#fff}.btn-secondary:hover{background-color:#7f8c8d}.btn-outline{background-color:#303030;color:#fff}.btn-outline:hover{background-color:#2b2b2b;color:#fff}.month-year-wrapper{position:relative;display:flex;align-items:center;width:100%}.month-year-wrapper .form-control{padding-right:45px}.month-picker-hidden{position:absolute;opacity:0;pointer-events:none;width:0;height:0;border:none;padding:0;margin:0}.month-picker-btn{position:absolute;right:5px;background:transparent;border:none;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:1}.month-picker-btn:hover:not(:disabled){color:#3498db}.month-picker-btn:disabled{cursor:not-allowed;opacity:.5}.month-picker-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}.search-select-wrapper{position:relative;width:100%}.search-select-input{padding-right:10px}.search-select-dropdown{position:absolute;top:calc(100% + 4px);left:0;right:auto;min-width:100%;max-width:calc(100vw - 16px);background:#fff;border:1px solid #d3d3d3;border-radius:8px;max-height:220px;overflow-y:auto;box-shadow:0 4px 10px #00000014;z-index:5;padding:6px 0;transform:translate(0);transition:transform .1s ease-out}.search-select-option{padding:8px 12px;cursor:pointer;display:flex;gap:8px;align-items:center;border-bottom:1px solid #f2f2f2}.search-select-option:last-child{border-bottom:none}.search-select-option:hover{background:#f5f9ff}.option-code{color:#0052cc;font-weight:700;min-width:90px}.option-name{color:#151d48;font-weight:500}.time-picker-wrapper{position:relative;display:flex;align-items:center;width:100%}.time-input{padding-right:45px;flex:1}.time-picker-btn{position:absolute;right:5px;background:transparent;border:none;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:1}.time-picker-btn:hover:not(:disabled){color:#3498db}.time-picker-btn:disabled{cursor:not-allowed;opacity:.5}.time-picker-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}input[type=time]{cursor:pointer}input[type=time]::-webkit-calendar-picker-indicator{cursor:pointer;opacity:0;position:absolute;right:0;width:100%;height:100%}.date-picker-field{width:100%}.date-picker-field ::ng-deep .mat-mdc-form-field{width:100%}.date-picker-field ::ng-deep .mat-mdc-text-field-wrapper{background-color:#fff}.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__trailing{border-color:#8cbba8}.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:#8cbba8}.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#3498db}.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__leading,.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__notch,.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__trailing{border-color:red!important}.date-picker-field ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.date-picker-field ::ng-deep .mat-mdc-form-field-input-control input{font-family:Poppins!important;font-size:14px;font-weight:400;color:#1f2b41}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FvEntryFieldComponent, selector: "fv-entry-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "type", "allowAlphabetsOnly", "maxLength"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvNumberFieldComponent, selector: "fv-number-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "min", "max", "step"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvDropdownComponent, selector: "fv-dropdown", inputs: ["label", "placeholder", "options", "schema", "control", "disabled"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvRadioGroupComponent, selector: "fv-radio-group", inputs: ["label", "control", "options", "disabled", "required", "name"], outputs: ["valueChange"] }, { kind: "component", type: FvCheckboxComponent, selector: "fv-checkbox", inputs: ["label", "control", "disabled", "required"], outputs: ["valueChange"] }, { kind: "component", type: FvDateFieldComponent, selector: "fv-date-field", inputs: ["label", "schema", "control", "disabled", "readonly", "min", "max"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvMonthYearFieldComponent, selector: "fv-month-year-field", inputs: ["label", "schema", "control", "disabled", "readonly", "min", "max"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvFileSelectorComponent, selector: "fv-file-selector", inputs: ["label", "placeholder", "schema", "control", "disabled", "accept", "maxSize"], outputs: ["valueChange", "blur"] }, { kind: "component", type: FvImageSelectorComponent, selector: "fv-image-selector", inputs: ["label", "placeholder", "schema", "control", "disabled", "maxSize"], outputs: ["valueChange", "blur"] }, { kind: "component", type: FvRichTextEditorComponent, selector: "fv-rich-text-editor", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "minHeight", "showToolbar"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvNameCodeComponent, selector: "fv-name-code", inputs: ["label", "placeholder", "options", "schema", "control", "disabled"], outputs: ["selectionChange"] }, { kind: "component", type: FvPhoneFieldComponent, selector: "fv-phone-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvUanFieldComponent, selector: "fv-uan-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvPfFieldComponent, selector: "fv-pf-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvEsiFieldComponent, selector: "fv-esi-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvIfscFieldComponent, selector: "fv-ifsc-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvMicrFieldComponent, selector: "fv-micr-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvIbanFieldComponent, selector: "fv-iban-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }] });
3188
+ `, isInline: true, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*{font-family:Poppins!important}.form-container{background:#f5f5f5;padding:5px 10px 10px;border-radius:8px;margin:0 auto;max-width:100%;box-sizing:border-box}.error-border{border-color:red!important}.hidden{display:none!important}.form-header{margin-bottom:5px}.form-header h2{margin:0;font-size:20px;font-weight:700;color:#303030}.dynamic-form{background:#fff;padding:10px;border-radius:6px;box-shadow:0 1px 3px #0000001a;max-width:100%;box-sizing:border-box}.form-section{margin-bottom:10px}.section-title{font-size:16px;font-weight:700;color:#303030;margin:0 0 16px;text-transform:uppercase;letter-spacing:.5px}.fields-row{display:grid;grid-template-columns:repeat(5,1fr);gap:16px;width:100%;box-sizing:border-box;overflow:visible}.form-field-wrapper{display:flex;position:relative;flex-direction:column;min-width:0;width:100%;box-sizing:border-box;overflow:visible}.password-toggle-btn{position:absolute;right:10px;top:32px;background:none;border:none;cursor:pointer;padding:4px;color:#666}.password-toggle-btn:hover{color:#333}.password-toggle-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}@media (min-width: 1200px) and (max-width: 1400px){.fields-row{grid-template-columns:repeat(5,1fr)}.form-control{width:180px;max-width:180px}}@media (max-width: 1200px){.fields-row{grid-template-columns:repeat(3,1fr)}.form-control{width:100%;max-width:100%}}@media (max-width: 992px){.fields-row{grid-template-columns:repeat(2,1fr);gap:12px}}@media (max-width: 768px){.fields-row{grid-template-columns:repeat(2,1fr);gap:10px}}@media (max-width: 640px){.fields-row{grid-template-columns:1fr;gap:12px}.form-field-wrapper{width:100%}}label{font-weight:600;margin-bottom:6px;color:#151d48;font-size:14px}.required{color:#e74c3c;margin-left:2px}.form-control{padding:5px 10px;width:100%;max-width:100%;height:34px;border:1px solid #8CBBA8;border-radius:8px;background-color:#fff;font-size:14px;font-weight:400;font-family:inherit;color:#1f2b41;transition:border-color .2s,box-shadow .2s;box-sizing:border-box}.form-control:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.form-control:disabled{background-color:#ecf0f1;cursor:not-allowed}textarea.form-control{resize:vertical;min-height:100px}select.form-control{cursor:pointer;appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23333' d='M6 9L1 4h10z'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 8px center;padding-right:40px}.checkbox-wrapper{display:flex;align-items:center;gap:8px}input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-label{cursor:pointer;margin:0}.file-upload-container{display:flex;align-items:center;gap:20px;padding:20px;background:#fff;max-width:100%;box-sizing:border-box;flex-wrap:wrap}.material-icons{font-family:Material Icons!important;border-radius:4px;display:inline-block;width:40px;padding:8px;height:40px}.file-field-wrapper{width:100%;margin-top:16px;max-width:100%;box-sizing:border-box}.photo-preview-circle{width:100px;height:100px;border-radius:50%;overflow:hidden;border:2px solid #ddd;cursor:pointer;transition:border-color .2s}.photo-preview-circle:hover{border-color:#3498db}.preview-image,.default-photo{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.preview-image img{width:100%;height:100%;object-fit:cover}.default-photo{background:#f0f0f0;color:#999;font-size:40px}.file-info{display:flex;flex-direction:column;gap:8px}.btn-delete{border:none;border-radius:4px;cursor:pointer;font-size:14px;padding:0}.upload-btn-group{display:flex;align-items:center;border:1px solid #d3d3d3;border-radius:8px;background:#fff;overflow:hidden;width:fit-content}.btn-upload{background:#fff;color:#222;border:none;padding:0 18px;font-size:16px;border-right:1px solid #e0e0e0;border-radius:8px 0 0 8px;outline:none;box-shadow:none;cursor:pointer;height:40px;transition:background .2s}.btn-upload-icon{background:#f5f5f5;border:none;border-radius:0 8px 8px 0;display:flex;align-items:center;justify-content:center;width:48px;height:40px;cursor:pointer;transition:background .2s}.btn-upload-icon i.material-icons{font-size:22px;color:#222}.btn-upload:hover,.btn-upload-icon:hover{background:#f0f0f0}.btn-delete{background:#fff;color:red}.btn-delete:hover{background:#f0f0f0}.file-name{font-size:12px;color:#666;margin:10px 8px 8px}.file-label{font-weight:600;margin-bottom:6px;color:#151d48;font-size:14px;display:block}.radio-label{font-weight:600;margin-bottom:15px;color:#151d48;font-size:14px;display:block}.radio-group{display:flex;gap:20px;align-items:center}.radio-item{display:flex;align-items:center;gap:6px}input[type=radio]{width:18px;height:18px;cursor:pointer;accent-color:#3498db}.radio-option-label{cursor:pointer;margin:0;font-weight:400}.hint{font-size:12px;color:#7f8c8d;margin-top:4px}.error-message{color:#e74c3c;font-size:12px;margin-top:4px}.form-actions{display:flex;gap:8px;align-items:center;justify-content:space-between;gap:12px;padding-top:5px}.btn{padding:8px 20px;border:none;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s}.btn-primary{background-color:#006aff;color:#fff}.btn-primary:hover:not(:disabled){background-color:#2980b9}.btn-primary:disabled{background-color:#bdc3c7;cursor:not-allowed}.btn-secondary{background-color:#95a5a6;color:#fff}.btn-secondary:hover{background-color:#7f8c8d}.btn-outline{background-color:#303030;color:#fff}.btn-outline:hover{background-color:#2b2b2b;color:#fff}.month-year-wrapper{position:relative;display:flex;align-items:center;width:100%}.month-year-wrapper .form-control{padding-right:45px}.month-picker-hidden{position:absolute;opacity:0;pointer-events:none;width:0;height:0;border:none;padding:0;margin:0}.month-picker-btn{position:absolute;right:5px;background:transparent;border:none;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:1}.month-picker-btn:hover:not(:disabled){color:#3498db}.month-picker-btn:disabled{cursor:not-allowed;opacity:.5}.month-picker-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}.search-select-wrapper{position:relative;width:100%}.search-select-input{padding-right:10px}.search-select-dropdown{position:absolute;top:calc(100% + 4px);left:0;right:auto;min-width:100%;max-width:calc(100vw - 16px);background:#fff;border:1px solid #d3d3d3;border-radius:8px;max-height:220px;overflow-y:auto;box-shadow:0 4px 10px #00000014;z-index:5;padding:6px 0;transform:translate(0);transition:transform .1s ease-out}.search-select-option{padding:8px 12px;cursor:pointer;display:flex;gap:8px;align-items:center;border-bottom:1px solid #f2f2f2}.search-select-option:last-child{border-bottom:none}.search-select-option:hover{background:#f5f9ff}.option-code{color:#0052cc;font-weight:700;min-width:90px}.option-name{color:#151d48;font-weight:500}.time-picker-wrapper{position:relative;display:flex;align-items:center;width:100%}.time-input{padding-right:45px;flex:1}.time-picker-btn{position:absolute;right:5px;background:transparent;border:none;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:1}.time-picker-btn:hover:not(:disabled){color:#3498db}.time-picker-btn:disabled{cursor:not-allowed;opacity:.5}.time-picker-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}input[type=time]{cursor:pointer}input[type=time]::-webkit-calendar-picker-indicator{cursor:pointer;opacity:0;position:absolute;right:0;width:100%;height:100%}.date-picker-field{width:100%}.date-picker-field ::ng-deep .mat-mdc-form-field{width:100%}.date-picker-field ::ng-deep .mat-mdc-text-field-wrapper{background-color:#fff}.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__trailing{border-color:#8cbba8}.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:#8cbba8}.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#3498db}.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__leading,.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__notch,.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__trailing{border-color:red!important}.date-picker-field ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.date-picker-field ::ng-deep .mat-mdc-form-field-input-control input{font-family:Poppins!important;font-size:14px;font-weight:400;color:#1f2b41}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FvEntryFieldComponent, selector: "fv-entry-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "type", "allowAlphabetsOnly", "maxLength"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvNumberFieldComponent, selector: "fv-number-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "min", "max", "step"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvDropdownComponent, selector: "fv-dropdown", inputs: ["label", "placeholder", "options", "schema", "control", "disabled"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvRadioGroupComponent, selector: "fv-radio-group", inputs: ["label", "control", "options", "disabled", "required", "name"], outputs: ["valueChange"] }, { kind: "component", type: FvCheckboxComponent, selector: "fv-checkbox", inputs: ["label", "control", "disabled", "required"], outputs: ["valueChange"] }, { kind: "component", type: FvDateFieldComponent, selector: "fv-date-field", inputs: ["label", "schema", "control", "disabled", "readonly", "min", "max"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvMonthYearFieldComponent, selector: "fv-month-year-field", inputs: ["label", "schema", "control", "disabled", "readonly", "min", "max"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvFileSelectorComponent, selector: "fv-file-selector", inputs: ["label", "placeholder", "schema", "control", "disabled", "accept", "maxSize"], outputs: ["valueChange", "blur"] }, { kind: "component", type: FvImageSelectorComponent, selector: "fv-image-selector", inputs: ["label", "placeholder", "schema", "control", "disabled", "maxSize"], outputs: ["valueChange", "blur"] }, { kind: "component", type: FvRichTextEditorComponent, selector: "fv-rich-text-editor", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "minHeight", "showToolbar"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvNameCodeComponent, selector: "fv-name-code", inputs: ["label", "placeholder", "options", "schema", "control", "disabled"], outputs: ["selectionChange"] }, { kind: "component", type: FvPhoneFieldComponent, selector: "fv-phone-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvUanFieldComponent, selector: "fv-uan-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvPfFieldComponent, selector: "fv-pf-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvEsiFieldComponent, selector: "fv-esi-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvIfscFieldComponent, selector: "fv-ifsc-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvMicrFieldComponent, selector: "fv-micr-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvIbanFieldComponent, selector: "fv-iban-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvEmailFieldComponent, selector: "fv-email-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvPasswordFieldComponent, selector: "fv-password-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly"], outputs: ["valueChange", "blur", "focus"] }] });
2656
3189
  }
2657
3190
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AddUpdateFormComponent, decorators: [{
2658
3191
  type: Component,
@@ -2669,7 +3202,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2669
3202
  FvFileSelectorComponent,
2670
3203
  FvImageSelectorComponent,
2671
3204
  FvRichTextEditorComponent,
2672
- FvRichTextEditorComponent,
2673
3205
  FvNameCodeComponent,
2674
3206
  FvPhoneFieldComponent,
2675
3207
  FvUanFieldComponent,
@@ -2678,6 +3210,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2678
3210
  FvIfscFieldComponent,
2679
3211
  FvMicrFieldComponent,
2680
3212
  FvIbanFieldComponent,
3213
+ FvEmailFieldComponent,
3214
+ FvPasswordFieldComponent,
2681
3215
  ], template: `
2682
3216
  <div class="form-container">
2683
3217
  <div class="form-header" *ngIf="config.formTitle">
@@ -2699,21 +3233,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2699
3233
  [style.grid-column]="'span ' + (column.colSpan || 1)"
2700
3234
  >
2701
3235
  <ng-container
2702
- *ngIf="
2703
- ['text', 'email', 'password'].includes(column.type) &&
2704
- !column.hidden
2705
- "
3236
+ *ngIf="column.type === 'text' && !column.hidden"
2706
3237
  >
2707
3238
  <fv-entry-field
2708
3239
  [label]="column.label"
2709
3240
  [placeholder]="column.placeholder || ''"
2710
- [type]="
2711
- column.type === 'password'
2712
- ? 'password'
2713
- : column.type === 'email'
2714
- ? 'email'
2715
- : 'text'
2716
- "
3241
+ type="text"
2717
3242
  [control]="getControl(column.name)"
2718
3243
  [schema]="getSchema(column)"
2719
3244
  [disabled]="column.disabled || false"
@@ -2725,6 +3250,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2725
3250
  </fv-entry-field>
2726
3251
  </ng-container>
2727
3252
 
3253
+ <ng-container
3254
+ *ngIf="column.type === 'email' && !column.hidden"
3255
+ >
3256
+ <fv-email-field
3257
+ [label]="column.label"
3258
+ [placeholder]="column.placeholder || ''"
3259
+ [control]="getControl(column.name)"
3260
+ [schema]="getSchema(column)"
3261
+ [disabled]="column.disabled || false"
3262
+ (valueChange)="handleFieldChange(column.name, $event)"
3263
+ >
3264
+ </fv-email-field>
3265
+ </ng-container>
3266
+
3267
+ <ng-container
3268
+ *ngIf="column.type === 'password' && !column.hidden"
3269
+ >
3270
+ <fv-password-field
3271
+ [label]="column.label"
3272
+ [placeholder]="column.placeholder || ''"
3273
+ [control]="getControl(column.name)"
3274
+ [schema]="getSchema(column)"
3275
+ [disabled]="column.disabled || false"
3276
+ (valueChange)="handleFieldChange(column.name, $event)"
3277
+ >
3278
+ </fv-password-field>
3279
+ </ng-container>
3280
+
2728
3281
  <ng-container
2729
3282
  *ngIf="column.type === 'number' && !column.hidden"
2730
3283
  >
@@ -2907,92 +3460,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2907
3460
  </div>
2908
3461
  </form>
2909
3462
  </div>
2910
- `, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*{font-family:Poppins!important}.form-container{background:#f5f5f5;padding:10px;border-radius:8px;margin:0 auto;max-width:100%;box-sizing:border-box}.error-border{border-color:red!important}.hidden{display:none!important}.form-header{margin-bottom:10px}.form-header h2{margin:0;font-size:20px;font-weight:700;color:#303030}.dynamic-form{background:#fff;padding:10px;border-radius:6px;box-shadow:0 1px 3px #0000001a;max-width:100%;box-sizing:border-box}.form-section{margin-bottom:10px}.section-title{font-size:16px;font-weight:700;color:#303030;margin:0 0 16px;text-transform:uppercase;letter-spacing:.5px}.fields-row{display:grid;grid-template-columns:repeat(5,1fr);gap:16px;width:100%;box-sizing:border-box;overflow:visible}.form-field-wrapper{display:flex;position:relative;flex-direction:column;min-width:0;width:100%;box-sizing:border-box;overflow:visible}.password-toggle-btn{position:absolute;right:10px;top:32px;background:none;border:none;cursor:pointer;padding:4px;color:#666}.password-toggle-btn:hover{color:#333}.password-toggle-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}@media (min-width: 1200px) and (max-width: 1400px){.fields-row{grid-template-columns:repeat(5,1fr)}.form-control{width:180px;max-width:180px}}@media (max-width: 1200px){.fields-row{grid-template-columns:repeat(3,1fr)}.form-control{width:100%;max-width:100%}}@media (max-width: 992px){.fields-row{grid-template-columns:repeat(2,1fr);gap:12px}}@media (max-width: 768px){.fields-row{grid-template-columns:repeat(2,1fr);gap:10px}}@media (max-width: 640px){.fields-row{grid-template-columns:1fr;gap:12px}.form-field-wrapper{width:100%}}label{font-weight:600;margin-bottom:6px;color:#151d48;font-size:14px}.required{color:#e74c3c;margin-left:2px}.form-control{padding:5px 10px;width:100%;max-width:100%;border:1px solid #8CBBA8;border-radius:8px;background-color:#fff;font-size:14px;font-weight:400;font-family:inherit;color:#1f2b41;transition:border-color .2s,box-shadow .2s;box-sizing:border-box}.form-control:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.form-control:disabled{background-color:#ecf0f1;cursor:not-allowed}textarea.form-control{resize:vertical;min-height:100px}select.form-control{cursor:pointer;appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23333' d='M6 9L1 4h10z'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 8px center;padding-right:40px}.checkbox-wrapper{display:flex;align-items:center;gap:8px}input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-label{cursor:pointer;margin:0}.file-upload-container{display:flex;align-items:center;gap:20px;padding:20px;background:#fff;max-width:100%;box-sizing:border-box;flex-wrap:wrap}.material-icons{font-family:Material Icons!important;border-radius:4px;display:inline-block;width:40px;padding:8px;height:40px}.file-field-wrapper{width:100%;margin-top:16px;max-width:100%;box-sizing:border-box}.photo-preview-circle{width:100px;height:100px;border-radius:50%;overflow:hidden;border:2px solid #ddd;cursor:pointer;transition:border-color .2s}.photo-preview-circle:hover{border-color:#3498db}.preview-image,.default-photo{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.preview-image img{width:100%;height:100%;object-fit:cover}.default-photo{background:#f0f0f0;color:#999;font-size:40px}.file-info{display:flex;flex-direction:column;gap:8px}.btn-delete{border:none;border-radius:4px;cursor:pointer;font-size:14px;padding:0}.upload-btn-group{display:flex;align-items:center;border:1px solid #d3d3d3;border-radius:8px;background:#fff;overflow:hidden;width:fit-content}.btn-upload{background:#fff;color:#222;border:none;padding:0 18px;font-size:16px;border-right:1px solid #e0e0e0;border-radius:8px 0 0 8px;outline:none;box-shadow:none;cursor:pointer;height:40px;transition:background .2s}.btn-upload-icon{background:#f5f5f5;border:none;border-radius:0 8px 8px 0;display:flex;align-items:center;justify-content:center;width:48px;height:40px;cursor:pointer;transition:background .2s}.btn-upload-icon i.material-icons{font-size:22px;color:#222}.btn-upload:hover,.btn-upload-icon:hover{background:#f0f0f0}.btn-delete{background:#fff;color:red}.btn-delete:hover{background:#f0f0f0}.file-name{font-size:12px;color:#666;margin:10px 8px 8px}.file-label{font-weight:600;margin-bottom:6px;color:#151d48;font-size:14px;display:block}.radio-label{font-weight:600;margin-bottom:15px;color:#151d48;font-size:14px;display:block}.radio-group{display:flex;gap:20px;align-items:center}.radio-item{display:flex;align-items:center;gap:6px}input[type=radio]{width:18px;height:18px;cursor:pointer;accent-color:#3498db}.radio-option-label{cursor:pointer;margin:0;font-weight:400}.hint{font-size:12px;color:#7f8c8d;margin-top:4px}.error-message{color:#e74c3c;font-size:12px;margin-top:4px}.form-actions{display:flex;gap:8px;align-items:center;justify-content:space-between;gap:12px;padding-top:5px}.btn{padding:8px 20px;border:none;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s}.btn-primary{background-color:#006aff;color:#fff}.btn-primary:hover:not(:disabled){background-color:#2980b9}.btn-primary:disabled{background-color:#bdc3c7;cursor:not-allowed}.btn-secondary{background-color:#95a5a6;color:#fff}.btn-secondary:hover{background-color:#7f8c8d}.btn-outline{background-color:#303030;color:#fff}.btn-outline:hover{background-color:#2b2b2b;color:#fff}.month-year-wrapper{position:relative;display:flex;align-items:center;width:100%}.month-year-wrapper .form-control{padding-right:45px}.month-picker-hidden{position:absolute;opacity:0;pointer-events:none;width:0;height:0;border:none;padding:0;margin:0}.month-picker-btn{position:absolute;right:5px;background:transparent;border:none;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:1}.month-picker-btn:hover:not(:disabled){color:#3498db}.month-picker-btn:disabled{cursor:not-allowed;opacity:.5}.month-picker-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}.search-select-wrapper{position:relative;width:100%}.search-select-input{padding-right:10px}.search-select-dropdown{position:absolute;top:calc(100% + 4px);left:0;right:auto;min-width:100%;max-width:calc(100vw - 16px);background:#fff;border:1px solid #d3d3d3;border-radius:8px;max-height:220px;overflow-y:auto;box-shadow:0 4px 10px #00000014;z-index:5;padding:6px 0;transform:translate(0);transition:transform .1s ease-out}.search-select-option{padding:8px 12px;cursor:pointer;display:flex;gap:8px;align-items:center;border-bottom:1px solid #f2f2f2}.search-select-option:last-child{border-bottom:none}.search-select-option:hover{background:#f5f9ff}.option-code{color:#0052cc;font-weight:700;min-width:90px}.option-name{color:#151d48;font-weight:500}.time-picker-wrapper{position:relative;display:flex;align-items:center;width:100%}.time-input{padding-right:45px;flex:1}.time-picker-btn{position:absolute;right:5px;background:transparent;border:none;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:1}.time-picker-btn:hover:not(:disabled){color:#3498db}.time-picker-btn:disabled{cursor:not-allowed;opacity:.5}.time-picker-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}input[type=time]{cursor:pointer}input[type=time]::-webkit-calendar-picker-indicator{cursor:pointer;opacity:0;position:absolute;right:0;width:100%;height:100%}.date-picker-field{width:100%}.date-picker-field ::ng-deep .mat-mdc-form-field{width:100%}.date-picker-field ::ng-deep .mat-mdc-text-field-wrapper{background-color:#fff}.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__trailing{border-color:#8cbba8}.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:#8cbba8}.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#3498db}.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__leading,.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__notch,.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__trailing{border-color:red!important}.date-picker-field ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.date-picker-field ::ng-deep .mat-mdc-form-field-input-control input{font-family:Poppins!important;font-size:14px;font-weight:400;color:#1f2b41}\n"] }]
3463
+ `, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*{font-family:Poppins!important}.form-container{background:#f5f5f5;padding:5px 10px 10px;border-radius:8px;margin:0 auto;max-width:100%;box-sizing:border-box}.error-border{border-color:red!important}.hidden{display:none!important}.form-header{margin-bottom:5px}.form-header h2{margin:0;font-size:20px;font-weight:700;color:#303030}.dynamic-form{background:#fff;padding:10px;border-radius:6px;box-shadow:0 1px 3px #0000001a;max-width:100%;box-sizing:border-box}.form-section{margin-bottom:10px}.section-title{font-size:16px;font-weight:700;color:#303030;margin:0 0 16px;text-transform:uppercase;letter-spacing:.5px}.fields-row{display:grid;grid-template-columns:repeat(5,1fr);gap:16px;width:100%;box-sizing:border-box;overflow:visible}.form-field-wrapper{display:flex;position:relative;flex-direction:column;min-width:0;width:100%;box-sizing:border-box;overflow:visible}.password-toggle-btn{position:absolute;right:10px;top:32px;background:none;border:none;cursor:pointer;padding:4px;color:#666}.password-toggle-btn:hover{color:#333}.password-toggle-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}@media (min-width: 1200px) and (max-width: 1400px){.fields-row{grid-template-columns:repeat(5,1fr)}.form-control{width:180px;max-width:180px}}@media (max-width: 1200px){.fields-row{grid-template-columns:repeat(3,1fr)}.form-control{width:100%;max-width:100%}}@media (max-width: 992px){.fields-row{grid-template-columns:repeat(2,1fr);gap:12px}}@media (max-width: 768px){.fields-row{grid-template-columns:repeat(2,1fr);gap:10px}}@media (max-width: 640px){.fields-row{grid-template-columns:1fr;gap:12px}.form-field-wrapper{width:100%}}label{font-weight:600;margin-bottom:6px;color:#151d48;font-size:14px}.required{color:#e74c3c;margin-left:2px}.form-control{padding:5px 10px;width:100%;max-width:100%;height:34px;border:1px solid #8CBBA8;border-radius:8px;background-color:#fff;font-size:14px;font-weight:400;font-family:inherit;color:#1f2b41;transition:border-color .2s,box-shadow .2s;box-sizing:border-box}.form-control:focus{outline:none;border-color:#3498db;box-shadow:0 0 0 3px #3498db1a}.form-control:disabled{background-color:#ecf0f1;cursor:not-allowed}textarea.form-control{resize:vertical;min-height:100px}select.form-control{cursor:pointer;appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23333' d='M6 9L1 4h10z'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 8px center;padding-right:40px}.checkbox-wrapper{display:flex;align-items:center;gap:8px}input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-label{cursor:pointer;margin:0}.file-upload-container{display:flex;align-items:center;gap:20px;padding:20px;background:#fff;max-width:100%;box-sizing:border-box;flex-wrap:wrap}.material-icons{font-family:Material Icons!important;border-radius:4px;display:inline-block;width:40px;padding:8px;height:40px}.file-field-wrapper{width:100%;margin-top:16px;max-width:100%;box-sizing:border-box}.photo-preview-circle{width:100px;height:100px;border-radius:50%;overflow:hidden;border:2px solid #ddd;cursor:pointer;transition:border-color .2s}.photo-preview-circle:hover{border-color:#3498db}.preview-image,.default-photo{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.preview-image img{width:100%;height:100%;object-fit:cover}.default-photo{background:#f0f0f0;color:#999;font-size:40px}.file-info{display:flex;flex-direction:column;gap:8px}.btn-delete{border:none;border-radius:4px;cursor:pointer;font-size:14px;padding:0}.upload-btn-group{display:flex;align-items:center;border:1px solid #d3d3d3;border-radius:8px;background:#fff;overflow:hidden;width:fit-content}.btn-upload{background:#fff;color:#222;border:none;padding:0 18px;font-size:16px;border-right:1px solid #e0e0e0;border-radius:8px 0 0 8px;outline:none;box-shadow:none;cursor:pointer;height:40px;transition:background .2s}.btn-upload-icon{background:#f5f5f5;border:none;border-radius:0 8px 8px 0;display:flex;align-items:center;justify-content:center;width:48px;height:40px;cursor:pointer;transition:background .2s}.btn-upload-icon i.material-icons{font-size:22px;color:#222}.btn-upload:hover,.btn-upload-icon:hover{background:#f0f0f0}.btn-delete{background:#fff;color:red}.btn-delete:hover{background:#f0f0f0}.file-name{font-size:12px;color:#666;margin:10px 8px 8px}.file-label{font-weight:600;margin-bottom:6px;color:#151d48;font-size:14px;display:block}.radio-label{font-weight:600;margin-bottom:15px;color:#151d48;font-size:14px;display:block}.radio-group{display:flex;gap:20px;align-items:center}.radio-item{display:flex;align-items:center;gap:6px}input[type=radio]{width:18px;height:18px;cursor:pointer;accent-color:#3498db}.radio-option-label{cursor:pointer;margin:0;font-weight:400}.hint{font-size:12px;color:#7f8c8d;margin-top:4px}.error-message{color:#e74c3c;font-size:12px;margin-top:4px}.form-actions{display:flex;gap:8px;align-items:center;justify-content:space-between;gap:12px;padding-top:5px}.btn{padding:8px 20px;border:none;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s}.btn-primary{background-color:#006aff;color:#fff}.btn-primary:hover:not(:disabled){background-color:#2980b9}.btn-primary:disabled{background-color:#bdc3c7;cursor:not-allowed}.btn-secondary{background-color:#95a5a6;color:#fff}.btn-secondary:hover{background-color:#7f8c8d}.btn-outline{background-color:#303030;color:#fff}.btn-outline:hover{background-color:#2b2b2b;color:#fff}.month-year-wrapper{position:relative;display:flex;align-items:center;width:100%}.month-year-wrapper .form-control{padding-right:45px}.month-picker-hidden{position:absolute;opacity:0;pointer-events:none;width:0;height:0;border:none;padding:0;margin:0}.month-picker-btn{position:absolute;right:5px;background:transparent;border:none;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:1}.month-picker-btn:hover:not(:disabled){color:#3498db}.month-picker-btn:disabled{cursor:not-allowed;opacity:.5}.month-picker-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}.search-select-wrapper{position:relative;width:100%}.search-select-input{padding-right:10px}.search-select-dropdown{position:absolute;top:calc(100% + 4px);left:0;right:auto;min-width:100%;max-width:calc(100vw - 16px);background:#fff;border:1px solid #d3d3d3;border-radius:8px;max-height:220px;overflow-y:auto;box-shadow:0 4px 10px #00000014;z-index:5;padding:6px 0;transform:translate(0);transition:transform .1s ease-out}.search-select-option{padding:8px 12px;cursor:pointer;display:flex;gap:8px;align-items:center;border-bottom:1px solid #f2f2f2}.search-select-option:last-child{border-bottom:none}.search-select-option:hover{background:#f5f9ff}.option-code{color:#0052cc;font-weight:700;min-width:90px}.option-name{color:#151d48;font-weight:500}.time-picker-wrapper{position:relative;display:flex;align-items:center;width:100%}.time-input{padding-right:45px;flex:1}.time-picker-btn{position:absolute;right:5px;background:transparent;border:none;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s;z-index:1}.time-picker-btn:hover:not(:disabled){color:#3498db}.time-picker-btn:disabled{cursor:not-allowed;opacity:.5}.time-picker-btn .material-icons{font-size:20px;width:auto;height:auto;padding:0}input[type=time]{cursor:pointer}input[type=time]::-webkit-calendar-picker-indicator{cursor:pointer;opacity:0;position:absolute;right:0;width:100%;height:100%}.date-picker-field{width:100%}.date-picker-field ::ng-deep .mat-mdc-form-field{width:100%}.date-picker-field ::ng-deep .mat-mdc-text-field-wrapper{background-color:#fff}.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__trailing{border-color:#8cbba8}.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:#8cbba8}.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__leading,.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__notch,.date-picker-field ::ng-deep .mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#3498db}.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__leading,.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__notch,.date-picker-field.error-border ::ng-deep .mdc-text-field--outlined .mdc-notched-outline__trailing{border-color:red!important}.date-picker-field ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.date-picker-field ::ng-deep .mat-mdc-form-field-input-control input{font-family:Poppins!important;font-size:14px;font-weight:400;color:#1f2b41}\n"] }]
2911
3464
  }], ctorParameters: () => [{ type: i2.FormBuilder }, { type: i0.ElementRef }], propDecorators: { config: [{
2912
3465
  type: Input
2913
3466
  }], validationError: [{
2914
3467
  type: Output
2915
3468
  }] } });
2916
3469
 
2917
- class FvControlsModule {
2918
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2919
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, imports: [CommonModule,
2920
- ReactiveFormsModule,
2921
- FvEntryFieldComponent,
2922
- FvDateFieldComponent,
2923
- FvMonthYearFieldComponent,
2924
- FvNumberFieldComponent,
2925
- FvCheckboxComponent,
2926
- FvRadioGroupComponent,
2927
- FvDropdownComponent,
2928
- FvFileSelectorComponent,
2929
- FvImageSelectorComponent,
2930
- FvRichTextEditorComponent,
2931
- FvNameCodeComponent,
2932
- AddUpdateFormComponent], exports: [FvEntryFieldComponent,
2933
- FvDateFieldComponent,
2934
- FvMonthYearFieldComponent,
2935
- FvNumberFieldComponent,
2936
- FvCheckboxComponent,
2937
- FvRadioGroupComponent,
2938
- FvDropdownComponent,
2939
- FvFileSelectorComponent,
2940
- FvImageSelectorComponent,
2941
- FvRichTextEditorComponent,
2942
- FvNameCodeComponent,
2943
- AddUpdateFormComponent] });
2944
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, imports: [CommonModule,
2945
- ReactiveFormsModule,
2946
- FvEntryFieldComponent,
2947
- FvDateFieldComponent,
2948
- FvMonthYearFieldComponent,
2949
- FvNumberFieldComponent,
2950
- FvCheckboxComponent,
2951
- FvRadioGroupComponent,
2952
- FvDropdownComponent,
2953
- FvFileSelectorComponent,
2954
- FvImageSelectorComponent,
2955
- FvRichTextEditorComponent,
2956
- FvNameCodeComponent,
2957
- AddUpdateFormComponent] });
2958
- }
2959
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, decorators: [{
2960
- type: NgModule,
2961
- args: [{
2962
- declarations: [],
2963
- imports: [
2964
- CommonModule,
2965
- ReactiveFormsModule,
2966
- FvEntryFieldComponent,
2967
- FvDateFieldComponent,
2968
- FvMonthYearFieldComponent,
2969
- FvNumberFieldComponent,
2970
- FvCheckboxComponent,
2971
- FvRadioGroupComponent,
2972
- FvDropdownComponent,
2973
- FvFileSelectorComponent,
2974
- FvImageSelectorComponent,
2975
- FvRichTextEditorComponent,
2976
- FvNameCodeComponent,
2977
- AddUpdateFormComponent,
2978
- ],
2979
- exports: [
2980
- FvEntryFieldComponent,
2981
- FvDateFieldComponent,
2982
- FvMonthYearFieldComponent,
2983
- FvNumberFieldComponent,
2984
- FvCheckboxComponent,
2985
- FvRadioGroupComponent,
2986
- FvDropdownComponent,
2987
- FvFileSelectorComponent,
2988
- FvImageSelectorComponent,
2989
- FvRichTextEditorComponent,
2990
- FvNameCodeComponent,
2991
- AddUpdateFormComponent,
2992
- ],
2993
- }]
2994
- }] });
2995
-
2996
3470
  class QueryFormComponent {
2997
3471
  fb;
2998
3472
  config;
@@ -3062,6 +3536,39 @@ class QueryFormComponent {
3062
3536
  rules.push({ name: 'required', params: { enabled: true }, errorKey: 'ERR_REQUIRED' });
3063
3537
  errorPriority.push('required');
3064
3538
  }
3539
+ if (column.type === 'email') {
3540
+ rules.push({
3541
+ name: 'regex',
3542
+ params: {
3543
+ pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
3544
+ },
3545
+ errorKey: 'ERR_EMAIL_INVALID',
3546
+ });
3547
+ errorPriority.push('regex');
3548
+ }
3549
+ if (column.type === 'pf') {
3550
+ rules.push({
3551
+ name: 'regex',
3552
+ params: {
3553
+ pattern: '^[A-Z]{2}/[A-Z]{3}/[0-9]{7}/[0-9]{3}/[0-9]{7}$'
3554
+ },
3555
+ errorKey: 'ERR_PF_INVALID'
3556
+ });
3557
+ errorPriority.push('regex');
3558
+ }
3559
+ if (column.type === 'password') {
3560
+ rules.push({
3561
+ name: 'passwordComplexity',
3562
+ params: {
3563
+ minLength: 8,
3564
+ requireUppercase: true,
3565
+ requireLowercase: true,
3566
+ requireNumber: true,
3567
+ requireSpecialChar: true
3568
+ }
3569
+ });
3570
+ errorPriority.push('passwordComplexity');
3571
+ }
3065
3572
  return {
3066
3573
  controlType: this.mapType(column.type),
3067
3574
  rules: rules,
@@ -3084,6 +3591,8 @@ class QueryFormComponent {
3084
3591
  case 'ifsc': return 'IfscField';
3085
3592
  case 'micr': return 'MicrField';
3086
3593
  case 'iban': return 'IbanField';
3594
+ case 'email': return 'EmailField';
3595
+ case 'password': return 'PasswordField';
3087
3596
  default: return 'EntryField';
3088
3597
  }
3089
3598
  }
@@ -3289,6 +3798,14 @@ class QueryFormComponent {
3289
3798
  <ng-container *ngIf="column.type === 'iban'">
3290
3799
  <fv-iban-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-iban-field>
3291
3800
  </ng-container>
3801
+
3802
+ <ng-container *ngIf="column.type === 'email'">
3803
+ <fv-email-field [label]="column.label" [placeholder]="column.placeholder || ''" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-email-field>
3804
+ </ng-container>
3805
+
3806
+ <ng-container *ngIf="column.type === 'password'">
3807
+ <fv-password-field [label]="column.label" [placeholder]="column.placeholder || ''" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-password-field>
3808
+ </ng-container>
3292
3809
  </div>
3293
3810
  </div>
3294
3811
 
@@ -3315,7 +3832,7 @@ class QueryFormComponent {
3315
3832
  </form>
3316
3833
  </div>
3317
3834
  </div>
3318
- `, isInline: true, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*{font-family:Poppins}.material-icons{font-family:Material Icons!important;font-size:22px;display:inline-block}.cont{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.validation-message{background-color:#fee;color:#c33;padding:12px 16px;border-radius:8px;margin:10px 0;display:flex;align-items:center;gap:8px;font-size:14px;font-weight:500;border:1px solid #fcc}.export-buttons{display:flex;gap:10px}.export-btn{cursor:pointer;display:flex;align-items:center;gap:5px;transition:all .3s ease;border:none;padding:8px 16px;border-radius:7px;background:#006aff;color:#fff}.export-btn:hover{background:#0045a6;box-shadow:0 4px 8px #00000026}.export-menu-container{position:relative;border-radius:7px}.export-menu{position:absolute;top:100%;right:0;background:#fff;border-radius:4px;box-shadow:0 4px 12px #00000026;margin-top:5px;min-width:180px;z-index:1000}.menu-item{width:100%;color:#000;text-align:left;background:#fff;border:none;cursor:pointer;font-size:14px;transition:background .2s;padding:12px 16px;display:flex;align-items:center;gap:10px}.menu-item:hover{background:#f5f5f5}.query-form-container{background:#f2f2f2;border-radius:8px;padding:10px;margin:auto;box-shadow:0 2px 5px #0000001a;margin-bottom:1rem;overflow:visible}.form-title{font-size:20px;font-weight:700;color:#303030;margin:0;font-family:Poppins}.form-content{display:flex;flex-direction:column;gap:5px;background-color:#fff;padding:10px;border:.5px solid #cfcfcf;border-radius:12px;overflow:visible}.form-row{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));justify-content:flex-start;gap:20px;align-items:end;margin-bottom:15px;overflow:visible}.form-field{display:flex;flex-direction:column;width:100%;position:relative;overflow:visible}.view-button{padding:8px 15px;background:#006aff;color:#fff;border:none;border-radius:7px;font-size:14px;font-weight:600;cursor:pointer;transition:background-color .2s}.view-button:hover{background:#0045a6}.button-row{display:flex;justify-content:space-between;gap:10px;padding-top:5px;margin-top:10px;border-top:1px solid #eee}.back-button{padding:8px 15px;background-color:#303030;color:#fff;border:none;border-radius:7px;font-size:14px;font-weight:600;cursor:pointer;transition:background-color .2s}.back-button:hover{background-color:#000}@media (max-width: 768px){.form-row{grid-template-columns:1fr}.button-row{justify-content:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FvEntryFieldComponent, selector: "fv-entry-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "type", "allowAlphabetsOnly", "maxLength"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvDropdownComponent, selector: "fv-dropdown", inputs: ["label", "placeholder", "options", "schema", "control", "disabled"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvNumberFieldComponent, selector: "fv-number-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "min", "max", "step"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvDateFieldComponent, selector: "fv-date-field", inputs: ["label", "schema", "control", "disabled", "readonly", "min", "max"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvMonthYearFieldComponent, selector: "fv-month-year-field", inputs: ["label", "schema", "control", "disabled", "readonly", "min", "max"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvFileSelectorComponent, selector: "fv-file-selector", inputs: ["label", "placeholder", "schema", "control", "disabled", "accept", "maxSize"], outputs: ["valueChange", "blur"] }, { kind: "component", type: FvNameCodeComponent, selector: "fv-name-code", inputs: ["label", "placeholder", "options", "schema", "control", "disabled"], outputs: ["selectionChange"] }, { kind: "component", type: FvPhoneFieldComponent, selector: "fv-phone-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvUanFieldComponent, selector: "fv-uan-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvPfFieldComponent, selector: "fv-pf-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvEsiFieldComponent, selector: "fv-esi-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvIfscFieldComponent, selector: "fv-ifsc-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvMicrFieldComponent, selector: "fv-micr-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvIbanFieldComponent, selector: "fv-iban-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }] });
3835
+ `, isInline: true, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*{font-family:Poppins}.material-icons{font-family:Material Icons!important;font-size:22px;display:inline-block}.cont{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.validation-message{background-color:#fee;color:#c33;padding:12px 16px;border-radius:8px;margin:10px 0;display:flex;align-items:center;gap:8px;font-size:14px;font-weight:500;border:1px solid #fcc}.export-buttons{display:flex;gap:10px}.export-btn{cursor:pointer;display:flex;align-items:center;gap:5px;transition:all .3s ease;border:none;padding:8px 16px;border-radius:7px;background:#006aff;color:#fff}.export-btn:hover{background:#0045a6;box-shadow:0 4px 8px #00000026}.export-menu-container{position:relative;border-radius:7px}.export-menu{position:absolute;top:100%;right:0;background:#fff;border-radius:4px;box-shadow:0 4px 12px #00000026;margin-top:5px;min-width:180px;z-index:1000}.menu-item{width:100%;color:#000;text-align:left;background:#fff;border:none;cursor:pointer;font-size:14px;transition:background .2s;padding:12px 16px;display:flex;align-items:center;gap:10px}.menu-item:hover{background:#f5f5f5}.query-form-container{background:#f2f2f2;border-radius:8px;padding:5px 10px 10px;margin:auto;box-shadow:0 2px 5px #0000001a;margin-bottom:1rem;overflow:visible}.form-title{font-size:20px;font-weight:700;color:#303030;margin:0;font-family:Poppins}.form-content{display:flex;flex-direction:column;gap:5px;background-color:#fff;padding:10px;border:.5px solid #cfcfcf;border-radius:12px;overflow:visible}.form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;width:100%;box-sizing:border-box;overflow:visible}.form-field{display:flex;flex-direction:column;min-width:0;width:100%;position:relative;overflow:visible;box-sizing:border-box}.view-button{padding:8px 20px;background:#006aff;color:#fff;border:none;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;transition:background-color .2s}.view-button:hover{background:#0045a6}.button-row{display:flex;justify-content:space-between;gap:12px;padding-top:5px;margin-top:5px}.back-button{padding:8px 20px;background-color:#303030;color:#fff;border:none;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;transition:background-color .2s}.back-button:hover{background-color:#2b2b2b}@media (min-width: 1200px) and (max-width: 1400px){.form-row{grid-template-columns:repeat(5,1fr)}}@media (max-width: 1200px){.form-row{grid-template-columns:repeat(3,1fr)}}@media (max-width: 992px){.form-row{grid-template-columns:repeat(2,1fr);gap:12px}}@media (max-width: 768px){.form-row{grid-template-columns:repeat(2,1fr);gap:10px}}@media (max-width: 640px){.form-row{grid-template-columns:1fr;gap:12px}.form-field{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FvEntryFieldComponent, selector: "fv-entry-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "type", "allowAlphabetsOnly", "maxLength"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvDropdownComponent, selector: "fv-dropdown", inputs: ["label", "placeholder", "options", "schema", "control", "disabled"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvNumberFieldComponent, selector: "fv-number-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly", "min", "max", "step"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvDateFieldComponent, selector: "fv-date-field", inputs: ["label", "schema", "control", "disabled", "readonly", "min", "max"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvMonthYearFieldComponent, selector: "fv-month-year-field", inputs: ["label", "schema", "control", "disabled", "readonly", "min", "max"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvFileSelectorComponent, selector: "fv-file-selector", inputs: ["label", "placeholder", "schema", "control", "disabled", "accept", "maxSize"], outputs: ["valueChange", "blur"] }, { kind: "component", type: FvNameCodeComponent, selector: "fv-name-code", inputs: ["label", "placeholder", "options", "schema", "control", "disabled"], outputs: ["selectionChange"] }, { kind: "component", type: FvPhoneFieldComponent, selector: "fv-phone-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvUanFieldComponent, selector: "fv-uan-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvPfFieldComponent, selector: "fv-pf-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvEsiFieldComponent, selector: "fv-esi-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvIfscFieldComponent, selector: "fv-ifsc-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvMicrFieldComponent, selector: "fv-micr-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvIbanFieldComponent, selector: "fv-iban-field", inputs: ["label", "control", "disabled", "schema"], outputs: ["blur", "focus"] }, { kind: "component", type: FvEmailFieldComponent, selector: "fv-email-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly"], outputs: ["valueChange", "blur", "focus"] }, { kind: "component", type: FvPasswordFieldComponent, selector: "fv-password-field", inputs: ["label", "placeholder", "schema", "control", "disabled", "readonly"], outputs: ["valueChange", "blur", "focus"] }] });
3319
3836
  }
3320
3837
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: QueryFormComponent, decorators: [{
3321
3838
  type: Component,
@@ -3336,6 +3853,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3336
3853
  FvIfscFieldComponent,
3337
3854
  FvMicrFieldComponent,
3338
3855
  FvIbanFieldComponent,
3856
+ FvEmailFieldComponent,
3857
+ FvPasswordFieldComponent,
3339
3858
  ], template: `
3340
3859
  <div class="query-form-container">
3341
3860
  <div class="d-flex cont">
@@ -3501,6 +4020,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3501
4020
  <ng-container *ngIf="column.type === 'iban'">
3502
4021
  <fv-iban-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-iban-field>
3503
4022
  </ng-container>
4023
+
4024
+ <ng-container *ngIf="column.type === 'email'">
4025
+ <fv-email-field [label]="column.label" [placeholder]="column.placeholder || ''" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-email-field>
4026
+ </ng-container>
4027
+
4028
+ <ng-container *ngIf="column.type === 'password'">
4029
+ <fv-password-field [label]="column.label" [placeholder]="column.placeholder || ''" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-password-field>
4030
+ </ng-container>
3504
4031
  </div>
3505
4032
  </div>
3506
4033
 
@@ -3527,7 +4054,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3527
4054
  </form>
3528
4055
  </div>
3529
4056
  </div>
3530
- `, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*{font-family:Poppins}.material-icons{font-family:Material Icons!important;font-size:22px;display:inline-block}.cont{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.validation-message{background-color:#fee;color:#c33;padding:12px 16px;border-radius:8px;margin:10px 0;display:flex;align-items:center;gap:8px;font-size:14px;font-weight:500;border:1px solid #fcc}.export-buttons{display:flex;gap:10px}.export-btn{cursor:pointer;display:flex;align-items:center;gap:5px;transition:all .3s ease;border:none;padding:8px 16px;border-radius:7px;background:#006aff;color:#fff}.export-btn:hover{background:#0045a6;box-shadow:0 4px 8px #00000026}.export-menu-container{position:relative;border-radius:7px}.export-menu{position:absolute;top:100%;right:0;background:#fff;border-radius:4px;box-shadow:0 4px 12px #00000026;margin-top:5px;min-width:180px;z-index:1000}.menu-item{width:100%;color:#000;text-align:left;background:#fff;border:none;cursor:pointer;font-size:14px;transition:background .2s;padding:12px 16px;display:flex;align-items:center;gap:10px}.menu-item:hover{background:#f5f5f5}.query-form-container{background:#f2f2f2;border-radius:8px;padding:10px;margin:auto;box-shadow:0 2px 5px #0000001a;margin-bottom:1rem;overflow:visible}.form-title{font-size:20px;font-weight:700;color:#303030;margin:0;font-family:Poppins}.form-content{display:flex;flex-direction:column;gap:5px;background-color:#fff;padding:10px;border:.5px solid #cfcfcf;border-radius:12px;overflow:visible}.form-row{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));justify-content:flex-start;gap:20px;align-items:end;margin-bottom:15px;overflow:visible}.form-field{display:flex;flex-direction:column;width:100%;position:relative;overflow:visible}.view-button{padding:8px 15px;background:#006aff;color:#fff;border:none;border-radius:7px;font-size:14px;font-weight:600;cursor:pointer;transition:background-color .2s}.view-button:hover{background:#0045a6}.button-row{display:flex;justify-content:space-between;gap:10px;padding-top:5px;margin-top:10px;border-top:1px solid #eee}.back-button{padding:8px 15px;background-color:#303030;color:#fff;border:none;border-radius:7px;font-size:14px;font-weight:600;cursor:pointer;transition:background-color .2s}.back-button:hover{background-color:#000}@media (max-width: 768px){.form-row{grid-template-columns:1fr}.button-row{justify-content:center}}\n"] }]
4057
+ `, styles: ["@import\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap\";@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*{font-family:Poppins}.material-icons{font-family:Material Icons!important;font-size:22px;display:inline-block}.cont{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.validation-message{background-color:#fee;color:#c33;padding:12px 16px;border-radius:8px;margin:10px 0;display:flex;align-items:center;gap:8px;font-size:14px;font-weight:500;border:1px solid #fcc}.export-buttons{display:flex;gap:10px}.export-btn{cursor:pointer;display:flex;align-items:center;gap:5px;transition:all .3s ease;border:none;padding:8px 16px;border-radius:7px;background:#006aff;color:#fff}.export-btn:hover{background:#0045a6;box-shadow:0 4px 8px #00000026}.export-menu-container{position:relative;border-radius:7px}.export-menu{position:absolute;top:100%;right:0;background:#fff;border-radius:4px;box-shadow:0 4px 12px #00000026;margin-top:5px;min-width:180px;z-index:1000}.menu-item{width:100%;color:#000;text-align:left;background:#fff;border:none;cursor:pointer;font-size:14px;transition:background .2s;padding:12px 16px;display:flex;align-items:center;gap:10px}.menu-item:hover{background:#f5f5f5}.query-form-container{background:#f2f2f2;border-radius:8px;padding:5px 10px 10px;margin:auto;box-shadow:0 2px 5px #0000001a;margin-bottom:1rem;overflow:visible}.form-title{font-size:20px;font-weight:700;color:#303030;margin:0;font-family:Poppins}.form-content{display:flex;flex-direction:column;gap:5px;background-color:#fff;padding:10px;border:.5px solid #cfcfcf;border-radius:12px;overflow:visible}.form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;width:100%;box-sizing:border-box;overflow:visible}.form-field{display:flex;flex-direction:column;min-width:0;width:100%;position:relative;overflow:visible;box-sizing:border-box}.view-button{padding:8px 20px;background:#006aff;color:#fff;border:none;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;transition:background-color .2s}.view-button:hover{background:#0045a6}.button-row{display:flex;justify-content:space-between;gap:12px;padding-top:5px;margin-top:5px}.back-button{padding:8px 20px;background-color:#303030;color:#fff;border:none;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;transition:background-color .2s}.back-button:hover{background-color:#2b2b2b}@media (min-width: 1200px) and (max-width: 1400px){.form-row{grid-template-columns:repeat(5,1fr)}}@media (max-width: 1200px){.form-row{grid-template-columns:repeat(3,1fr)}}@media (max-width: 992px){.form-row{grid-template-columns:repeat(2,1fr);gap:12px}}@media (max-width: 768px){.form-row{grid-template-columns:repeat(2,1fr);gap:10px}}@media (max-width: 640px){.form-row{grid-template-columns:1fr;gap:12px}.form-field{width:100%}}\n"] }]
3531
4058
  }], ctorParameters: () => [{ type: i2.FormBuilder }], propDecorators: { config: [{
3532
4059
  type: Input
3533
4060
  }], onSubmit: [{
@@ -3541,6 +4068,100 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3541
4068
  args: ['document:click', ['$event']]
3542
4069
  }] } });
3543
4070
 
4071
+ class FvControlsModule {
4072
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
4073
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, imports: [CommonModule,
4074
+ ReactiveFormsModule,
4075
+ FvEntryFieldComponent,
4076
+ FvDateFieldComponent,
4077
+ FvMonthYearFieldComponent,
4078
+ FvNumberFieldComponent,
4079
+ FvCheckboxComponent,
4080
+ FvRadioGroupComponent,
4081
+ FvDropdownComponent,
4082
+ FvFileSelectorComponent,
4083
+ FvImageSelectorComponent,
4084
+ FvRichTextEditorComponent,
4085
+ FvNameCodeComponent,
4086
+ AddUpdateFormComponent,
4087
+ QueryFormComponent,
4088
+ FvEmailFieldComponent,
4089
+ FvPasswordFieldComponent], exports: [FvEntryFieldComponent,
4090
+ FvDateFieldComponent,
4091
+ FvMonthYearFieldComponent,
4092
+ FvNumberFieldComponent,
4093
+ FvCheckboxComponent,
4094
+ FvRadioGroupComponent,
4095
+ FvDropdownComponent,
4096
+ FvFileSelectorComponent,
4097
+ FvImageSelectorComponent,
4098
+ FvRichTextEditorComponent,
4099
+ FvNameCodeComponent,
4100
+ AddUpdateFormComponent,
4101
+ QueryFormComponent,
4102
+ FvEmailFieldComponent,
4103
+ FvPasswordFieldComponent] });
4104
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, imports: [CommonModule,
4105
+ ReactiveFormsModule,
4106
+ FvEntryFieldComponent,
4107
+ FvDateFieldComponent,
4108
+ FvMonthYearFieldComponent,
4109
+ FvNumberFieldComponent,
4110
+ FvCheckboxComponent,
4111
+ FvRadioGroupComponent,
4112
+ FvDropdownComponent,
4113
+ FvFileSelectorComponent,
4114
+ FvImageSelectorComponent,
4115
+ FvRichTextEditorComponent,
4116
+ FvNameCodeComponent,
4117
+ AddUpdateFormComponent,
4118
+ QueryFormComponent,
4119
+ FvEmailFieldComponent,
4120
+ FvPasswordFieldComponent] });
4121
+ }
4122
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, decorators: [{
4123
+ type: NgModule,
4124
+ args: [{
4125
+ declarations: [],
4126
+ imports: [
4127
+ CommonModule,
4128
+ ReactiveFormsModule,
4129
+ FvEntryFieldComponent,
4130
+ FvDateFieldComponent,
4131
+ FvMonthYearFieldComponent,
4132
+ FvNumberFieldComponent,
4133
+ FvCheckboxComponent,
4134
+ FvRadioGroupComponent,
4135
+ FvDropdownComponent,
4136
+ FvFileSelectorComponent,
4137
+ FvImageSelectorComponent,
4138
+ FvRichTextEditorComponent,
4139
+ FvNameCodeComponent,
4140
+ AddUpdateFormComponent,
4141
+ QueryFormComponent,
4142
+ FvEmailFieldComponent,
4143
+ FvPasswordFieldComponent,
4144
+ ],
4145
+ exports: [
4146
+ FvEntryFieldComponent,
4147
+ FvDateFieldComponent,
4148
+ FvMonthYearFieldComponent,
4149
+ FvNumberFieldComponent,
4150
+ FvCheckboxComponent,
4151
+ FvRadioGroupComponent,
4152
+ FvDropdownComponent,
4153
+ FvFileSelectorComponent,
4154
+ FvImageSelectorComponent,
4155
+ FvRichTextEditorComponent,
4156
+ FvNameCodeComponent,
4157
+ AddUpdateFormComponent,
4158
+ QueryFormComponent,
4159
+ FvEmailFieldComponent,
4160
+ FvPasswordFieldComponent,
4161
+ ],
4162
+ }]
4163
+ }] });
4164
+
3544
4165
  /*
3545
4166
  * Public API Surface of fv-controls
3546
4167
  */
@@ -3549,5 +4170,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3549
4170
  * Generated bundle index. Do not edit.
3550
4171
  */
3551
4172
 
3552
- export { AddUpdateFormComponent, FvCheckboxComponent, FvControlsModule, FvDateFieldComponent, FvDropdownComponent, FvEntryFieldComponent, FvEsiFieldComponent, FvFileSelectorComponent, FvIbanFieldComponent, FvIfscFieldComponent, FvImageSelectorComponent, FvMicrFieldComponent, FvMonthYearFieldComponent, FvNameCodeComponent, FvNumberFieldComponent, FvPfFieldComponent, FvPhoneFieldComponent, FvRadioGroupComponent, FvRichTextEditorComponent, FvUanFieldComponent, QueryFormComponent };
4173
+ export { AddUpdateFormComponent, FvCheckboxComponent, FvControlsModule, FvDateFieldComponent, FvDropdownComponent, FvEmailFieldComponent, FvEntryFieldComponent, FvEsiFieldComponent, FvFileSelectorComponent, FvIbanFieldComponent, FvIfscFieldComponent, FvImageSelectorComponent, FvMicrFieldComponent, FvMonthYearFieldComponent, FvNameCodeComponent, FvNumberFieldComponent, FvPasswordFieldComponent, FvPfFieldComponent, FvPhoneFieldComponent, FvRadioGroupComponent, FvRichTextEditorComponent, FvUanFieldComponent, QueryFormComponent };
3553
4174
  //# sourceMappingURL=fovestta2-web-angular.mjs.map