@fovestta2/web-angular 1.0.1 → 1.0.3

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 (32) hide show
  1. package/esm2022/lib/add-update-form/add-update-form.component.mjs +1044 -0
  2. package/esm2022/lib/fv-controls.module.mjs +16 -4
  3. package/esm2022/lib/fv-dropdown/fv-dropdown.component.mjs +116 -17
  4. package/esm2022/lib/fv-entry-field/fv-entry-field.component.mjs +29 -3
  5. package/esm2022/lib/fv-esi-field/fv-esi-field.component.mjs +63 -0
  6. package/esm2022/lib/fv-iban-field/fv-iban-field.component.mjs +63 -0
  7. package/esm2022/lib/fv-ifsc-field/fv-ifsc-field.component.mjs +63 -0
  8. package/esm2022/lib/fv-micr-field/fv-micr-field.component.mjs +63 -0
  9. package/esm2022/lib/fv-name-code/fv-name-code.component.mjs +273 -0
  10. package/esm2022/lib/fv-pf-field/fv-pf-field.component.mjs +63 -0
  11. package/esm2022/lib/fv-phone-field/fv-phone-field.component.mjs +105 -0
  12. package/esm2022/lib/fv-radio-group/fv-radio-group.component.mjs +3 -3
  13. package/esm2022/lib/fv-uan-field/fv-uan-field.component.mjs +65 -0
  14. package/esm2022/lib/query-form/query-form.component.mjs +569 -0
  15. package/esm2022/public-api.mjs +15 -5
  16. package/fesm2022/fovestta2-web-angular.mjs +2492 -88
  17. package/fesm2022/fovestta2-web-angular.mjs.map +1 -1
  18. package/lib/add-update-form/add-update-form.component.d.ts +102 -0
  19. package/lib/fv-controls.module.d.ts +3 -1
  20. package/lib/fv-dropdown/fv-dropdown.component.d.ts +14 -2
  21. package/lib/fv-entry-field/fv-entry-field.component.d.ts +4 -1
  22. package/lib/fv-esi-field/fv-esi-field.component.d.ts +21 -0
  23. package/lib/fv-iban-field/fv-iban-field.component.d.ts +21 -0
  24. package/lib/fv-ifsc-field/fv-ifsc-field.component.d.ts +21 -0
  25. package/lib/fv-micr-field/fv-micr-field.component.d.ts +21 -0
  26. package/lib/fv-name-code/fv-name-code.component.d.ts +41 -0
  27. package/lib/fv-pf-field/fv-pf-field.component.d.ts +21 -0
  28. package/lib/fv-phone-field/fv-phone-field.component.d.ts +25 -0
  29. package/lib/fv-uan-field/fv-uan-field.component.d.ts +21 -0
  30. package/lib/query-form/query-form.component.d.ts +53 -0
  31. package/package.json +2 -2
  32. package/public-api.d.ts +14 -4
@@ -1,12 +1,13 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Component, Input, Output, ViewChild, NgModule } from '@angular/core';
2
+ import { EventEmitter, Component, Input, Output, ViewChild, HostListener, forwardRef, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
5
  import * as i2 from '@angular/forms';
6
- import { ReactiveFormsModule } from '@angular/forms';
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
9
  import { Validator as Validator$1 } from '@fovestta/validation-engine';
10
+ import { distinctUntilChanged } from 'rxjs/operators';
10
11
 
11
12
  class FvEntryFieldComponent {
12
13
  label = '';
@@ -16,6 +17,8 @@ class FvEntryFieldComponent {
16
17
  disabled = false;
17
18
  readonly = false;
18
19
  type = 'text';
20
+ allowAlphabetsOnly = false;
21
+ maxLength = null;
19
22
  valueChange = new EventEmitter();
20
23
  blur = new EventEmitter();
21
24
  focus = new EventEmitter();
@@ -64,6 +67,26 @@ class FvEntryFieldComponent {
64
67
  onFocus(event) {
65
68
  this.focus.emit();
66
69
  }
70
+ onInput(event) {
71
+ const input = event.target;
72
+ let value = input.value;
73
+ if (this.allowAlphabetsOnly) {
74
+ // Remove any non-alphabet characters (keeping spaces if desired, usually names have spaces)
75
+ // Assuming 'alphabets' means [a-zA-Z] and maybe spaces.
76
+ // Strict alphabets: /[^a-zA-Z]/g
77
+ const newValue = value.replace(/[^a-zA-Z ]/g, '');
78
+ if (newValue !== value) {
79
+ value = newValue;
80
+ input.value = value;
81
+ this.control.setValue(value);
82
+ }
83
+ }
84
+ if (this.maxLength && value.length > this.maxLength) {
85
+ value = value.substring(0, this.maxLength);
86
+ input.value = value;
87
+ this.control.setValue(value);
88
+ }
89
+ }
67
90
  isRequired() {
68
91
  return (this.schema?.rules?.some((r) => r.name === 'required' && r.params?.['enabled']) || false);
69
92
  }
@@ -80,11 +103,11 @@ class FvEntryFieldComponent {
80
103
  return errorMessages[this.errorMessage] || this.errorMessage;
81
104
  }
82
105
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEntryFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
83
- 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" }, 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)\" 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: [".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"] }] });
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"] }] });
84
107
  }
85
108
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEntryFieldComponent, decorators: [{
86
109
  type: Component,
87
- 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)\" 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: [".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"] }]
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"] }]
88
111
  }], propDecorators: { label: [{
89
112
  type: Input
90
113
  }], placeholder: [{
@@ -99,6 +122,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
99
122
  type: Input
100
123
  }], type: [{
101
124
  type: Input
125
+ }], allowAlphabetsOnly: [{
126
+ type: Input
127
+ }], maxLength: [{
128
+ type: Input
102
129
  }], valueChange: [{
103
130
  type: Output
104
131
  }], blur: [{
@@ -494,11 +521,11 @@ class FvRadioGroupComponent {
494
521
  return this.control.value === value;
495
522
  }
496
523
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvRadioGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
497
- 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:8px;height:8px;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 }] });
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 }] });
498
525
  }
499
526
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvRadioGroupComponent, decorators: [{
500
527
  type: Component,
501
- 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:8px;height:8px;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"] }]
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"] }]
502
529
  }], propDecorators: { label: [{
503
530
  type: Input
504
531
  }], control: [{
@@ -516,6 +543,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
516
543
  }] } });
517
544
 
518
545
  class FvDropdownComponent {
546
+ el;
519
547
  label = '';
520
548
  placeholder = 'Select an option';
521
549
  options = [];
@@ -525,14 +553,21 @@ class FvDropdownComponent {
525
553
  valueChange = new EventEmitter();
526
554
  blur = new EventEmitter();
527
555
  focus = new EventEmitter();
556
+ searchInput;
528
557
  errorMessage = null;
529
558
  isOpen = false;
530
559
  subscription;
560
+ searchControl = new FormControl('');
561
+ filteredOptions = [];
562
+ constructor(el) {
563
+ this.el = el;
564
+ }
531
565
  ngOnInit() {
532
566
  if (!this.control) {
533
567
  console.error('FvDropdown: control is required');
534
568
  return;
535
569
  }
570
+ this.filteredOptions = this.options;
536
571
  if (!this.schema) {
537
572
  console.warn('FvDropdown: schema is not provided, validation will be skipped');
538
573
  return;
@@ -541,15 +576,48 @@ class FvDropdownComponent {
541
576
  this.subscription = this.control.valueChanges.subscribe((value) => {
542
577
  this.validateValue(value);
543
578
  this.valueChange.emit(value);
579
+ // Sync search text
580
+ const selected = this.options.find(opt => opt.value === value);
581
+ if (selected) {
582
+ this.searchControl.setValue(selected.label, { emitEvent: false });
583
+ }
584
+ else if (!value) {
585
+ this.searchControl.setValue('', { emitEvent: false });
586
+ }
587
+ });
588
+ // Search Control Changes
589
+ this.searchControl.valueChanges.subscribe(term => {
590
+ this.filterOptions(term || '');
544
591
  });
545
592
  // Validate initial value
546
593
  if (this.control.value) {
547
594
  this.validateValue(this.control.value);
595
+ const selected = this.options.find(opt => opt.value === this.control.value);
596
+ if (selected) {
597
+ this.searchControl.setValue(selected.label, { emitEvent: false });
598
+ }
548
599
  }
549
600
  }
550
601
  ngOnDestroy() {
551
602
  this.subscription?.unsubscribe();
552
603
  }
604
+ ngOnChanges(changes) {
605
+ if (changes['options'] && changes['options'].currentValue) {
606
+ this.filteredOptions = this.options;
607
+ // Re-filter if search text exists
608
+ if (this.searchControl.value) {
609
+ this.filterOptions(this.searchControl.value);
610
+ }
611
+ }
612
+ if (changes['disabled']) {
613
+ if (this.disabled) {
614
+ this.searchControl.disable({ emitEvent: false });
615
+ }
616
+ else {
617
+ this.searchControl.enable({ emitEvent: false });
618
+ }
619
+ }
620
+ }
553
621
  validateValue(value) {
554
622
  if (!this.schema)
555
623
  return;
@@ -562,28 +630,79 @@ class FvDropdownComponent {
562
630
  this.control.setErrors(null);
563
631
  }
564
632
  }
633
+ filterOptions(term) {
634
+ if (!term) {
635
+ this.filteredOptions = this.options;
636
+ return;
637
+ }
638
+ const lower = term.toLowerCase();
639
+ this.filteredOptions = this.options.filter(opt => opt.label.toLowerCase().includes(lower));
640
+ }
565
641
  toggleDropdown() {
566
642
  if (!this.disabled) {
567
- this.isOpen = !this.isOpen;
568
- if (this.isOpen) {
569
- this.focus.emit();
643
+ if (!this.isOpen) {
644
+ this.openDropdown();
570
645
  }
646
+ else {
647
+ this.closeDropdown();
648
+ }
649
+ }
650
+ }
651
+ openDropdown() {
652
+ if (!this.disabled) {
653
+ this.isOpen = true;
654
+ this.focus.emit();
655
+ // Filter based on current text, do not reset blindly
656
+ this.filterOptions(this.searchControl.value || '');
657
+ }
658
+ }
659
+ onContainerClick(event) {
660
+ if (this.disabled)
661
+ return;
662
+ // If click is on the arrow or input, let them handle it.
663
+ // But if on the padding of div, focus input.
664
+ const target = event.target;
665
+ if (!target.classList.contains('fv-dropdown-input') && !target.classList.contains('fv-dropdown-arrow')) {
666
+ this.searchInput.nativeElement.focus();
667
+ if (!this.isOpen)
668
+ this.openDropdown();
669
+ }
670
+ }
671
+ closeDropdown() {
672
+ this.isOpen = false;
673
+ // Restore label
674
+ const selected = this.options.find(opt => opt.value === this.control.value);
675
+ if (selected) {
676
+ this.searchControl.setValue(selected.label, { emitEvent: false });
677
+ }
678
+ else {
679
+ if (!this.control.value)
680
+ this.searchControl.setValue('', { emitEvent: false });
571
681
  }
572
682
  }
573
683
  selectOption(option) {
574
684
  this.control.setValue(option.value);
685
+ this.searchControl.setValue(option.label, { emitEvent: false });
575
686
  this.isOpen = false;
687
+ this.searchInput.nativeElement.blur(); // Remove focus from input
576
688
  this.blur.emit();
577
689
  }
578
690
  onBlur() {
579
- // Close dropdown after a small delay to allow click events to fire
580
- setTimeout(() => {
581
- this.isOpen = false;
582
- if (this.control && this.schema) {
583
- this.validateValue(this.control.value);
691
+ // Validation handled on closeDropdown
692
+ }
693
+ onClickOutside(event) {
694
+ if (!this.el.nativeElement.contains(event.target)) {
695
+ if (this.isOpen) {
696
+ this.closeDropdown();
697
+ if (this.control && this.schema) {
698
+ this.validateValue(this.control.value);
699
+ }
700
+ this.blur.emit();
584
701
  }
585
- this.blur.emit();
586
- }, 200);
702
+ }
703
+ }
704
+ onInputFocus() {
705
+ this.openDropdown();
587
706
  }
588
707
  isRequired() {
589
708
  return (this.schema?.rules?.some((r) => r.name === 'required' && r.params?.['enabled']) || false);
@@ -604,13 +723,13 @@ class FvDropdownComponent {
604
723
  isSelected(option) {
605
724
  return option.value === this.control?.value;
606
725
  }
607
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
608
- 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" }, 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)=\"toggleDropdown()\" (blur)=\"onBlur()\" tabindex=\"0\">\r\n <span class=\"fv-dropdown-selected\" [class.fv-dropdown-placeholder]=\"!control.value\">\r\n {{ getSelectedLabel() }}\r\n </span>\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <div *ngFor=\"let option of options\" class=\"fv-dropdown-option\"\r\n [class.fv-dropdown-option-selected]=\"isSelected(option)\" (click)=\"selectOption(option)\">\r\n {{ option.label }}\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;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}\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 }] });
726
+ 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"] }] });
609
728
  }
610
729
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvDropdownComponent, decorators: [{
611
730
  type: Component,
612
- 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)=\"toggleDropdown()\" (blur)=\"onBlur()\" tabindex=\"0\">\r\n <span class=\"fv-dropdown-selected\" [class.fv-dropdown-placeholder]=\"!control.value\">\r\n {{ getSelectedLabel() }}\r\n </span>\r\n <span class=\"fv-dropdown-arrow\" [class.arrow-up]=\"isOpen\">\u25BC</span>\r\n </div>\r\n\r\n <div *ngIf=\"isOpen\" class=\"fv-dropdown-options\">\r\n <div *ngFor=\"let option of options\" class=\"fv-dropdown-option\"\r\n [class.fv-dropdown-option-selected]=\"isSelected(option)\" (click)=\"selectOption(option)\">\r\n {{ option.label }}\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;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}\n"] }]
613
- }], propDecorators: { label: [{
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"] }]
732
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { label: [{
614
733
  type: Input
615
734
  }], placeholder: [{
616
735
  type: Input
@@ -628,6 +747,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
628
747
  type: Output
629
748
  }], focus: [{
630
749
  type: Output
750
+ }], searchInput: [{
751
+ type: ViewChild,
752
+ args: ['searchInput']
753
+ }], onClickOutside: [{
754
+ type: HostListener,
755
+ args: ['document:click', ['$event']]
631
756
  }] } });
632
757
 
633
758
  class FvFileSelectorComponent {
@@ -1068,74 +1193,2353 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1068
1193
  args: ['editor']
1069
1194
  }] } });
1070
1195
 
1071
- class FvControlsModule {
1072
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1073
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, imports: [CommonModule,
1074
- ReactiveFormsModule,
1075
- FvEntryFieldComponent,
1076
- FvDateFieldComponent,
1077
- FvMonthYearFieldComponent,
1078
- FvNumberFieldComponent,
1079
- FvCheckboxComponent,
1080
- FvRadioGroupComponent,
1081
- FvDropdownComponent,
1082
- FvFileSelectorComponent,
1083
- FvImageSelectorComponent,
1084
- FvRichTextEditorComponent], exports: [FvEntryFieldComponent,
1085
- FvDateFieldComponent,
1086
- FvMonthYearFieldComponent,
1087
- FvNumberFieldComponent,
1088
- FvCheckboxComponent,
1089
- FvRadioGroupComponent,
1090
- FvDropdownComponent,
1091
- FvFileSelectorComponent,
1092
- FvImageSelectorComponent,
1093
- FvRichTextEditorComponent] });
1094
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, imports: [CommonModule,
1095
- ReactiveFormsModule,
1096
- FvEntryFieldComponent,
1097
- FvDateFieldComponent,
1098
- FvMonthYearFieldComponent,
1099
- FvNumberFieldComponent,
1100
- FvCheckboxComponent,
1101
- FvRadioGroupComponent,
1102
- FvDropdownComponent,
1103
- FvFileSelectorComponent,
1104
- FvImageSelectorComponent,
1105
- FvRichTextEditorComponent] });
1196
+ class FvNameCodeComponent {
1197
+ label = '';
1198
+ placeholder = '';
1199
+ options = [];
1200
+ schema;
1201
+ control; // Alternative to formControlName
1202
+ disabled = false;
1203
+ selectionChange = new EventEmitter();
1204
+ searchControl = new FormControl('');
1205
+ filteredOptions = [];
1206
+ isOpen = false;
1207
+ // Implementation of ControlValueAccessor
1208
+ onChange = () => { };
1209
+ onTouched = () => { };
1210
+ value = null;
1211
+ ngOnInit() {
1212
+ this.filteredOptions = this.options;
1213
+ // Setup search filter
1214
+ this.searchControl.valueChanges.subscribe(term => {
1215
+ 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
+ });
1225
+ // If control is passed directly
1226
+ if (this.control) {
1227
+ if (this.control.value) {
1228
+ this.writeValue(this.control.value);
1229
+ }
1230
+ this.control.valueChanges.subscribe(val => {
1231
+ this.writeValue(val);
1232
+ });
1233
+ // Sync disabled state
1234
+ if (this.control.disabled !== this.disabled) {
1235
+ this.setDisabledState(this.control.disabled);
1236
+ }
1237
+ }
1238
+ }
1239
+ filterOptions(term) {
1240
+ if (!term) {
1241
+ this.filteredOptions = this.options;
1242
+ return;
1243
+ }
1244
+ const lowerTerm = term.toLowerCase();
1245
+ this.filteredOptions = this.options.filter(opt => opt.code.toLowerCase().includes(lowerTerm) ||
1246
+ opt.name.toLowerCase().includes(lowerTerm));
1247
+ }
1248
+ openDropdown() {
1249
+ if (!this.disabled) {
1250
+ this.isOpen = true;
1251
+ this.filterOptions(this.searchControl.value || '');
1252
+ }
1253
+ }
1254
+ onBlur() {
1255
+ this.onTouched();
1256
+ }
1257
+ closeDropdown() {
1258
+ this.isOpen = false;
1259
+ // Restore display text if not selected?
1260
+ const selectedOption = this.options.find(o => o.value === this.value);
1261
+ if (selectedOption) {
1262
+ this.searchControl.setValue(`${selectedOption.code} - ${selectedOption.name}`, { emitEvent: false });
1263
+ }
1264
+ else {
1265
+ // If no valid value, clear text? or keep partial text?
1266
+ // Usually better to clear if no selection made
1267
+ if (!this.value) {
1268
+ this.searchControl.setValue('', { emitEvent: false });
1269
+ }
1270
+ }
1271
+ this.onTouched();
1272
+ }
1273
+ selectOption(option) {
1274
+ this.value = option.value;
1275
+ this.onChange(this.value);
1276
+ this.searchControl.setValue(`${option.code} - ${option.name}`, { emitEvent: false });
1277
+ this.selectionChange.emit(this.value);
1278
+ this.isOpen = false;
1279
+ }
1280
+ writeValue(value) {
1281
+ this.value = value;
1282
+ const selectedOption = this.options.find(o => o.value === value);
1283
+ if (selectedOption) {
1284
+ this.searchControl.setValue(`${selectedOption.code} - ${selectedOption.name}`, { emitEvent: false });
1285
+ }
1286
+ else {
1287
+ this.searchControl.setValue('', { emitEvent: false });
1288
+ }
1289
+ }
1290
+ registerOnChange(fn) {
1291
+ this.onChange = fn;
1292
+ }
1293
+ registerOnTouched(fn) {
1294
+ this.onTouched = fn;
1295
+ }
1296
+ setDisabledState(isDisabled) {
1297
+ this.disabled = isDisabled;
1298
+ if (isDisabled) {
1299
+ this.searchControl.disable({ emitEvent: false });
1300
+ }
1301
+ else {
1302
+ this.searchControl.enable({ emitEvent: false });
1303
+ }
1304
+ }
1305
+ isInvalid() {
1306
+ if (this.control) {
1307
+ return this.control.invalid && (this.control.dirty || this.control.touched);
1308
+ }
1309
+ return false;
1310
+ }
1311
+ isRequired() {
1312
+ return this.schema?.rules?.some(r => r.name === 'required') || false;
1313
+ }
1314
+ getErrorMessage() {
1315
+ if (!this.control || !this.control.errors || !this.schema)
1316
+ return '';
1317
+ 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
1325
+ if (rule)
1326
+ return this.getReadableError(rule.errorKey);
1327
+ }
1328
+ }
1329
+ // Fallback for standard angular errors
1330
+ if (this.control.hasError('required'))
1331
+ return 'This field is required';
1332
+ return 'Invalid value';
1333
+ }
1334
+ getReadableError(key) {
1335
+ const map = {
1336
+ 'ERR_REQUIRED': 'This field is required',
1337
+ 'ERR_MIN_LENGTH': 'Value is too short',
1338
+ // Add others as needed
1339
+ };
1340
+ return map[key] || 'Invalid value';
1341
+ }
1342
+ onClickOutside(event) {
1343
+ const element = event.target;
1344
+ // Check if click is inside component
1345
+ const clickedInside = event.target.closest('.fv-name-code-container');
1346
+ if (!clickedInside) {
1347
+ this.closeDropdown();
1348
+ }
1349
+ }
1350
+ 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: [
1352
+ {
1353
+ provide: NG_VALUE_ACCESSOR,
1354
+ useExisting: forwardRef(() => FvNameCodeComponent),
1355
+ multi: true
1356
+ }
1357
+ ], ngImport: i0, template: `
1358
+ <div class="fv-name-code-container" (clickOutside)="closeDropdown()">
1359
+ <label *ngIf="label" class="fv-label">
1360
+ {{ label }}
1361
+ <span *ngIf="isRequired()" class="required-asterisk">*</span>
1362
+ </label>
1363
+
1364
+ <div class="search-box-wrapper">
1365
+ <input
1366
+ type="text"
1367
+ class="fv-input"
1368
+ [placeholder]="(searchControl.value || isOpen) ? '' : (placeholder || 'Search by Code or Name')"
1369
+ [formControl]="searchControl"
1370
+ (focus)="openDropdown()"
1371
+ (blur)="onBlur()"
1372
+ [class.error]="isInvalid()"
1373
+ [attr.disabled]="disabled ? true : null"
1374
+ />
1375
+ </div>
1376
+
1377
+ <div class="dropdown-list" *ngIf="isOpen && !disabled">
1378
+ <div
1379
+ class="dropdown-item"
1380
+ *ngFor="let option of filteredOptions"
1381
+ (click)="selectOption(option)"
1382
+ >
1383
+ <span class="code">{{ option.code }}</span>
1384
+ <span class="name">{{ option.name }}</span>
1385
+ </div>
1386
+ <div class="no-results" *ngIf="filteredOptions.length === 0">
1387
+ No results found
1388
+ </div>
1389
+ </div>
1390
+
1391
+ <div *ngIf="isInvalid()" class="error-message">
1392
+ {{ getErrorMessage() }}
1393
+ </div>
1394
+ </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"] }] });
1106
1396
  }
1107
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvControlsModule, decorators: [{
1108
- type: NgModule,
1109
- args: [{
1110
- declarations: [],
1111
- imports: [
1112
- CommonModule,
1113
- ReactiveFormsModule,
1114
- FvEntryFieldComponent,
1115
- FvDateFieldComponent,
1116
- FvMonthYearFieldComponent,
1117
- FvNumberFieldComponent,
1118
- FvCheckboxComponent,
1119
- FvRadioGroupComponent,
1120
- FvDropdownComponent,
1121
- FvFileSelectorComponent,
1122
- FvImageSelectorComponent,
1123
- FvRichTextEditorComponent,
1124
- ],
1125
- exports: [
1126
- FvEntryFieldComponent,
1127
- FvDateFieldComponent,
1128
- FvMonthYearFieldComponent,
1129
- FvNumberFieldComponent,
1130
- FvCheckboxComponent,
1131
- FvRadioGroupComponent,
1132
- FvDropdownComponent,
1133
- FvFileSelectorComponent,
1134
- FvImageSelectorComponent,
1135
- FvRichTextEditorComponent,
1136
- ],
1137
- }]
1138
- }] });
1397
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvNameCodeComponent, decorators: [{
1398
+ type: Component,
1399
+ args: [{ selector: 'fv-name-code', standalone: true, imports: [CommonModule, ReactiveFormsModule], template: `
1400
+ <div class="fv-name-code-container" (clickOutside)="closeDropdown()">
1401
+ <label *ngIf="label" class="fv-label">
1402
+ {{ label }}
1403
+ <span *ngIf="isRequired()" class="required-asterisk">*</span>
1404
+ </label>
1405
+
1406
+ <div class="search-box-wrapper">
1407
+ <input
1408
+ type="text"
1409
+ class="fv-input"
1410
+ [placeholder]="(searchControl.value || isOpen) ? '' : (placeholder || 'Search by Code or Name')"
1411
+ [formControl]="searchControl"
1412
+ (focus)="openDropdown()"
1413
+ (blur)="onBlur()"
1414
+ [class.error]="isInvalid()"
1415
+ [attr.disabled]="disabled ? true : null"
1416
+ />
1417
+ </div>
1418
+
1419
+ <div class="dropdown-list" *ngIf="isOpen && !disabled">
1420
+ <div
1421
+ class="dropdown-item"
1422
+ *ngFor="let option of filteredOptions"
1423
+ (click)="selectOption(option)"
1424
+ >
1425
+ <span class="code">{{ option.code }}</span>
1426
+ <span class="name">{{ option.name }}</span>
1427
+ </div>
1428
+ <div class="no-results" *ngIf="filteredOptions.length === 0">
1429
+ No results found
1430
+ </div>
1431
+ </div>
1432
+
1433
+ <div *ngIf="isInvalid()" class="error-message">
1434
+ {{ getErrorMessage() }}
1435
+ </div>
1436
+ </div>
1437
+ `, providers: [
1438
+ {
1439
+ provide: NG_VALUE_ACCESSOR,
1440
+ useExisting: forwardRef(() => FvNameCodeComponent),
1441
+ multi: true
1442
+ }
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"] }]
1444
+ }], propDecorators: { label: [{
1445
+ type: Input
1446
+ }], placeholder: [{
1447
+ type: Input
1448
+ }], options: [{
1449
+ type: Input
1450
+ }], schema: [{
1451
+ type: Input
1452
+ }], control: [{
1453
+ type: Input
1454
+ }], disabled: [{
1455
+ type: Input
1456
+ }], selectionChange: [{
1457
+ type: Output
1458
+ }], onClickOutside: [{
1459
+ type: HostListener,
1460
+ args: ['document:click', ['$event']]
1461
+ }] } });
1462
+
1463
+ class FvPhoneFieldComponent {
1464
+ label = '';
1465
+ control;
1466
+ disabled = false;
1467
+ schema;
1468
+ blur = new EventEmitter();
1469
+ focus = new EventEmitter();
1470
+ countryCode = '+91';
1471
+ countryCodes = [
1472
+ '+1', '+7', '+20', '+27', '+30', '+31', '+32', '+33', '+34', '+36', '+39', '+40', '+41', '+43', '+44', '+45', '+46', '+47',
1473
+ '+48', '+49', '+51', '+52', '+53', '+54', '+55', '+56', '+57', '+58', '+60', '+61', '+62', '+63', '+64', '+65', '+66',
1474
+ '+81', '+82', '+84', '+86', '+90', '+91', '+92', '+93', '+94', '+95', '+98', '+212', '+213', '+216', '+218', '+220',
1475
+ '+221', '+222', '+223', '+224', '+225', '+226', '+227', '+228', '+229', '+230', '+231', '+232', '+233', '+234', '+235',
1476
+ '+236', '+237', '+238', '+239', '+240', '+241', '+242', '+243', '+244', '+245', '+246', '+248', '+249', '+250', '+251',
1477
+ '+252', '+253', '+254', '+255', '+256', '+257', '+258', '+260', '+261', '+262', '+263', '+264', '+265', '+266', '+267',
1478
+ '+268', '+269', '+290', '+291', '+297', '+298', '+299', '+350', '+351', '+352', '+353', '+354', '+355', '+356', '+357',
1479
+ '+358', '+359', '+370', '+371', '+372', '+373', '+374', '+375', '+376', '+377', '+378', '+380', '+381', '+382', '+383',
1480
+ '+385', '+386', '+387', '+389', '+420', '+421', '+423', '+500', '+501', '+502', '+503', '+504', '+505', '+506', '+507',
1481
+ '+508', '+509', '+590', '+591', '+592', '+593', '+594', '+595', '+596', '+597', '+598', '+599', '+670', '+672', '+673',
1482
+ '+674', '+675', '+676', '+677', '+678', '+679', '+680', '+681', '+682', '+683', '+685', '+686', '+687', '+688', '+689',
1483
+ '+690', '+691', '+692', '+850', '+852', '+853', '+855', '+856', '+880', '+886', '+960', '+961', '+962', '+963', '+964',
1484
+ '+965', '+966', '+967', '+968', '+970', '+971', '+972', '+973', '+974', '+975', '+976', '+977', '+992', '+993', '+994',
1485
+ '+995', '+996', '+998'
1486
+ ];
1487
+ errorMessage = null;
1488
+ subscription;
1489
+ ngOnInit() {
1490
+ if (!this.control) {
1491
+ console.error('FvPhoneField: control is required');
1492
+ return;
1493
+ }
1494
+ // Subscribe to value changes
1495
+ this.subscription = this.control.valueChanges.subscribe((value) => {
1496
+ this.validateValue(value);
1497
+ });
1498
+ if (this.control.value) {
1499
+ this.validateValue(this.control.value);
1500
+ }
1501
+ }
1502
+ ngOnDestroy() {
1503
+ this.subscription?.unsubscribe();
1504
+ }
1505
+ onInput(event) {
1506
+ const input = event.target;
1507
+ let value = input.value;
1508
+ // Allow only numbers
1509
+ const numericValue = value.replace(/[^0-9]/g, '');
1510
+ // Limit to 10 digits
1511
+ const truncatedValue = numericValue.substring(0, 10);
1512
+ if (value !== truncatedValue) {
1513
+ input.value = truncatedValue;
1514
+ this.control.setValue(truncatedValue);
1515
+ }
1516
+ }
1517
+ validateValue(value) {
1518
+ if (!this.schema)
1519
+ return;
1520
+ const result = Validator.validate(value, this.schema);
1521
+ this.errorMessage = result.errorKey;
1522
+ if (!result.isValid && result.errorKey) {
1523
+ this.control.setErrors({ [result.errorKey]: true });
1524
+ }
1525
+ else {
1526
+ this.control.setErrors(null);
1527
+ }
1528
+ }
1529
+ onBlur() {
1530
+ this.blur.emit();
1531
+ if (this.control && this.schema) {
1532
+ this.validateValue(this.control.value);
1533
+ }
1534
+ }
1535
+ onFocus() {
1536
+ this.focus.emit();
1537
+ }
1538
+ isRequired() {
1539
+ return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false;
1540
+ }
1541
+ 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"] }] });
1543
+ }
1544
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvPhoneFieldComponent, decorators: [{
1545
+ 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"] }]
1547
+ }], propDecorators: { label: [{
1548
+ type: Input
1549
+ }], control: [{
1550
+ type: Input
1551
+ }], disabled: [{
1552
+ type: Input
1553
+ }], schema: [{
1554
+ type: Input
1555
+ }], blur: [{
1556
+ type: Output
1557
+ }], focus: [{
1558
+ type: Output
1559
+ }] } });
1560
+
1561
+ class FvUanFieldComponent {
1562
+ label = 'UAN Number';
1563
+ control;
1564
+ disabled = false;
1565
+ schema;
1566
+ blur = new EventEmitter();
1567
+ focus = new EventEmitter();
1568
+ errorMessage = null;
1569
+ subscription;
1570
+ ngOnInit() {
1571
+ if (!this.control)
1572
+ return;
1573
+ this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1574
+ }
1575
+ ngOnDestroy() { this.subscription?.unsubscribe(); }
1576
+ onInput(event) {
1577
+ const input = event.target;
1578
+ let value = input.value;
1579
+ const numericValue = value.replace(/[^0-9]/g, ''); // Numbers only
1580
+ const truncatedValue = numericValue.substring(0, 12); // UAN is 12 digits
1581
+ if (value !== truncatedValue) {
1582
+ input.value = truncatedValue;
1583
+ this.control.setValue(truncatedValue);
1584
+ }
1585
+ }
1586
+ validateValue(value) {
1587
+ if (!this.schema)
1588
+ return;
1589
+ const result = Validator.validate(value, this.schema);
1590
+ this.errorMessage = result.errorKey;
1591
+ if (!result.isValid && result.errorKey)
1592
+ this.control.setErrors({ [result.errorKey]: true });
1593
+ else
1594
+ this.control.setErrors(null);
1595
+ }
1596
+ isRequired() {
1597
+ return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false;
1598
+ }
1599
+ 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"] }] });
1601
+ }
1602
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvUanFieldComponent, decorators: [{
1603
+ 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"] }]
1605
+ }], propDecorators: { label: [{
1606
+ type: Input
1607
+ }], control: [{
1608
+ type: Input
1609
+ }], disabled: [{
1610
+ type: Input
1611
+ }], schema: [{
1612
+ type: Input
1613
+ }], blur: [{
1614
+ type: Output
1615
+ }], focus: [{
1616
+ type: Output
1617
+ }] } });
1618
+
1619
+ class FvPfFieldComponent {
1620
+ label = 'PF Number';
1621
+ control;
1622
+ disabled = false;
1623
+ schema;
1624
+ blur = new EventEmitter();
1625
+ focus = new EventEmitter();
1626
+ errorMessage = null;
1627
+ subscription;
1628
+ ngOnInit() {
1629
+ if (!this.control)
1630
+ return;
1631
+ this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1632
+ }
1633
+ ngOnDestroy() { this.subscription?.unsubscribe(); }
1634
+ onInput(event) {
1635
+ const input = event.target;
1636
+ let value = input.value;
1637
+ // Allow Alphanumeric and slash
1638
+ const formatted = value.replace(/[^a-zA-Z0-9/]/g, '').toUpperCase();
1639
+ if (value !== formatted) {
1640
+ input.value = formatted;
1641
+ this.control.setValue(formatted);
1642
+ }
1643
+ }
1644
+ validateValue(value) {
1645
+ if (!this.schema)
1646
+ return;
1647
+ const result = Validator.validate(value, this.schema);
1648
+ this.errorMessage = result.errorKey;
1649
+ if (!result.isValid && result.errorKey)
1650
+ this.control.setErrors({ [result.errorKey]: true });
1651
+ else
1652
+ this.control.setErrors(null);
1653
+ }
1654
+ isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1655
+ 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"] }] });
1657
+ }
1658
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvPfFieldComponent, decorators: [{
1659
+ 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"] }]
1661
+ }], propDecorators: { label: [{
1662
+ type: Input
1663
+ }], control: [{
1664
+ type: Input
1665
+ }], disabled: [{
1666
+ type: Input
1667
+ }], schema: [{
1668
+ type: Input
1669
+ }], blur: [{
1670
+ type: Output
1671
+ }], focus: [{
1672
+ type: Output
1673
+ }] } });
1674
+
1675
+ class FvEsiFieldComponent {
1676
+ label = 'ESI Number';
1677
+ control;
1678
+ disabled = false;
1679
+ schema;
1680
+ blur = new EventEmitter();
1681
+ focus = new EventEmitter();
1682
+ errorMessage = null;
1683
+ subscription;
1684
+ ngOnInit() {
1685
+ if (!this.control)
1686
+ return;
1687
+ this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1688
+ }
1689
+ ngOnDestroy() { this.subscription?.unsubscribe(); }
1690
+ onInput(event) {
1691
+ const input = event.target;
1692
+ let value = input.value;
1693
+ const numericValue = value.replace(/[^0-9]/g, '');
1694
+ const truncatedValue = numericValue.substring(0, 17);
1695
+ if (value !== truncatedValue) {
1696
+ input.value = truncatedValue;
1697
+ this.control.setValue(truncatedValue);
1698
+ }
1699
+ }
1700
+ validateValue(value) {
1701
+ if (!this.schema)
1702
+ return;
1703
+ const result = Validator.validate(value, this.schema);
1704
+ this.errorMessage = result.errorKey;
1705
+ if (!result.isValid && result.errorKey)
1706
+ this.control.setErrors({ [result.errorKey]: true });
1707
+ else
1708
+ this.control.setErrors(null);
1709
+ }
1710
+ isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1711
+ 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"] }] });
1713
+ }
1714
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvEsiFieldComponent, decorators: [{
1715
+ 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"] }]
1717
+ }], propDecorators: { label: [{
1718
+ type: Input
1719
+ }], control: [{
1720
+ type: Input
1721
+ }], disabled: [{
1722
+ type: Input
1723
+ }], schema: [{
1724
+ type: Input
1725
+ }], blur: [{
1726
+ type: Output
1727
+ }], focus: [{
1728
+ type: Output
1729
+ }] } });
1730
+
1731
+ class FvIfscFieldComponent {
1732
+ label = 'IFSC Code';
1733
+ control;
1734
+ disabled = false;
1735
+ schema;
1736
+ blur = new EventEmitter();
1737
+ focus = new EventEmitter();
1738
+ errorMessage = null;
1739
+ subscription;
1740
+ ngOnInit() {
1741
+ if (!this.control)
1742
+ return;
1743
+ this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1744
+ }
1745
+ ngOnDestroy() { this.subscription?.unsubscribe(); }
1746
+ onInput(event) {
1747
+ const input = event.target;
1748
+ let value = input.value;
1749
+ const formatted = value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
1750
+ const truncated = formatted.substring(0, 11);
1751
+ if (value !== truncated) {
1752
+ input.value = truncated;
1753
+ this.control.setValue(truncated);
1754
+ }
1755
+ }
1756
+ validateValue(value) {
1757
+ if (!this.schema)
1758
+ return;
1759
+ const result = Validator.validate(value, this.schema);
1760
+ this.errorMessage = result.errorKey;
1761
+ if (!result.isValid && result.errorKey)
1762
+ this.control.setErrors({ [result.errorKey]: true });
1763
+ else
1764
+ this.control.setErrors(null);
1765
+ }
1766
+ isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1767
+ 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"] }] });
1769
+ }
1770
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvIfscFieldComponent, decorators: [{
1771
+ 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"] }]
1773
+ }], propDecorators: { label: [{
1774
+ type: Input
1775
+ }], control: [{
1776
+ type: Input
1777
+ }], disabled: [{
1778
+ type: Input
1779
+ }], schema: [{
1780
+ type: Input
1781
+ }], blur: [{
1782
+ type: Output
1783
+ }], focus: [{
1784
+ type: Output
1785
+ }] } });
1786
+
1787
+ class FvMicrFieldComponent {
1788
+ label = 'MICR Code';
1789
+ control;
1790
+ disabled = false;
1791
+ schema;
1792
+ blur = new EventEmitter();
1793
+ focus = new EventEmitter();
1794
+ errorMessage = null;
1795
+ subscription;
1796
+ ngOnInit() {
1797
+ if (!this.control)
1798
+ return;
1799
+ this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1800
+ }
1801
+ ngOnDestroy() { this.subscription?.unsubscribe(); }
1802
+ onInput(event) {
1803
+ const input = event.target;
1804
+ let value = input.value;
1805
+ const numericValue = value.replace(/[^0-9]/g, '');
1806
+ const truncatedValue = numericValue.substring(0, 9);
1807
+ if (value !== truncatedValue) {
1808
+ input.value = truncatedValue;
1809
+ this.control.setValue(truncatedValue);
1810
+ }
1811
+ }
1812
+ validateValue(value) {
1813
+ if (!this.schema)
1814
+ return;
1815
+ const result = Validator.validate(value, this.schema);
1816
+ this.errorMessage = result.errorKey;
1817
+ if (!result.isValid && result.errorKey)
1818
+ this.control.setErrors({ [result.errorKey]: true });
1819
+ else
1820
+ this.control.setErrors(null);
1821
+ }
1822
+ isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1823
+ 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"] }] });
1825
+ }
1826
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvMicrFieldComponent, decorators: [{
1827
+ 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"] }]
1829
+ }], propDecorators: { label: [{
1830
+ type: Input
1831
+ }], control: [{
1832
+ type: Input
1833
+ }], disabled: [{
1834
+ type: Input
1835
+ }], schema: [{
1836
+ type: Input
1837
+ }], blur: [{
1838
+ type: Output
1839
+ }], focus: [{
1840
+ type: Output
1841
+ }] } });
1842
+
1843
+ class FvIbanFieldComponent {
1844
+ label = 'IBAN Number';
1845
+ control;
1846
+ disabled = false;
1847
+ schema;
1848
+ blur = new EventEmitter();
1849
+ focus = new EventEmitter();
1850
+ errorMessage = null;
1851
+ subscription;
1852
+ ngOnInit() {
1853
+ if (!this.control)
1854
+ return;
1855
+ this.subscription = this.control.valueChanges.subscribe((value) => this.validateValue(value));
1856
+ }
1857
+ ngOnDestroy() { this.subscription?.unsubscribe(); }
1858
+ onInput(event) {
1859
+ const input = event.target;
1860
+ let value = input.value;
1861
+ const formatted = value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
1862
+ const truncated = formatted.substring(0, 34);
1863
+ if (value !== truncated) {
1864
+ input.value = truncated;
1865
+ this.control.setValue(truncated);
1866
+ }
1867
+ }
1868
+ validateValue(value) {
1869
+ if (!this.schema)
1870
+ return;
1871
+ const result = Validator.validate(value, this.schema);
1872
+ this.errorMessage = result.errorKey;
1873
+ if (!result.isValid && result.errorKey)
1874
+ this.control.setErrors({ [result.errorKey]: true });
1875
+ else
1876
+ this.control.setErrors(null);
1877
+ }
1878
+ isRequired() { return this.schema?.rules?.some(r => r.name === 'required' && r.params?.['enabled']) || false; }
1879
+ 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"] }] });
1881
+ }
1882
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvIbanFieldComponent, decorators: [{
1883
+ 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"] }]
1885
+ }], propDecorators: { label: [{
1886
+ type: Input
1887
+ }], control: [{
1888
+ type: Input
1889
+ }], disabled: [{
1890
+ type: Input
1891
+ }], schema: [{
1892
+ type: Input
1893
+ }], blur: [{
1894
+ type: Output
1895
+ }], focus: [{
1896
+ type: Output
1897
+ }] } });
1898
+
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
+ }
1916
+ ngOnInit() {
1917
+ this.initializeForm();
1918
+ }
1919
+ ngAfterViewInit() {
1920
+ // Lifecycle hook - can be used for datepicker initialization if needed
1921
+ }
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)`;
1926
+ }
1927
+ getControl(name) {
1928
+ return this.form.get(name);
1929
+ }
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
+ });
1969
+ errorPriority.push('maxLength');
1970
+ break;
1971
+ case 'pattern':
1972
+ rules.push({
1973
+ name: 'regex',
1974
+ params: { pattern: v.value },
1975
+ errorKey: 'ERR_REGEX_MISMATCH',
1976
+ });
1977
+ errorPriority.push('regex');
1978
+ break;
1979
+ case 'min':
1980
+ rules.push({
1981
+ name: 'min',
1982
+ params: { value: v.value },
1983
+ errorKey: 'ERR_MIN_VALUE',
1984
+ });
1985
+ errorPriority.push('min');
1986
+ break;
1987
+ case 'max':
1988
+ rules.push({
1989
+ name: 'max',
1990
+ params: { value: v.value },
1991
+ errorKey: 'ERR_MAX_VALUE',
1992
+ });
1993
+ errorPriority.push('max');
1994
+ break;
1995
+ }
1996
+ });
1997
+ }
1998
+ // Map 'name-code' to 'Dropdown' or similar for validation schema purposes if needed
1999
+ let controlType = column.type;
2000
+ if (column.type === 'name-code') {
2001
+ controlType = 'select'; // Treat as select for schema lookup if library expects 'select' or 'Dropdown'
2002
+ }
2003
+ return {
2004
+ controlType: controlType,
2005
+ errorPriority: errorPriority,
2006
+ rules: rules,
2007
+ };
2008
+ }
2009
+ isImageField(column) {
2010
+ return (column.type === 'file' &&
2011
+ (column.accept?.startsWith('image') || column.filePreview === true));
2012
+ }
2013
+ initializeForm() {
2014
+ this.submitted = false;
2015
+ const formGroupConfig = {};
2016
+ this.config.sections.forEach((section) => {
2017
+ section.fields.forEach((column) => {
2018
+ let initialValue = column.value || '';
2019
+ // Format month-year fields to YYYY-MM format
2020
+ if (column.type === 'month-year' && initialValue) {
2021
+ initialValue = this.formatMonthYearValue(initialValue);
2022
+ }
2023
+ formGroupConfig[column.name] = [
2024
+ { value: initialValue, disabled: column.disabled || false },
2025
+ null, // We'll set validators after form creation
2026
+ ];
2027
+ // If it's a file field with an existing value, set the preview
2028
+ if (column.type === 'file' && column.value) {
2029
+ this.filePreviews.set(column.name, column.value);
2030
+ // Extract filename from URL or base64
2031
+ const fileName = this.extractFileName(column.value);
2032
+ if (fileName) {
2033
+ this.fileNames.set(column.name, fileName);
2034
+ }
2035
+ }
2036
+ // Initialize search display for name-code fields - No longer needed as FvNameCode handles display internally
2037
+ /* if (column.type === 'name-code' && initialValue && column.options) {
2038
+ // Logic moved to component
2039
+ } */
2040
+ });
2041
+ });
2042
+ this.form = this.fb.group(formGroupConfig);
2043
+ this.config.sections.forEach((section) => {
2044
+ section.fields.forEach((column) => {
2045
+ const validators = this.buildValidators(column.validations, this.form);
2046
+ if (validators.length > 0) {
2047
+ this.form.get(column.name)?.setValidators(validators);
2048
+ this.form.get(column.name)?.updateValueAndValidity();
2049
+ }
2050
+ });
2051
+ });
2052
+ // Subscribe to value changes for all fields to trigger onChange handlers
2053
+ Object.keys(this.form.controls).forEach((key) => {
2054
+ const control = this.form.get(key);
2055
+ if (control) {
2056
+ const subscription = control.valueChanges
2057
+ .pipe(distinctUntilChanged())
2058
+ .subscribe((value) => {
2059
+ const column = this.getColumnByName(key);
2060
+ if (column?.onChange) {
2061
+ column.onChange(value, this.form);
2062
+ }
2063
+ });
2064
+ this.valueChangeSubscriptions.push(subscription);
2065
+ }
2066
+ });
2067
+ }
2068
+ ngOnDestroy() {
2069
+ // Clean up all subscriptions to prevent memory leaks
2070
+ this.valueChangeSubscriptions.forEach((sub) => sub.unsubscribe());
2071
+ this.valueChangeSubscriptions = [];
2072
+ }
2073
+ handleFieldChange(fieldName, eventValue) {
2074
+ const column = this.getColumnByName(fieldName);
2075
+ const formControl = this.form.get(fieldName);
2076
+ // Format month-year fields (especially expiryDate) to YYYY-MM
2077
+ if (column?.type === 'month-year' && eventValue) {
2078
+ const formattedValue = this.formatMonthYearValue(eventValue);
2079
+ if (formControl && formattedValue !== eventValue) {
2080
+ formControl.setValue(formattedValue, { emitEvent: false });
2081
+ eventValue = formattedValue;
2082
+ }
2083
+ }
2084
+ if (column?.onChange) {
2085
+ // Use the event value directly (what the user just selected/typed)
2086
+ // This ensures we have the correct value even if form control hasn't updated yet
2087
+ const valueToPass = eventValue !== undefined ? eventValue : this.form.get(fieldName)?.value;
2088
+ const onChangeFn = column.onChange; // Store the function reference
2089
+ // Store the selected value - this is what the user chose
2090
+ const selectedValue = valueToPass;
2091
+ // Ensure the form control has the selected value before calling onChange
2092
+ if (formControl && selectedValue !== undefined) {
2093
+ if (formControl.value !== selectedValue) {
2094
+ formControl.setValue(selectedValue, { emitEvent: false });
2095
+ }
2096
+ }
2097
+ // Call onChange with the selected value
2098
+ if (onChangeFn) {
2099
+ onChangeFn(selectedValue, this.form);
2100
+ }
2101
+ // Restore the value for the field that triggered the change if it was cleared by onChange
2102
+ // This is critical: if onChange clears the field that was just changed, we restore it
2103
+ // Only restore if we had a non-empty value (empty string, null, undefined are not restored)
2104
+ if (formControl &&
2105
+ selectedValue !== undefined &&
2106
+ selectedValue !== null &&
2107
+ selectedValue !== '') {
2108
+ // Use setTimeout with 0 delay to run after any synchronous operations in onChange
2109
+ setTimeout(() => {
2110
+ // Check if the value was cleared or changed
2111
+ const currentValue = formControl.value;
2112
+ // If the value doesn't match what was selected, restore it
2113
+ // This handles the case where onChange cleared the field unintentionally
2114
+ if (currentValue !== selectedValue) {
2115
+ formControl.setValue(selectedValue, { emitEvent: false });
2116
+ }
2117
+ }, 0);
2118
+ }
2119
+ }
2120
+ }
2121
+ formatMonthYearValue(value) {
2122
+ if (!value)
2123
+ return value;
2124
+ // Normalize to YYYY-MM
2125
+ if (value.match(/^\d{2}-\d{4}$/)) {
2126
+ const [month, year] = value.split('-');
2127
+ return `${year}-${month}`;
2128
+ }
2129
+ // If already in YYYY-MM format, return as is
2130
+ return value;
2131
+ }
2132
+ parseMonthYearValue(value) {
2133
+ if (!value)
2134
+ return value;
2135
+ // Display and picker both use YYYY-MM; normalize MM-YYYY if present
2136
+ if (value.match(/^\d{2}-\d{4}$/)) {
2137
+ const [month, year] = value.split('-');
2138
+ return `${year}-${month}`;
2139
+ }
2140
+ return value;
2141
+ }
2142
+ handleMonthYearChange(fieldName, value) {
2143
+ // Format the input value to YYYY-MM format
2144
+ let formattedValue = value;
2145
+ // If it's in MM-YYYY format, convert to YYYY-MM
2146
+ if (formattedValue.match(/^\d{2}-\d{4}$/)) {
2147
+ const [month, year] = formattedValue.split('-');
2148
+ formattedValue = `${year}-${month}`;
2149
+ }
2150
+ // If it's in YYYYMM format (no dash), convert to YYYY-MM
2151
+ else if (formattedValue.match(/^\d{6}$/)) {
2152
+ const year = formattedValue.substring(0, 4);
2153
+ const month = formattedValue.substring(4, 6);
2154
+ formattedValue = `${year}-${month}`;
2155
+ }
2156
+ // If it's already in YYYY-MM format, leave as is
2157
+ else if (formattedValue.match(/^\d{4}-\d{2}$/)) {
2158
+ // Already in correct format
2159
+ }
2160
+ // If user is typing, allow partial input
2161
+ else if (formattedValue.match(/^\d{1,6}$/)) {
2162
+ // Allow partial input while typing
2163
+ }
2164
+ const formControl = this.form.get(fieldName);
2165
+ if (formControl && formattedValue !== value) {
2166
+ formControl.setValue(formattedValue, { emitEvent: false });
2167
+ }
2168
+ this.handleFieldChange(fieldName, formattedValue);
2169
+ }
2170
+ handleMonthYearBlur(fieldName) {
2171
+ const formControl = this.form.get(fieldName);
2172
+ if (!formControl)
2173
+ return;
2174
+ const value = formControl.value || '';
2175
+ // Ensure the value is in YYYY-MM format on blur
2176
+ if (value && !value.match(/^\d{4}-\d{2}$/)) {
2177
+ // Try to parse and format
2178
+ const formatted = this.formatMonthYearValue(value);
2179
+ if (formatted !== value) {
2180
+ formControl.setValue(formatted, { emitEvent: false });
2181
+ }
2182
+ }
2183
+ }
2184
+ handleMonthYearPickerChange(fieldName, value) {
2185
+ // Month picker outputs YYYY-MM; just normalize
2186
+ const formattedValue = this.formatMonthYearValue(value);
2187
+ const formControl = this.form.get(fieldName);
2188
+ if (formControl) {
2189
+ formControl.setValue(formattedValue, { emitEvent: false });
2190
+ this.handleFieldChange(fieldName, formattedValue);
2191
+ }
2192
+ }
2193
+ getMonthYearPickerValue(fieldName) {
2194
+ const formControl = this.form.get(fieldName);
2195
+ if (!formControl)
2196
+ return '';
2197
+ const value = formControl.value || '';
2198
+ // Display and picker both expect YYYY-MM
2199
+ return this.parseMonthYearValue(value);
2200
+ }
2201
+ openMonthPicker(fieldName) {
2202
+ const monthInput = document.getElementById(fieldName + '_picker');
2203
+ if (monthInput && monthInput.type === 'month') {
2204
+ // Update the picker value before opening
2205
+ const currentValue = this.getMonthYearPickerValue(fieldName);
2206
+ if (currentValue) {
2207
+ monthInput.value = currentValue;
2208
+ }
2209
+ // Try modern showPicker API first, fallback to click
2210
+ if (monthInput.showPicker) {
2211
+ monthInput.showPicker();
2212
+ }
2213
+ else {
2214
+ monthInput.focus();
2215
+ monthInput.click();
2216
+ }
2217
+ }
2218
+ }
2219
+ getColumnByName(name) {
2220
+ return this.config.sections
2221
+ .flatMap((s) => s.fields)
2222
+ .find((c) => c.name === name);
2223
+ }
2224
+ getFileFields(fields) {
2225
+ return fields.filter((f) => f.type === 'file');
2226
+ }
2227
+ getNonFileFields(fields) {
2228
+ return fields.filter((f) => f.type !== 'file');
2229
+ }
2230
+ togglePasswordVisibility(fieldName) {
2231
+ const current = this.passwordVisibility.get(fieldName) || false;
2232
+ this.passwordVisibility.set(fieldName, !current);
2233
+ }
2234
+ hasRequiredValidation(column) {
2235
+ return column.validations?.some((v) => v.type === 'required') || false;
2236
+ }
2237
+ isPasswordVisible(fieldName) {
2238
+ return this.passwordVisibility.get(fieldName) || false;
2239
+ }
2240
+ buildValidators(validations, formGroup) {
2241
+ if (!validations)
2242
+ return [];
2243
+ const validators = [];
2244
+ validations.forEach((validation) => {
2245
+ switch (validation.type) {
2246
+ case 'required':
2247
+ validators.push(Validators.required);
2248
+ break;
2249
+ case 'email':
2250
+ validators.push(Validators.email);
2251
+ break;
2252
+ case 'minLength':
2253
+ validators.push(Validators.minLength(validation.value));
2254
+ break;
2255
+ case 'maxLength':
2256
+ validators.push(Validators.maxLength(validation.value));
2257
+ break;
2258
+ case 'min':
2259
+ validators.push(Validators.min(validation.value));
2260
+ break;
2261
+ case 'max':
2262
+ validators.push(Validators.max(validation.value));
2263
+ break;
2264
+ case 'pattern':
2265
+ validators.push(Validators.pattern(validation.value));
2266
+ break;
2267
+ case 'custom':
2268
+ if (validation.validator) {
2269
+ validators.push((control) => {
2270
+ const isValid = validation.validator(control.value, formGroup);
2271
+ return isValid ? null : { custom: true };
2272
+ });
2273
+ }
2274
+ break;
2275
+ }
2276
+ });
2277
+ return validators;
2278
+ }
2279
+ triggerFileUpload(fieldName) {
2280
+ document.getElementById('fileInput_' + fieldName)?.click();
2281
+ }
2282
+ openTimePicker(fieldName) {
2283
+ const timeInput = document.getElementById(fieldName);
2284
+ if (timeInput && timeInput.type === 'time') {
2285
+ // Try modern showPicker API first, fallback to click
2286
+ if (timeInput.showPicker) {
2287
+ timeInput.showPicker();
2288
+ }
2289
+ else {
2290
+ timeInput.focus();
2291
+ timeInput.click();
2292
+ }
2293
+ }
2294
+ }
2295
+ onFileChange(event, fieldName) {
2296
+ const file = event.target.files[0];
2297
+ if (file) {
2298
+ this.fileNames.set(fieldName, file.name);
2299
+ const reader = new FileReader();
2300
+ reader.readAsDataURL(file);
2301
+ reader.onload = () => {
2302
+ const base64String = reader.result;
2303
+ this.filePreviews.set(fieldName, base64String);
2304
+ this.form.get(fieldName)?.setValue(base64String);
2305
+ // Trigger onChange handler for file fields
2306
+ const column = this.getColumnByName(fieldName);
2307
+ if (column?.onChange) {
2308
+ column.onChange(base64String, this.form);
2309
+ }
2310
+ };
2311
+ }
2312
+ }
2313
+ extractFileName(value) {
2314
+ if (!value)
2315
+ return '';
2316
+ // If it's a URL, extract filename from URL
2317
+ if (value.startsWith('http')) {
2318
+ const parts = value.split('/');
2319
+ return parts[parts.length - 1];
2320
+ }
2321
+ // If it's base64, return a generic name
2322
+ if (value.startsWith(`data:image`)) {
2323
+ return 'uploaded-image.jpg';
2324
+ }
2325
+ return 'existing-photo.jpg';
2326
+ }
2327
+ getFilePreview(fieldName) {
2328
+ return this.filePreviews.get(fieldName) || null;
2329
+ }
2330
+ getFileName(fieldName) {
2331
+ return this.fileNames.get(fieldName) || null;
2332
+ }
2333
+ mapSearchOptions(options) {
2334
+ return options.map(opt => ({
2335
+ code: opt.code || opt.value,
2336
+ name: opt.name || opt.label || opt.value,
2337
+ value: opt.value
2338
+ }));
2339
+ }
2340
+ deleteFile(fieldName) {
2341
+ this.filePreviews.delete(fieldName);
2342
+ this.fileNames.delete(fieldName);
2343
+ this.form.get(fieldName)?.setValue('');
2344
+ // Trigger onChange handler when file is deleted
2345
+ const column = this.getColumnByName(fieldName);
2346
+ if (column?.onChange) {
2347
+ column.onChange('', this.form);
2348
+ }
2349
+ }
2350
+ handleSubmit() {
2351
+ this.submitted = true;
2352
+ if (this.form.invalid) {
2353
+ // Mark all fields as touched to show red borders
2354
+ Object.keys(this.form.controls).forEach((key) => {
2355
+ this.form.get(key)?.markAsTouched();
2356
+ });
2357
+ // Count only required fields that are invalid
2358
+ const allColumns = this.config.sections.flatMap((s) => s.fields);
2359
+ const invalidRequiredCount = Object.keys(this.form.controls).filter((key) => {
2360
+ const control = this.form.get(key);
2361
+ if (!control?.invalid)
2362
+ return false;
2363
+ // Check if this field has required validation
2364
+ const column = allColumns.find((c) => c.name === key);
2365
+ return (column?.validations?.some((v) => v.type === 'required') || false);
2366
+ }).length;
2367
+ // Only emit if there are required fields missing
2368
+ if (invalidRequiredCount > 0) {
2369
+ this.validationError.emit(`Please fill all required fields marked with *. ${invalidRequiredCount} field(s) need attention.`);
2370
+ }
2371
+ return;
2372
+ }
2373
+ const formData = this.form.getRawValue();
2374
+ this.config.onSubmit(formData);
2375
+ }
2376
+ handleReset() {
2377
+ this.submitted = false;
2378
+ this.form.reset();
2379
+ if (this.config.onReset) {
2380
+ this.config.onReset();
2381
+ }
2382
+ }
2383
+ isFieldInvalid(fieldName) {
2384
+ const field = this.form.get(fieldName);
2385
+ return !!(field && field.invalid && this.submitted);
2386
+ }
2387
+ getErrorMessage(fieldName) {
2388
+ const field = this.form.get(fieldName);
2389
+ if (!field?.errors)
2390
+ return '';
2391
+ // Check if there's a custom message from validations
2392
+ const allColumns = this.config.sections.flatMap((s) => s.fields);
2393
+ const column = allColumns.find((c) => c.name === fieldName);
2394
+ // Check for custom validation error
2395
+ if (field.errors['custom']) {
2396
+ const customValidation = column?.validations?.find((v) => v.type === 'custom');
2397
+ return customValidation?.message || 'Invalid field';
2398
+ }
2399
+ // Check if there's a custom message from validations
2400
+ const errorKeys = Object.keys(field.errors);
2401
+ for (const key of errorKeys) {
2402
+ const validation = column?.validations?.find((v) => v.type === key);
2403
+ if (validation?.message) {
2404
+ return validation.message;
2405
+ }
2406
+ }
2407
+ // Default error messages
2408
+ if (field.errors['required']) {
2409
+ return `${column?.label} is required`;
2410
+ }
2411
+ if (field.errors['email'])
2412
+ return 'Invalid email format';
2413
+ if (field.errors['minlength'])
2414
+ return `Minimum length is ${field.errors['minlength'].requiredLength}`;
2415
+ if (field.errors['maxlength'])
2416
+ return `Maximum length is ${field.errors['maxlength'].requiredLength}`;
2417
+ if (field.errors['min'])
2418
+ return `Minimum value is ${field.errors['min'].min}`;
2419
+ if (field.errors['max'])
2420
+ return `Maximum value is ${field.errors['max'].max}`;
2421
+ if (field.errors['pattern'])
2422
+ return 'Invalid format';
2423
+ return 'Invalid field';
2424
+ }
2425
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AddUpdateFormComponent, deps: [{ token: i2.FormBuilder }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
2426
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: AddUpdateFormComponent, isStandalone: true, selector: "lib-add-update-form", inputs: { config: "config" }, outputs: { validationError: "validationError" }, ngImport: i0, template: `
2427
+ <div class="form-container">
2428
+ <div class="form-header" *ngIf="config.formTitle">
2429
+ <h2>{{ config.formTitle }}</h2>
2430
+ </div>
2431
+
2432
+ <form [formGroup]="form" (ngSubmit)="handleSubmit()" class="dynamic-form">
2433
+ <div *ngFor="let section of config.sections" class="form-section">
2434
+ <h3 class="section-title" *ngIf="section.title">
2435
+ {{ section.title }}
2436
+ </h3>
2437
+
2438
+ <div class="fields-row">
2439
+ <ng-container *ngFor="let column of section.fields">
2440
+ <div
2441
+ class="form-field-wrapper"
2442
+ [ngClass]="'field-' + column.type"
2443
+ [ngStyle]="column.hidden ? { display: 'none' } : {}"
2444
+ [style.grid-column]="'span ' + (column.colSpan || 1)"
2445
+ >
2446
+ <ng-container
2447
+ *ngIf="
2448
+ ['text', 'email', 'password'].includes(column.type) &&
2449
+ !column.hidden
2450
+ "
2451
+ >
2452
+ <fv-entry-field
2453
+ [label]="column.label"
2454
+ [placeholder]="column.placeholder || ''"
2455
+ [type]="
2456
+ column.type === 'password'
2457
+ ? 'password'
2458
+ : column.type === 'email'
2459
+ ? 'email'
2460
+ : 'text'
2461
+ "
2462
+ [control]="getControl(column.name)"
2463
+ [schema]="getSchema(column)"
2464
+ [disabled]="column.disabled || false"
2465
+ [readonly]="false"
2466
+ [allowAlphabetsOnly]="column.allowAlphabetsOnly || false"
2467
+ [maxLength]="column.maxLength || null"
2468
+ (valueChange)="handleFieldChange(column.name, $event)"
2469
+ >
2470
+ </fv-entry-field>
2471
+ </ng-container>
2472
+
2473
+ <ng-container
2474
+ *ngIf="column.type === 'number' && !column.hidden"
2475
+ >
2476
+ <fv-number-field
2477
+ [label]="column.label"
2478
+ [placeholder]="column.placeholder || ''"
2479
+ [control]="getControl(column.name)"
2480
+ [schema]="getSchema(column)"
2481
+ [disabled]="column.disabled || false"
2482
+ (valueChange)="handleFieldChange(column.name, $event)"
2483
+ >
2484
+ </fv-number-field>
2485
+ </ng-container>
2486
+
2487
+ <ng-container
2488
+ *ngIf="column.type === 'select' && !column.hidden"
2489
+ >
2490
+ <fv-dropdown
2491
+ [label]="column.label"
2492
+ [placeholder]="column.placeholder || 'Select option'"
2493
+ [options]="column.options || []"
2494
+ [control]="getControl(column.name)"
2495
+ [schema]="getSchema(column)"
2496
+ [disabled]="column.disabled || false"
2497
+ (valueChange)="handleFieldChange(column.name, $event)"
2498
+ >
2499
+ </fv-dropdown>
2500
+ </ng-container>
2501
+
2502
+ <ng-container
2503
+ *ngIf="column.type === 'checkbox' && !column.hidden"
2504
+ >
2505
+ <fv-checkbox
2506
+ [label]="column.label"
2507
+ [control]="getControl(column.name)"
2508
+ [disabled]="column.disabled || false"
2509
+ (valueChange)="handleFieldChange(column.name, $event)"
2510
+ >
2511
+ </fv-checkbox>
2512
+ </ng-container>
2513
+
2514
+ <ng-container *ngIf="column.type === 'radio' && !column.hidden">
2515
+ <fv-radio-group
2516
+ [label]="column.label"
2517
+ [options]="column.options || []"
2518
+ [control]="getControl(column.name)"
2519
+ [disabled]="column.disabled || false"
2520
+ (valueChange)="handleFieldChange(column.name, $event)"
2521
+ >
2522
+ </fv-radio-group>
2523
+ </ng-container>
2524
+
2525
+ <ng-container *ngIf="column.type === 'date' && !column.hidden">
2526
+ <fv-date-field
2527
+ [label]="column.label"
2528
+ [control]="getControl(column.name)"
2529
+ [schema]="getSchema(column)"
2530
+ [disabled]="column.disabled || false"
2531
+ (valueChange)="handleFieldChange(column.name, $event)"
2532
+ >
2533
+ </fv-date-field>
2534
+ </ng-container>
2535
+
2536
+ <ng-container
2537
+ *ngIf="column.type === 'month-year' && !column.hidden"
2538
+ >
2539
+ <fv-month-year-field
2540
+ [label]="column.label"
2541
+ [control]="getControl(column.name)"
2542
+ [schema]="getSchema(column)"
2543
+ [disabled]="column.disabled || false"
2544
+ (valueChange)="handleMonthYearChange(column.name, $event)"
2545
+ >
2546
+ </fv-month-year-field>
2547
+ </ng-container>
2548
+
2549
+ <ng-container
2550
+ *ngIf="column.type === 'textarea' && !column.hidden"
2551
+ >
2552
+ <fv-rich-text-editor
2553
+ [label]="column.label"
2554
+ [placeholder]="column.placeholder || ''"
2555
+ [control]="getControl(column.name)"
2556
+ [schema]="getSchema(column)"
2557
+ [disabled]="column.disabled || false"
2558
+ (valueChange)="handleFieldChange(column.name, $event)"
2559
+ >
2560
+ </fv-rich-text-editor>
2561
+ </ng-container>
2562
+
2563
+ <ng-container *ngIf="column.type === 'file' && !column.hidden">
2564
+ <ng-container *ngIf="isImageField(column); else standardFile">
2565
+ <fv-image-selector
2566
+ [label]="column.label"
2567
+ [placeholder]="column.placeholder || 'Select image'"
2568
+ [control]="getControl(column.name)"
2569
+ [schema]="getSchema(column)"
2570
+ [disabled]="column.disabled || false"
2571
+ (valueChange)="onFileChange($event, column.name)"
2572
+ >
2573
+ </fv-image-selector>
2574
+ </ng-container>
2575
+
2576
+ <ng-template #standardFile>
2577
+ <fv-file-selector
2578
+ [label]="column.label"
2579
+ [placeholder]="column.placeholder || 'Select file'"
2580
+ [accept]="column.accept || '*/*'"
2581
+ [control]="getControl(column.name)"
2582
+ [schema]="getSchema(column)"
2583
+ [disabled]="column.disabled || false"
2584
+ (valueChange)="onFileChange($event, column.name)"
2585
+ >
2586
+ </fv-file-selector>
2587
+ </ng-template>
2588
+ </ng-container>
2589
+
2590
+ <ng-container
2591
+ *ngIf="column.type === 'name-code' && !column.hidden"
2592
+ >
2593
+ <fv-name-code
2594
+ [label]="column.label"
2595
+ [placeholder]="column.placeholder || 'Search by Code or Name'"
2596
+ [options]="column.options ? mapSearchOptions(column.options) : []"
2597
+ [control]="getControl(column.name)"
2598
+ [schema]="getSchema(column)"
2599
+ [disabled]="column.disabled || false"
2600
+ >
2601
+ </fv-name-code>
2602
+ </ng-container>
2603
+
2604
+ <ng-container *ngIf="column.type === 'phone' && !column.hidden">
2605
+ <fv-phone-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-phone-field>
2606
+ </ng-container>
2607
+
2608
+ <ng-container *ngIf="column.type === 'uan' && !column.hidden">
2609
+ <fv-uan-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-uan-field>
2610
+ </ng-container>
2611
+
2612
+ <ng-container *ngIf="column.type === 'pf' && !column.hidden">
2613
+ <fv-pf-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-pf-field>
2614
+ </ng-container>
2615
+
2616
+ <ng-container *ngIf="column.type === 'esi' && !column.hidden">
2617
+ <fv-esi-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-esi-field>
2618
+ </ng-container>
2619
+
2620
+ <ng-container *ngIf="column.type === 'ifsc' && !column.hidden">
2621
+ <fv-ifsc-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-ifsc-field>
2622
+ </ng-container>
2623
+
2624
+ <ng-container *ngIf="column.type === 'micr' && !column.hidden">
2625
+ <fv-micr-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-micr-field>
2626
+ </ng-container>
2627
+
2628
+ <ng-container *ngIf="column.type === 'iban' && !column.hidden">
2629
+ <fv-iban-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-iban-field>
2630
+ </ng-container>
2631
+ </div>
2632
+ </ng-container>
2633
+ </div>
2634
+ </div>
2635
+
2636
+
2637
+ <div class="form-actions">
2638
+ <button
2639
+ type="submit"
2640
+ class="btn btn-primary"
2641
+ [disabled]="form.invalid && submitted"
2642
+ >
2643
+ {{ config.submitLabel || 'Save' }}
2644
+ </button>
2645
+ <button
2646
+ type="button"
2647
+ class="btn btn-outline"
2648
+ (click)="config.onCancel()"
2649
+ >
2650
+ {{ config.cancelLabel || 'Cancel' }}
2651
+ </button>
2652
+ </div>
2653
+ </form>
2654
+ </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%;overflow-x:hidden;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}.form-field-wrapper{display:flex;position:relative;flex-direction:column;min-width:0;width:100%;box-sizing:border-box}.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"] }] });
2656
+ }
2657
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AddUpdateFormComponent, decorators: [{
2658
+ type: Component,
2659
+ args: [{ selector: 'lib-add-update-form', standalone: true, imports: [
2660
+ CommonModule,
2661
+ ReactiveFormsModule,
2662
+ FvEntryFieldComponent,
2663
+ FvNumberFieldComponent,
2664
+ FvDropdownComponent,
2665
+ FvRadioGroupComponent,
2666
+ FvCheckboxComponent,
2667
+ FvDateFieldComponent,
2668
+ FvMonthYearFieldComponent,
2669
+ FvFileSelectorComponent,
2670
+ FvImageSelectorComponent,
2671
+ FvRichTextEditorComponent,
2672
+ FvRichTextEditorComponent,
2673
+ FvNameCodeComponent,
2674
+ FvPhoneFieldComponent,
2675
+ FvUanFieldComponent,
2676
+ FvPfFieldComponent,
2677
+ FvEsiFieldComponent,
2678
+ FvIfscFieldComponent,
2679
+ FvMicrFieldComponent,
2680
+ FvIbanFieldComponent,
2681
+ ], template: `
2682
+ <div class="form-container">
2683
+ <div class="form-header" *ngIf="config.formTitle">
2684
+ <h2>{{ config.formTitle }}</h2>
2685
+ </div>
2686
+
2687
+ <form [formGroup]="form" (ngSubmit)="handleSubmit()" class="dynamic-form">
2688
+ <div *ngFor="let section of config.sections" class="form-section">
2689
+ <h3 class="section-title" *ngIf="section.title">
2690
+ {{ section.title }}
2691
+ </h3>
2692
+
2693
+ <div class="fields-row">
2694
+ <ng-container *ngFor="let column of section.fields">
2695
+ <div
2696
+ class="form-field-wrapper"
2697
+ [ngClass]="'field-' + column.type"
2698
+ [ngStyle]="column.hidden ? { display: 'none' } : {}"
2699
+ [style.grid-column]="'span ' + (column.colSpan || 1)"
2700
+ >
2701
+ <ng-container
2702
+ *ngIf="
2703
+ ['text', 'email', 'password'].includes(column.type) &&
2704
+ !column.hidden
2705
+ "
2706
+ >
2707
+ <fv-entry-field
2708
+ [label]="column.label"
2709
+ [placeholder]="column.placeholder || ''"
2710
+ [type]="
2711
+ column.type === 'password'
2712
+ ? 'password'
2713
+ : column.type === 'email'
2714
+ ? 'email'
2715
+ : 'text'
2716
+ "
2717
+ [control]="getControl(column.name)"
2718
+ [schema]="getSchema(column)"
2719
+ [disabled]="column.disabled || false"
2720
+ [readonly]="false"
2721
+ [allowAlphabetsOnly]="column.allowAlphabetsOnly || false"
2722
+ [maxLength]="column.maxLength || null"
2723
+ (valueChange)="handleFieldChange(column.name, $event)"
2724
+ >
2725
+ </fv-entry-field>
2726
+ </ng-container>
2727
+
2728
+ <ng-container
2729
+ *ngIf="column.type === 'number' && !column.hidden"
2730
+ >
2731
+ <fv-number-field
2732
+ [label]="column.label"
2733
+ [placeholder]="column.placeholder || ''"
2734
+ [control]="getControl(column.name)"
2735
+ [schema]="getSchema(column)"
2736
+ [disabled]="column.disabled || false"
2737
+ (valueChange)="handleFieldChange(column.name, $event)"
2738
+ >
2739
+ </fv-number-field>
2740
+ </ng-container>
2741
+
2742
+ <ng-container
2743
+ *ngIf="column.type === 'select' && !column.hidden"
2744
+ >
2745
+ <fv-dropdown
2746
+ [label]="column.label"
2747
+ [placeholder]="column.placeholder || 'Select option'"
2748
+ [options]="column.options || []"
2749
+ [control]="getControl(column.name)"
2750
+ [schema]="getSchema(column)"
2751
+ [disabled]="column.disabled || false"
2752
+ (valueChange)="handleFieldChange(column.name, $event)"
2753
+ >
2754
+ </fv-dropdown>
2755
+ </ng-container>
2756
+
2757
+ <ng-container
2758
+ *ngIf="column.type === 'checkbox' && !column.hidden"
2759
+ >
2760
+ <fv-checkbox
2761
+ [label]="column.label"
2762
+ [control]="getControl(column.name)"
2763
+ [disabled]="column.disabled || false"
2764
+ (valueChange)="handleFieldChange(column.name, $event)"
2765
+ >
2766
+ </fv-checkbox>
2767
+ </ng-container>
2768
+
2769
+ <ng-container *ngIf="column.type === 'radio' && !column.hidden">
2770
+ <fv-radio-group
2771
+ [label]="column.label"
2772
+ [options]="column.options || []"
2773
+ [control]="getControl(column.name)"
2774
+ [disabled]="column.disabled || false"
2775
+ (valueChange)="handleFieldChange(column.name, $event)"
2776
+ >
2777
+ </fv-radio-group>
2778
+ </ng-container>
2779
+
2780
+ <ng-container *ngIf="column.type === 'date' && !column.hidden">
2781
+ <fv-date-field
2782
+ [label]="column.label"
2783
+ [control]="getControl(column.name)"
2784
+ [schema]="getSchema(column)"
2785
+ [disabled]="column.disabled || false"
2786
+ (valueChange)="handleFieldChange(column.name, $event)"
2787
+ >
2788
+ </fv-date-field>
2789
+ </ng-container>
2790
+
2791
+ <ng-container
2792
+ *ngIf="column.type === 'month-year' && !column.hidden"
2793
+ >
2794
+ <fv-month-year-field
2795
+ [label]="column.label"
2796
+ [control]="getControl(column.name)"
2797
+ [schema]="getSchema(column)"
2798
+ [disabled]="column.disabled || false"
2799
+ (valueChange)="handleMonthYearChange(column.name, $event)"
2800
+ >
2801
+ </fv-month-year-field>
2802
+ </ng-container>
2803
+
2804
+ <ng-container
2805
+ *ngIf="column.type === 'textarea' && !column.hidden"
2806
+ >
2807
+ <fv-rich-text-editor
2808
+ [label]="column.label"
2809
+ [placeholder]="column.placeholder || ''"
2810
+ [control]="getControl(column.name)"
2811
+ [schema]="getSchema(column)"
2812
+ [disabled]="column.disabled || false"
2813
+ (valueChange)="handleFieldChange(column.name, $event)"
2814
+ >
2815
+ </fv-rich-text-editor>
2816
+ </ng-container>
2817
+
2818
+ <ng-container *ngIf="column.type === 'file' && !column.hidden">
2819
+ <ng-container *ngIf="isImageField(column); else standardFile">
2820
+ <fv-image-selector
2821
+ [label]="column.label"
2822
+ [placeholder]="column.placeholder || 'Select image'"
2823
+ [control]="getControl(column.name)"
2824
+ [schema]="getSchema(column)"
2825
+ [disabled]="column.disabled || false"
2826
+ (valueChange)="onFileChange($event, column.name)"
2827
+ >
2828
+ </fv-image-selector>
2829
+ </ng-container>
2830
+
2831
+ <ng-template #standardFile>
2832
+ <fv-file-selector
2833
+ [label]="column.label"
2834
+ [placeholder]="column.placeholder || 'Select file'"
2835
+ [accept]="column.accept || '*/*'"
2836
+ [control]="getControl(column.name)"
2837
+ [schema]="getSchema(column)"
2838
+ [disabled]="column.disabled || false"
2839
+ (valueChange)="onFileChange($event, column.name)"
2840
+ >
2841
+ </fv-file-selector>
2842
+ </ng-template>
2843
+ </ng-container>
2844
+
2845
+ <ng-container
2846
+ *ngIf="column.type === 'name-code' && !column.hidden"
2847
+ >
2848
+ <fv-name-code
2849
+ [label]="column.label"
2850
+ [placeholder]="column.placeholder || 'Search by Code or Name'"
2851
+ [options]="column.options ? mapSearchOptions(column.options) : []"
2852
+ [control]="getControl(column.name)"
2853
+ [schema]="getSchema(column)"
2854
+ [disabled]="column.disabled || false"
2855
+ >
2856
+ </fv-name-code>
2857
+ </ng-container>
2858
+
2859
+ <ng-container *ngIf="column.type === 'phone' && !column.hidden">
2860
+ <fv-phone-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-phone-field>
2861
+ </ng-container>
2862
+
2863
+ <ng-container *ngIf="column.type === 'uan' && !column.hidden">
2864
+ <fv-uan-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-uan-field>
2865
+ </ng-container>
2866
+
2867
+ <ng-container *ngIf="column.type === 'pf' && !column.hidden">
2868
+ <fv-pf-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-pf-field>
2869
+ </ng-container>
2870
+
2871
+ <ng-container *ngIf="column.type === 'esi' && !column.hidden">
2872
+ <fv-esi-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-esi-field>
2873
+ </ng-container>
2874
+
2875
+ <ng-container *ngIf="column.type === 'ifsc' && !column.hidden">
2876
+ <fv-ifsc-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-ifsc-field>
2877
+ </ng-container>
2878
+
2879
+ <ng-container *ngIf="column.type === 'micr' && !column.hidden">
2880
+ <fv-micr-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-micr-field>
2881
+ </ng-container>
2882
+
2883
+ <ng-container *ngIf="column.type === 'iban' && !column.hidden">
2884
+ <fv-iban-field [label]="column.label" [control]="getControl(column.name)" [schema]="getSchema(column)" [disabled]="column.disabled || false"></fv-iban-field>
2885
+ </ng-container>
2886
+ </div>
2887
+ </ng-container>
2888
+ </div>
2889
+ </div>
2890
+
2891
+
2892
+ <div class="form-actions">
2893
+ <button
2894
+ type="submit"
2895
+ class="btn btn-primary"
2896
+ [disabled]="form.invalid && submitted"
2897
+ >
2898
+ {{ config.submitLabel || 'Save' }}
2899
+ </button>
2900
+ <button
2901
+ type="button"
2902
+ class="btn btn-outline"
2903
+ (click)="config.onCancel()"
2904
+ >
2905
+ {{ config.cancelLabel || 'Cancel' }}
2906
+ </button>
2907
+ </div>
2908
+ </form>
2909
+ </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%;overflow-x:hidden;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}.form-field-wrapper{display:flex;position:relative;flex-direction:column;min-width:0;width:100%;box-sizing:border-box}.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"] }]
2911
+ }], ctorParameters: () => [{ type: i2.FormBuilder }, { type: i0.ElementRef }], propDecorators: { config: [{
2912
+ type: Input
2913
+ }], validationError: [{
2914
+ type: Output
2915
+ }] } });
2916
+
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
+ class QueryFormComponent {
2997
+ fb;
2998
+ config;
2999
+ onSubmit = new EventEmitter();
3000
+ onExport = new EventEmitter();
3001
+ onBack = new EventEmitter();
3002
+ form;
3003
+ showExportMenu = false;
3004
+ showValidationError = false;
3005
+ subs = [];
3006
+ constructor(fb) {
3007
+ this.fb = fb;
3008
+ }
3009
+ ngOnInit() {
3010
+ const group = {};
3011
+ if (this.config && this.config.rows) {
3012
+ this.config.rows.forEach((row) => {
3013
+ row.columns.forEach((col) => {
3014
+ const validators = [];
3015
+ if (col.required) {
3016
+ validators.push(Validators.required);
3017
+ }
3018
+ group[col.key] = new FormControl({ value: '', disabled: col.readonly || false }, validators);
3019
+ });
3020
+ });
3021
+ }
3022
+ this.form = this.fb.group(group);
3023
+ // Subscribe to value changes to trigger onChange callbacks
3024
+ this.subs.push(this.form.valueChanges.subscribe((value) => {
3025
+ this.config.rows.forEach((row) => {
3026
+ row.columns.forEach((col) => {
3027
+ if (col.onChange) {
3028
+ // Verify if this specific control changed?
3029
+ // For simplicity, we can pass value[col.key] but strictly we should check diff.
3030
+ // However, simple approach:
3031
+ // This runs on every change, might be noisy but acceptable for now.
3032
+ // A better approach would be subscribing to individual controls if performance matters.
3033
+ }
3034
+ });
3035
+ });
3036
+ }));
3037
+ // Subscribe individually to support onChange
3038
+ this.config.rows.forEach((row) => {
3039
+ row.columns.forEach((col) => {
3040
+ if (col.onChange) {
3041
+ const control = this.form.get(col.key);
3042
+ if (control) {
3043
+ this.subs.push(control.valueChanges.subscribe(val => {
3044
+ col.onChange(val);
3045
+ }));
3046
+ }
3047
+ }
3048
+ });
3049
+ });
3050
+ }
3051
+ ngOnDestroy() {
3052
+ this.subs.forEach((s) => s.unsubscribe());
3053
+ }
3054
+ getControl(key) {
3055
+ return this.form.get(key);
3056
+ }
3057
+ getSchema(column) {
3058
+ // Generate a simple schema based on column definition
3059
+ const rules = [];
3060
+ const errorPriority = [];
3061
+ if (column.required) {
3062
+ rules.push({ name: 'required', params: { enabled: true }, errorKey: 'ERR_REQUIRED' });
3063
+ errorPriority.push('required');
3064
+ }
3065
+ return {
3066
+ controlType: this.mapType(column.type),
3067
+ rules: rules,
3068
+ errorPriority: errorPriority
3069
+ };
3070
+ }
3071
+ mapType(type) {
3072
+ switch (type) {
3073
+ case 'text': return 'EntryField';
3074
+ case 'number': return 'NumberField';
3075
+ case 'date': return 'DateField';
3076
+ case 'dropdown': return 'Dropdown';
3077
+ case 'month': return 'MonthYearField';
3078
+ case 'file': return 'FileSelector';
3079
+ case 'name-code': return 'Dropdown';
3080
+ case 'phone': return 'PhoneField';
3081
+ case 'uan': return 'UanField';
3082
+ case 'pf': return 'PfField';
3083
+ case 'esi': return 'EsiField';
3084
+ case 'ifsc': return 'IfscField';
3085
+ case 'micr': return 'MicrField';
3086
+ case 'iban': return 'IbanField';
3087
+ default: return 'EntryField';
3088
+ }
3089
+ }
3090
+ mapSearchOptions(options) {
3091
+ return options.map(opt => ({
3092
+ code: opt.code || opt.value,
3093
+ name: opt.name || opt.label || opt.value,
3094
+ value: opt.value
3095
+ }));
3096
+ }
3097
+ triggerFileUpload(columnKey) {
3098
+ // FvFileSelector handles this internally, but if we needed external trigger...
3099
+ }
3100
+ toggleExportMenu(event) {
3101
+ event.stopPropagation();
3102
+ this.showExportMenu = !this.showExportMenu;
3103
+ }
3104
+ clickOutside(event) {
3105
+ if (this.showExportMenu) {
3106
+ this.showExportMenu = false;
3107
+ }
3108
+ }
3109
+ exportToFormat(format) {
3110
+ this.onExport.emit(format);
3111
+ this.showExportMenu = false;
3112
+ }
3113
+ onButtonClick() {
3114
+ if (this.form.valid) {
3115
+ this.showValidationError = false;
3116
+ this.onSubmit.emit(this.form.value);
3117
+ }
3118
+ else {
3119
+ this.showValidationError = true;
3120
+ this.form.markAllAsTouched();
3121
+ }
3122
+ }
3123
+ onBackClick() {
3124
+ this.onBack.emit();
3125
+ }
3126
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: QueryFormComponent, deps: [{ token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
3127
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: QueryFormComponent, isStandalone: true, selector: "lib-query-form", inputs: { config: "config" }, outputs: { onSubmit: "onSubmit", onExport: "onExport", onBack: "onBack" }, host: { listeners: { "document:click": "clickOutside($event)" } }, ngImport: i0, template: `
3128
+ <div class="query-form-container">
3129
+ <div class="d-flex cont">
3130
+ <h2 class="form-title">{{ config.title }}</h2>
3131
+
3132
+ <div
3133
+ class="export-buttons"
3134
+ *ngIf="
3135
+ config.showExportButton &&
3136
+ config.exportFormats &&
3137
+ config.exportFormats.length > 0
3138
+ "
3139
+ >
3140
+ <div class="export-menu-container">
3141
+ <button
3142
+ type="button"
3143
+ class="export-btn menu-trigger"
3144
+ (click)="toggleExportMenu($event)"
3145
+ title="Toggle export options"
3146
+ >
3147
+ <i class="material-icons">file_download</i>
3148
+ <i class="material-icons arrow">arrow_drop_down</i>
3149
+ </button>
3150
+ <div class="export-menu" *ngIf="showExportMenu">
3151
+ <button
3152
+ type="button"
3153
+ *ngFor="let format of config.exportFormats"
3154
+ class="menu-item"
3155
+ (click)="exportToFormat(format)"
3156
+ [attr.title]="'Export as ' + format.toUpperCase()"
3157
+ >
3158
+ Export as {{ format.toUpperCase() }}
3159
+ </button>
3160
+ </div>
3161
+ </div>
3162
+ </div>
3163
+ </div>
3164
+
3165
+ <!-- Validation Error Message -->
3166
+ <div *ngIf="showValidationError" class="validation-message">
3167
+ <i class="material-icons">error</i>
3168
+ Please fill all required fields
3169
+ </div>
3170
+
3171
+ <div class="form-content">
3172
+ <form [formGroup]="form">
3173
+ <div
3174
+ *ngFor="let row of config.rows; let rowIndex = index"
3175
+ class="form-row"
3176
+ >
3177
+ <div *ngFor="let column of row.columns" class="form-field">
3178
+
3179
+ <!-- Dropdown -->
3180
+ <ng-container *ngIf="column.type === 'dropdown'">
3181
+ <fv-dropdown
3182
+ [label]="column.label"
3183
+ [placeholder]="column.placeholder || 'Select option'"
3184
+ [options]="column.options || []"
3185
+ [control]="getControl(column.key)"
3186
+ [schema]="getSchema(column)"
3187
+ [disabled]="column.readonly || false"
3188
+ >
3189
+ </fv-dropdown>
3190
+ </ng-container>
3191
+
3192
+ <!-- Text Input -->
3193
+ <ng-container *ngIf="column.type === 'text'">
3194
+ <fv-entry-field
3195
+ [label]="column.label"
3196
+ [placeholder]="column.placeholder || ''"
3197
+ type="text"
3198
+ [control]="getControl(column.key)"
3199
+ [schema]="getSchema(column)"
3200
+ [disabled]="column.readonly || false"
3201
+ >
3202
+ </fv-entry-field>
3203
+ </ng-container>
3204
+
3205
+ <!-- Number Input -->
3206
+ <ng-container *ngIf="column.type === 'number'">
3207
+ <fv-number-field
3208
+ [label]="column.label"
3209
+ [placeholder]="column.placeholder || ''"
3210
+ [control]="getControl(column.key)"
3211
+ [schema]="getSchema(column)"
3212
+ [disabled]="column.readonly || false"
3213
+ >
3214
+ </fv-number-field>
3215
+ </ng-container>
3216
+
3217
+ <!-- Date Input -->
3218
+ <ng-container *ngIf="column.type === 'date'">
3219
+ <fv-date-field
3220
+ [label]="column.label"
3221
+ [control]="getControl(column.key)"
3222
+ [schema]="getSchema(column)"
3223
+ [disabled]="column.readonly || false"
3224
+ >
3225
+ </fv-date-field>
3226
+ </ng-container>
3227
+
3228
+ <!-- Month/Year Input -->
3229
+ <ng-container *ngIf="column.type === 'month'">
3230
+ <fv-month-year-field
3231
+ [label]="column.label"
3232
+ [control]="getControl(column.key)"
3233
+ [schema]="getSchema(column)"
3234
+ [disabled]="column.readonly || false"
3235
+ >
3236
+ </fv-month-year-field>
3237
+ </ng-container>
3238
+
3239
+ <!-- File Upload -->
3240
+ <ng-container *ngIf="column.type === 'file'">
3241
+ <fv-file-selector
3242
+ [label]="column.label"
3243
+ [placeholder]="column.placeholder || 'Select file'"
3244
+ [accept]="column.accept || '*/*'"
3245
+ [control]="getControl(column.key)"
3246
+ [schema]="getSchema(column)"
3247
+ [disabled]="column.readonly || false"
3248
+ >
3249
+ </fv-file-selector>
3250
+ </ng-container>
3251
+
3252
+ <!-- Name Code Field -->
3253
+ <ng-container *ngIf="column.type === 'name-code'">
3254
+ <fv-name-code
3255
+ [label]="column.label"
3256
+ [placeholder]="column.placeholder || 'Search by Code or Name'"
3257
+ [options]="mapSearchOptions(column.options || [])"
3258
+ [control]="getControl(column.key)"
3259
+ [schema]="getSchema(column)"
3260
+ [disabled]="column.readonly || false"
3261
+ >
3262
+ </fv-name-code>
3263
+ </ng-container>
3264
+
3265
+ <ng-container *ngIf="column.type === 'phone'">
3266
+ <fv-phone-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-phone-field>
3267
+ </ng-container>
3268
+
3269
+ <ng-container *ngIf="column.type === 'uan'">
3270
+ <fv-uan-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-uan-field>
3271
+ </ng-container>
3272
+
3273
+ <ng-container *ngIf="column.type === 'pf'">
3274
+ <fv-pf-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-pf-field>
3275
+ </ng-container>
3276
+
3277
+ <ng-container *ngIf="column.type === 'esi'">
3278
+ <fv-esi-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-esi-field>
3279
+ </ng-container>
3280
+
3281
+ <ng-container *ngIf="column.type === 'ifsc'">
3282
+ <fv-ifsc-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-ifsc-field>
3283
+ </ng-container>
3284
+
3285
+ <ng-container *ngIf="column.type === 'micr'">
3286
+ <fv-micr-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-micr-field>
3287
+ </ng-container>
3288
+
3289
+ <ng-container *ngIf="column.type === 'iban'">
3290
+ <fv-iban-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-iban-field>
3291
+ </ng-container>
3292
+ </div>
3293
+ </div>
3294
+
3295
+ <!-- Buttons Row -->
3296
+ <div class="button-row">
3297
+ <button
3298
+ type="button"
3299
+ class="view-button"
3300
+ (click)="onButtonClick()"
3301
+ [attr.title]="config.buttonText || 'View'"
3302
+ >
3303
+ {{ config.buttonText || 'View' }}
3304
+ </button>
3305
+ <button
3306
+ *ngIf="config.showBackButton"
3307
+ type="button"
3308
+ class="back-button"
3309
+ (click)="onBackClick()"
3310
+ [attr.title]="config.backButtonText || 'Back'"
3311
+ >
3312
+ {{ config.backButtonText || 'Back' }}
3313
+ </button>
3314
+ </div>
3315
+ </form>
3316
+ </div>
3317
+ </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}.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}.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}.form-field{display:flex;flex-direction:column;width:100%}.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"] }] });
3319
+ }
3320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: QueryFormComponent, decorators: [{
3321
+ type: Component,
3322
+ args: [{ selector: 'lib-query-form', standalone: true, imports: [
3323
+ CommonModule,
3324
+ ReactiveFormsModule,
3325
+ FvEntryFieldComponent,
3326
+ FvDropdownComponent,
3327
+ FvNumberFieldComponent,
3328
+ FvDateFieldComponent,
3329
+ FvMonthYearFieldComponent,
3330
+ FvFileSelectorComponent,
3331
+ FvNameCodeComponent,
3332
+ FvPhoneFieldComponent,
3333
+ FvUanFieldComponent,
3334
+ FvPfFieldComponent,
3335
+ FvEsiFieldComponent,
3336
+ FvIfscFieldComponent,
3337
+ FvMicrFieldComponent,
3338
+ FvIbanFieldComponent,
3339
+ ], template: `
3340
+ <div class="query-form-container">
3341
+ <div class="d-flex cont">
3342
+ <h2 class="form-title">{{ config.title }}</h2>
3343
+
3344
+ <div
3345
+ class="export-buttons"
3346
+ *ngIf="
3347
+ config.showExportButton &&
3348
+ config.exportFormats &&
3349
+ config.exportFormats.length > 0
3350
+ "
3351
+ >
3352
+ <div class="export-menu-container">
3353
+ <button
3354
+ type="button"
3355
+ class="export-btn menu-trigger"
3356
+ (click)="toggleExportMenu($event)"
3357
+ title="Toggle export options"
3358
+ >
3359
+ <i class="material-icons">file_download</i>
3360
+ <i class="material-icons arrow">arrow_drop_down</i>
3361
+ </button>
3362
+ <div class="export-menu" *ngIf="showExportMenu">
3363
+ <button
3364
+ type="button"
3365
+ *ngFor="let format of config.exportFormats"
3366
+ class="menu-item"
3367
+ (click)="exportToFormat(format)"
3368
+ [attr.title]="'Export as ' + format.toUpperCase()"
3369
+ >
3370
+ Export as {{ format.toUpperCase() }}
3371
+ </button>
3372
+ </div>
3373
+ </div>
3374
+ </div>
3375
+ </div>
3376
+
3377
+ <!-- Validation Error Message -->
3378
+ <div *ngIf="showValidationError" class="validation-message">
3379
+ <i class="material-icons">error</i>
3380
+ Please fill all required fields
3381
+ </div>
3382
+
3383
+ <div class="form-content">
3384
+ <form [formGroup]="form">
3385
+ <div
3386
+ *ngFor="let row of config.rows; let rowIndex = index"
3387
+ class="form-row"
3388
+ >
3389
+ <div *ngFor="let column of row.columns" class="form-field">
3390
+
3391
+ <!-- Dropdown -->
3392
+ <ng-container *ngIf="column.type === 'dropdown'">
3393
+ <fv-dropdown
3394
+ [label]="column.label"
3395
+ [placeholder]="column.placeholder || 'Select option'"
3396
+ [options]="column.options || []"
3397
+ [control]="getControl(column.key)"
3398
+ [schema]="getSchema(column)"
3399
+ [disabled]="column.readonly || false"
3400
+ >
3401
+ </fv-dropdown>
3402
+ </ng-container>
3403
+
3404
+ <!-- Text Input -->
3405
+ <ng-container *ngIf="column.type === 'text'">
3406
+ <fv-entry-field
3407
+ [label]="column.label"
3408
+ [placeholder]="column.placeholder || ''"
3409
+ type="text"
3410
+ [control]="getControl(column.key)"
3411
+ [schema]="getSchema(column)"
3412
+ [disabled]="column.readonly || false"
3413
+ >
3414
+ </fv-entry-field>
3415
+ </ng-container>
3416
+
3417
+ <!-- Number Input -->
3418
+ <ng-container *ngIf="column.type === 'number'">
3419
+ <fv-number-field
3420
+ [label]="column.label"
3421
+ [placeholder]="column.placeholder || ''"
3422
+ [control]="getControl(column.key)"
3423
+ [schema]="getSchema(column)"
3424
+ [disabled]="column.readonly || false"
3425
+ >
3426
+ </fv-number-field>
3427
+ </ng-container>
3428
+
3429
+ <!-- Date Input -->
3430
+ <ng-container *ngIf="column.type === 'date'">
3431
+ <fv-date-field
3432
+ [label]="column.label"
3433
+ [control]="getControl(column.key)"
3434
+ [schema]="getSchema(column)"
3435
+ [disabled]="column.readonly || false"
3436
+ >
3437
+ </fv-date-field>
3438
+ </ng-container>
3439
+
3440
+ <!-- Month/Year Input -->
3441
+ <ng-container *ngIf="column.type === 'month'">
3442
+ <fv-month-year-field
3443
+ [label]="column.label"
3444
+ [control]="getControl(column.key)"
3445
+ [schema]="getSchema(column)"
3446
+ [disabled]="column.readonly || false"
3447
+ >
3448
+ </fv-month-year-field>
3449
+ </ng-container>
3450
+
3451
+ <!-- File Upload -->
3452
+ <ng-container *ngIf="column.type === 'file'">
3453
+ <fv-file-selector
3454
+ [label]="column.label"
3455
+ [placeholder]="column.placeholder || 'Select file'"
3456
+ [accept]="column.accept || '*/*'"
3457
+ [control]="getControl(column.key)"
3458
+ [schema]="getSchema(column)"
3459
+ [disabled]="column.readonly || false"
3460
+ >
3461
+ </fv-file-selector>
3462
+ </ng-container>
3463
+
3464
+ <!-- Name Code Field -->
3465
+ <ng-container *ngIf="column.type === 'name-code'">
3466
+ <fv-name-code
3467
+ [label]="column.label"
3468
+ [placeholder]="column.placeholder || 'Search by Code or Name'"
3469
+ [options]="mapSearchOptions(column.options || [])"
3470
+ [control]="getControl(column.key)"
3471
+ [schema]="getSchema(column)"
3472
+ [disabled]="column.readonly || false"
3473
+ >
3474
+ </fv-name-code>
3475
+ </ng-container>
3476
+
3477
+ <ng-container *ngIf="column.type === 'phone'">
3478
+ <fv-phone-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-phone-field>
3479
+ </ng-container>
3480
+
3481
+ <ng-container *ngIf="column.type === 'uan'">
3482
+ <fv-uan-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-uan-field>
3483
+ </ng-container>
3484
+
3485
+ <ng-container *ngIf="column.type === 'pf'">
3486
+ <fv-pf-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-pf-field>
3487
+ </ng-container>
3488
+
3489
+ <ng-container *ngIf="column.type === 'esi'">
3490
+ <fv-esi-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-esi-field>
3491
+ </ng-container>
3492
+
3493
+ <ng-container *ngIf="column.type === 'ifsc'">
3494
+ <fv-ifsc-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-ifsc-field>
3495
+ </ng-container>
3496
+
3497
+ <ng-container *ngIf="column.type === 'micr'">
3498
+ <fv-micr-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-micr-field>
3499
+ </ng-container>
3500
+
3501
+ <ng-container *ngIf="column.type === 'iban'">
3502
+ <fv-iban-field [label]="column.label" [control]="getControl(column.key)" [schema]="getSchema(column)" [disabled]="column.readonly || false"></fv-iban-field>
3503
+ </ng-container>
3504
+ </div>
3505
+ </div>
3506
+
3507
+ <!-- Buttons Row -->
3508
+ <div class="button-row">
3509
+ <button
3510
+ type="button"
3511
+ class="view-button"
3512
+ (click)="onButtonClick()"
3513
+ [attr.title]="config.buttonText || 'View'"
3514
+ >
3515
+ {{ config.buttonText || 'View' }}
3516
+ </button>
3517
+ <button
3518
+ *ngIf="config.showBackButton"
3519
+ type="button"
3520
+ class="back-button"
3521
+ (click)="onBackClick()"
3522
+ [attr.title]="config.backButtonText || 'Back'"
3523
+ >
3524
+ {{ config.backButtonText || 'Back' }}
3525
+ </button>
3526
+ </div>
3527
+ </form>
3528
+ </div>
3529
+ </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}.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}.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}.form-field{display:flex;flex-direction:column;width:100%}.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"] }]
3531
+ }], ctorParameters: () => [{ type: i2.FormBuilder }], propDecorators: { config: [{
3532
+ type: Input
3533
+ }], onSubmit: [{
3534
+ type: Output
3535
+ }], onExport: [{
3536
+ type: Output
3537
+ }], onBack: [{
3538
+ type: Output
3539
+ }], clickOutside: [{
3540
+ type: HostListener,
3541
+ args: ['document:click', ['$event']]
3542
+ }] } });
1139
3543
 
1140
3544
  /*
1141
3545
  * Public API Surface of fv-controls
@@ -1145,5 +3549,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1145
3549
  * Generated bundle index. Do not edit.
1146
3550
  */
1147
3551
 
1148
- export { FvCheckboxComponent, FvControlsModule, FvDateFieldComponent, FvDropdownComponent, FvEntryFieldComponent, FvFileSelectorComponent, FvImageSelectorComponent, FvMonthYearFieldComponent, FvNumberFieldComponent, FvRadioGroupComponent, FvRichTextEditorComponent };
3552
+ export { AddUpdateFormComponent, FvCheckboxComponent, FvControlsModule, FvDateFieldComponent, FvDropdownComponent, FvEntryFieldComponent, FvEsiFieldComponent, FvFileSelectorComponent, FvIbanFieldComponent, FvIfscFieldComponent, FvImageSelectorComponent, FvMicrFieldComponent, FvMonthYearFieldComponent, FvNameCodeComponent, FvNumberFieldComponent, FvPfFieldComponent, FvPhoneFieldComponent, FvRadioGroupComponent, FvRichTextEditorComponent, FvUanFieldComponent, QueryFormComponent };
1149
3553
  //# sourceMappingURL=fovestta2-web-angular.mjs.map