commons-shared-web-ui 0.0.4 → 0.0.6

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.
@@ -1,11 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { NgModule, Input, Component, EventEmitter, HostListener, Output, forwardRef, Injectable, inject, LOCALE_ID, ViewChildren } from '@angular/core';
2
+ import { NgModule, Input, Component, EventEmitter, HostListener, Output, forwardRef, Directive, ViewChild, Injectable, inject, LOCALE_ID, ViewChildren } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, formatDate } from '@angular/common';
5
5
  import { MatCardModule } from '@angular/material/card';
6
- import * as i2$1 from '@angular/material/snack-bar';
6
+ import * as i2$2 from '@angular/material/snack-bar';
7
7
  import { MatSnackBarModule } from '@angular/material/snack-bar';
8
- import * as i4 from '@angular/material/checkbox';
9
8
  import { MatCheckboxModule } from '@angular/material/checkbox';
10
9
  import { MatDividerModule } from '@angular/material/divider';
11
10
  import * as i6 from '@angular/material/radio';
@@ -14,14 +13,14 @@ import { MatDialogModule } from '@angular/material/dialog';
14
13
  import { MatFormFieldModule } from '@angular/material/form-field';
15
14
  import * as i2 from '@angular/material/icon';
16
15
  import { MatIconModule } from '@angular/material/icon';
17
- import * as i7 from '@angular/material/button';
16
+ import * as i10 from '@angular/material/button';
18
17
  import { MatButtonModule } from '@angular/material/button';
19
18
  import { MatMenuModule } from '@angular/material/menu';
20
- import * as i7$1 from '@angular/material/datepicker';
19
+ import * as i7 from '@angular/material/datepicker';
21
20
  import { MatDatepickerModule } from '@angular/material/datepicker';
22
21
  import { MatTabsModule } from '@angular/material/tabs';
23
22
  import { MatNativeDateModule } from '@angular/material/core';
24
- import * as i8$1 from '@angular/material/input';
23
+ import * as i8 from '@angular/material/input';
25
24
  import { MatInputModule } from '@angular/material/input';
26
25
  import { MatProgressBarModule } from '@angular/material/progress-bar';
27
26
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
@@ -33,7 +32,6 @@ import { MatListModule } from '@angular/material/list';
33
32
  import { MatChipsModule } from '@angular/material/chips';
34
33
  import { MatPaginatorModule } from '@angular/material/paginator';
35
34
  import { MatTableModule } from '@angular/material/table';
36
- import * as i8 from '@angular/material/expansion';
37
35
  import { MatExpansionModule } from '@angular/material/expansion';
38
36
  import { CdkAccordionModule } from '@angular/cdk/accordion';
39
37
  import { MatSortModule } from '@angular/material/sort';
@@ -43,10 +41,12 @@ import { MatButtonToggleModule } from '@angular/material/button-toggle';
43
41
  import * as i1$2 from '@angular/forms';
44
42
  import { FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, Validators } from '@angular/forms';
45
43
  import * as i1$1 from '@angular/router';
44
+ import * as i2$1 from '@angular/cdk/scrolling';
45
+ import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
46
+ import { Subject, BehaviorSubject, combineLatest, forkJoin, of } from 'rxjs';
47
+ import { debounceTime, distinctUntilChanged, takeUntil, map, finalize, catchError } from 'rxjs/operators';
46
48
  import * as i3 from '@angular/common/http';
47
- import { HttpParams } from '@angular/common/http';
48
- import { BehaviorSubject, Subject, combineLatest, forkJoin, of } from 'rxjs';
49
- import { takeUntil, debounceTime, distinctUntilChanged, map, finalize, catchError } from 'rxjs/operators';
49
+ import { HttpParams, HttpHeaders } from '@angular/common/http';
50
50
 
51
51
  class MaterialModule {
52
52
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MaterialModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -233,6 +233,7 @@ class AlertComponent {
233
233
  message = '';
234
234
  icon = true;
235
235
  customIcon = ''; // New input for custom class
236
+ labels;
236
237
  // Customization Inputs
237
238
  width;
238
239
  height;
@@ -286,11 +287,11 @@ class AlertComponent {
286
287
  }
287
288
  }
288
289
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
289
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: AlertComponent, isStandalone: false, selector: "lib-alert", inputs: { variant: "variant", title: "title", message: "message", icon: "icon", customIcon: "customIcon", width: "width", height: "height", borderRadius: "borderRadius", padding: "padding", gap: "gap", backgroundColor: "backgroundColor", color: "color", borderColor: "borderColor", fontSize: "fontSize", fontWeight: "fontWeight", boxShadow: "boxShadow", borderTopLeftRadius: "borderTopLeftRadius", borderTopRightRadius: "borderTopRightRadius", borderBottomLeftRadius: "borderBottomLeftRadius", borderBottomRightRadius: "borderBottomRightRadius" }, ngImport: i0, template: "<div class=\"cc-alert\" [ngClass]=\"'cc-alert-' + variant\" [style.width]=\"width\" [style.height]=\"height\"\r\n [style.border-radius]=\"borderRadius\" [style.border-top-left-radius]=\"borderTopLeftRadius\"\r\n [style.border-top-right-radius]=\"borderTopRightRadius\" [style.border-bottom-left-radius]=\"borderBottomLeftRadius\"\r\n [style.border-bottom-right-radius]=\"borderBottomRightRadius\" [style.padding]=\"padding\" [style.gap]=\"gap\"\r\n [style.background-color]=\"backgroundColor\" [style.color]=\"color\" [style.border-color]=\"borderColor\"\r\n [style.font-size]=\"fontSize\" [style.font-weight]=\"fontWeight\" [style.box-shadow]=\"boxShadow\">\r\n\r\n <div class=\"cc-alert-icon\" *ngIf=\"icon\">\r\n <i *ngIf=\"customIcon\" [ngClass]=\"customIcon\"></i>\r\n <i *ngIf=\"!customIcon && isDefaultIcon\" [ngClass]=\"defaultIconClass\"></i>\r\n <i *ngIf=\"!customIcon && isStringIcon && !isImgIcon\" [ngClass]=\"iconString\"></i>\r\n <img *ngIf=\"!customIcon && isStringIcon && isImgIcon\" [src]=\"iconString\" alt=\"alert icon\" />\r\n <ng-container *ngIf=\"isObjectIcon\">\r\n <i *ngIf=\"iconObject.type === 'fontawesome'\" [ngClass]=\"iconObject.value\"></i>\r\n <span *ngIf=\"iconObject.type === 'material'\" class=\"material-icons\">{{ iconObject.value }}</span>\r\n <img *ngIf=\"iconObject.type === 'img'\" [src]=\"iconObject.value\" alt=\"alert icon\" />\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"cc-alert-content\">\r\n <div class=\"cc-alert-title\" *ngIf=\"title\">{{ title }}</div>\r\n <div class=\"cc-alert-message\" *ngIf=\"message\">{{ message }}</div>\r\n <ng-content></ng-content>\r\n </div>\r\n</div>", styles: [".cc-alert{display:flex;align-items:flex-start;width:100%;padding:var(--cc-alert-padding, 1rem 2rem);border-radius:var(--cc-alert-radius, .75rem);gap:var(--cc-alert-gap, 1rem);box-sizing:border-box;font-family:var(--cc-alert-font-family, inherit)}.cc-alert .cc-alert-icon{font-size:var(--cc-alert-icon-size, 1.25rem);flex-shrink:0;margin-top:var(--cc-alert-icon-margin-top, .125rem)}.cc-alert .cc-alert-icon img{width:var(--cc-alert-icon-size, 1.25rem);height:var(--cc-alert-icon-size, 1.25rem);object-fit:contain}.cc-alert .cc-alert-content{display:flex;flex-direction:column;gap:.25rem;flex-grow:1}.cc-alert .cc-alert-content .cc-alert-title{font-weight:700;font-size:var(--cc-alert-title-size, 1rem);line-height:var(--cc-alert-title-line-height, 1.5rem)}.cc-alert .cc-alert-content .cc-alert-message{font-size:var(--cc-alert-message-size, .875rem);line-height:200%;opacity:.9}.cc-alert.cc-alert-info{background-color:var(--cc-alert-info-bg);color:var(--cc-alert-info-color)}.cc-alert.cc-alert-info .cc-alert-icon{color:#5f6368}.cc-alert.cc-alert-warning{background-color:var(--cc-alert-warning-bg);color:var(--cc-alert-warning-color)}.cc-alert.cc-alert-warning .cc-alert-title,.cc-alert.cc-alert-warning .cc-alert-icon{color:var(--cc-alert-warning-title-color)}.cc-alert.cc-alert-warning-shadow{background-color:var(--cc-alert-warning-bg);color:var(--cc-alert-warning-color);box-shadow:var(--cc-alert-warning-shadow)}.cc-alert.cc-alert-warning-shadow .cc-alert-title,.cc-alert.cc-alert-warning-shadow .cc-alert-icon{color:var(--cc-alert-warning-title-color)}.cc-alert.cc-alert-success{background-color:var(--cc-alert-success-bg);color:var(--cc-alert-success-color)}.cc-alert.cc-alert-error{background-color:var(--cc-alert-error-bg);color:var(--cc-alert-error-color)}.cc-alert.cc-alert-error .cc-alert-icon{color:var(--cc-alert-error-color)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
290
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: AlertComponent, isStandalone: false, selector: "lib-alert", inputs: { variant: "variant", title: "title", message: "message", icon: "icon", customIcon: "customIcon", labels: "labels", width: "width", height: "height", borderRadius: "borderRadius", padding: "padding", gap: "gap", backgroundColor: "backgroundColor", color: "color", borderColor: "borderColor", fontSize: "fontSize", fontWeight: "fontWeight", boxShadow: "boxShadow", borderTopLeftRadius: "borderTopLeftRadius", borderTopRightRadius: "borderTopRightRadius", borderBottomLeftRadius: "borderBottomLeftRadius", borderBottomRightRadius: "borderBottomRightRadius" }, ngImport: i0, template: "<div class=\"cc-alert\" [ngClass]=\"'cc-alert-' + variant\" [style.width]=\"width\" [style.height]=\"height\"\r\n [style.border-radius]=\"borderRadius\" [style.border-top-left-radius]=\"borderTopLeftRadius\"\r\n [style.border-top-right-radius]=\"borderTopRightRadius\" [style.border-bottom-left-radius]=\"borderBottomLeftRadius\"\r\n [style.border-bottom-right-radius]=\"borderBottomRightRadius\" [style.padding]=\"padding\" [style.gap]=\"gap\"\r\n [style.background-color]=\"backgroundColor\" [style.color]=\"color\" [style.border-color]=\"borderColor\"\r\n [style.font-size]=\"fontSize\" [style.font-weight]=\"fontWeight\" [style.box-shadow]=\"boxShadow\">\r\n\r\n <div class=\"cc-alert-icon\" *ngIf=\"icon\">\r\n <i *ngIf=\"customIcon\" [ngClass]=\"customIcon\"></i>\r\n <i *ngIf=\"!customIcon && isDefaultIcon\" [ngClass]=\"defaultIconClass\"></i>\r\n <i *ngIf=\"!customIcon && isStringIcon && !isImgIcon\" [ngClass]=\"iconString\"></i>\r\n <img *ngIf=\"!customIcon && isStringIcon && isImgIcon\" [src]=\"iconString\"\r\n [attr.alt]=\"labels?.iconAltText || 'alert icon'\" />\r\n <ng-container *ngIf=\"isObjectIcon\">\r\n <i *ngIf=\"iconObject.type === 'fontawesome'\" [ngClass]=\"iconObject.value\"></i>\r\n <span *ngIf=\"iconObject.type === 'material'\" class=\"material-icons\">{{ iconObject.value }}</span>\r\n <img *ngIf=\"iconObject.type === 'img'\" [src]=\"iconObject.value\"\r\n [attr.alt]=\"labels?.iconAltText || 'alert icon'\" />\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"cc-alert-content\">\r\n <div class=\"cc-alert-title\" *ngIf=\"title\">{{ title }}</div>\r\n <div class=\"cc-alert-message\" *ngIf=\"message\">{{ message }}</div>\r\n <ng-content></ng-content>\r\n </div>\r\n</div>", styles: [".cc-alert{display:flex;align-items:flex-start;width:100%;padding:var(--cc-alert-padding, 1rem 2rem);border-radius:var(--cc-alert-radius, .75rem);gap:var(--cc-alert-gap, 1rem);box-sizing:border-box;font-family:var(--cc-alert-font-family, inherit)}.cc-alert .cc-alert-icon{font-size:var(--cc-alert-icon-size, 1.25rem);flex-shrink:0;margin-top:var(--cc-alert-icon-margin-top, .125rem)}.cc-alert .cc-alert-icon img{width:var(--cc-alert-icon-size, 1.25rem);height:var(--cc-alert-icon-size, 1.25rem);object-fit:contain}.cc-alert .cc-alert-content{display:flex;flex-direction:column;gap:.25rem;flex-grow:1}.cc-alert .cc-alert-content .cc-alert-title{font-weight:700;font-size:var(--cc-alert-title-size, 1rem);line-height:var(--cc-alert-title-line-height, 1.5rem)}.cc-alert .cc-alert-content .cc-alert-message{font-size:var(--cc-alert-message-size, .875rem);line-height:200%;opacity:.9}.cc-alert.cc-alert-info{background-color:var(--cc-alert-info-bg);color:var(--cc-alert-info-color)}.cc-alert.cc-alert-info .cc-alert-icon{color:#5f6368}.cc-alert.cc-alert-warning{background-color:var(--cc-alert-warning-bg);color:var(--cc-alert-warning-color)}.cc-alert.cc-alert-warning .cc-alert-title,.cc-alert.cc-alert-warning .cc-alert-icon{color:var(--cc-alert-warning-title-color)}.cc-alert.cc-alert-warning-shadow{background-color:var(--cc-alert-warning-bg);color:var(--cc-alert-warning-color);box-shadow:var(--cc-alert-warning-shadow)}.cc-alert.cc-alert-warning-shadow .cc-alert-title,.cc-alert.cc-alert-warning-shadow .cc-alert-icon{color:var(--cc-alert-warning-title-color)}.cc-alert.cc-alert-success{background-color:var(--cc-alert-success-bg);color:var(--cc-alert-success-color)}.cc-alert.cc-alert-error{background-color:var(--cc-alert-error-bg);color:var(--cc-alert-error-color)}.cc-alert.cc-alert-error .cc-alert-icon{color:var(--cc-alert-error-color)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
290
291
  }
291
292
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlertComponent, decorators: [{
292
293
  type: Component,
293
- args: [{ selector: 'lib-alert', standalone: false, template: "<div class=\"cc-alert\" [ngClass]=\"'cc-alert-' + variant\" [style.width]=\"width\" [style.height]=\"height\"\r\n [style.border-radius]=\"borderRadius\" [style.border-top-left-radius]=\"borderTopLeftRadius\"\r\n [style.border-top-right-radius]=\"borderTopRightRadius\" [style.border-bottom-left-radius]=\"borderBottomLeftRadius\"\r\n [style.border-bottom-right-radius]=\"borderBottomRightRadius\" [style.padding]=\"padding\" [style.gap]=\"gap\"\r\n [style.background-color]=\"backgroundColor\" [style.color]=\"color\" [style.border-color]=\"borderColor\"\r\n [style.font-size]=\"fontSize\" [style.font-weight]=\"fontWeight\" [style.box-shadow]=\"boxShadow\">\r\n\r\n <div class=\"cc-alert-icon\" *ngIf=\"icon\">\r\n <i *ngIf=\"customIcon\" [ngClass]=\"customIcon\"></i>\r\n <i *ngIf=\"!customIcon && isDefaultIcon\" [ngClass]=\"defaultIconClass\"></i>\r\n <i *ngIf=\"!customIcon && isStringIcon && !isImgIcon\" [ngClass]=\"iconString\"></i>\r\n <img *ngIf=\"!customIcon && isStringIcon && isImgIcon\" [src]=\"iconString\" alt=\"alert icon\" />\r\n <ng-container *ngIf=\"isObjectIcon\">\r\n <i *ngIf=\"iconObject.type === 'fontawesome'\" [ngClass]=\"iconObject.value\"></i>\r\n <span *ngIf=\"iconObject.type === 'material'\" class=\"material-icons\">{{ iconObject.value }}</span>\r\n <img *ngIf=\"iconObject.type === 'img'\" [src]=\"iconObject.value\" alt=\"alert icon\" />\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"cc-alert-content\">\r\n <div class=\"cc-alert-title\" *ngIf=\"title\">{{ title }}</div>\r\n <div class=\"cc-alert-message\" *ngIf=\"message\">{{ message }}</div>\r\n <ng-content></ng-content>\r\n </div>\r\n</div>", styles: [".cc-alert{display:flex;align-items:flex-start;width:100%;padding:var(--cc-alert-padding, 1rem 2rem);border-radius:var(--cc-alert-radius, .75rem);gap:var(--cc-alert-gap, 1rem);box-sizing:border-box;font-family:var(--cc-alert-font-family, inherit)}.cc-alert .cc-alert-icon{font-size:var(--cc-alert-icon-size, 1.25rem);flex-shrink:0;margin-top:var(--cc-alert-icon-margin-top, .125rem)}.cc-alert .cc-alert-icon img{width:var(--cc-alert-icon-size, 1.25rem);height:var(--cc-alert-icon-size, 1.25rem);object-fit:contain}.cc-alert .cc-alert-content{display:flex;flex-direction:column;gap:.25rem;flex-grow:1}.cc-alert .cc-alert-content .cc-alert-title{font-weight:700;font-size:var(--cc-alert-title-size, 1rem);line-height:var(--cc-alert-title-line-height, 1.5rem)}.cc-alert .cc-alert-content .cc-alert-message{font-size:var(--cc-alert-message-size, .875rem);line-height:200%;opacity:.9}.cc-alert.cc-alert-info{background-color:var(--cc-alert-info-bg);color:var(--cc-alert-info-color)}.cc-alert.cc-alert-info .cc-alert-icon{color:#5f6368}.cc-alert.cc-alert-warning{background-color:var(--cc-alert-warning-bg);color:var(--cc-alert-warning-color)}.cc-alert.cc-alert-warning .cc-alert-title,.cc-alert.cc-alert-warning .cc-alert-icon{color:var(--cc-alert-warning-title-color)}.cc-alert.cc-alert-warning-shadow{background-color:var(--cc-alert-warning-bg);color:var(--cc-alert-warning-color);box-shadow:var(--cc-alert-warning-shadow)}.cc-alert.cc-alert-warning-shadow .cc-alert-title,.cc-alert.cc-alert-warning-shadow .cc-alert-icon{color:var(--cc-alert-warning-title-color)}.cc-alert.cc-alert-success{background-color:var(--cc-alert-success-bg);color:var(--cc-alert-success-color)}.cc-alert.cc-alert-error{background-color:var(--cc-alert-error-bg);color:var(--cc-alert-error-color)}.cc-alert.cc-alert-error .cc-alert-icon{color:var(--cc-alert-error-color)}\n"] }]
294
+ args: [{ selector: 'lib-alert', standalone: false, template: "<div class=\"cc-alert\" [ngClass]=\"'cc-alert-' + variant\" [style.width]=\"width\" [style.height]=\"height\"\r\n [style.border-radius]=\"borderRadius\" [style.border-top-left-radius]=\"borderTopLeftRadius\"\r\n [style.border-top-right-radius]=\"borderTopRightRadius\" [style.border-bottom-left-radius]=\"borderBottomLeftRadius\"\r\n [style.border-bottom-right-radius]=\"borderBottomRightRadius\" [style.padding]=\"padding\" [style.gap]=\"gap\"\r\n [style.background-color]=\"backgroundColor\" [style.color]=\"color\" [style.border-color]=\"borderColor\"\r\n [style.font-size]=\"fontSize\" [style.font-weight]=\"fontWeight\" [style.box-shadow]=\"boxShadow\">\r\n\r\n <div class=\"cc-alert-icon\" *ngIf=\"icon\">\r\n <i *ngIf=\"customIcon\" [ngClass]=\"customIcon\"></i>\r\n <i *ngIf=\"!customIcon && isDefaultIcon\" [ngClass]=\"defaultIconClass\"></i>\r\n <i *ngIf=\"!customIcon && isStringIcon && !isImgIcon\" [ngClass]=\"iconString\"></i>\r\n <img *ngIf=\"!customIcon && isStringIcon && isImgIcon\" [src]=\"iconString\"\r\n [attr.alt]=\"labels?.iconAltText || 'alert icon'\" />\r\n <ng-container *ngIf=\"isObjectIcon\">\r\n <i *ngIf=\"iconObject.type === 'fontawesome'\" [ngClass]=\"iconObject.value\"></i>\r\n <span *ngIf=\"iconObject.type === 'material'\" class=\"material-icons\">{{ iconObject.value }}</span>\r\n <img *ngIf=\"iconObject.type === 'img'\" [src]=\"iconObject.value\"\r\n [attr.alt]=\"labels?.iconAltText || 'alert icon'\" />\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"cc-alert-content\">\r\n <div class=\"cc-alert-title\" *ngIf=\"title\">{{ title }}</div>\r\n <div class=\"cc-alert-message\" *ngIf=\"message\">{{ message }}</div>\r\n <ng-content></ng-content>\r\n </div>\r\n</div>", styles: [".cc-alert{display:flex;align-items:flex-start;width:100%;padding:var(--cc-alert-padding, 1rem 2rem);border-radius:var(--cc-alert-radius, .75rem);gap:var(--cc-alert-gap, 1rem);box-sizing:border-box;font-family:var(--cc-alert-font-family, inherit)}.cc-alert .cc-alert-icon{font-size:var(--cc-alert-icon-size, 1.25rem);flex-shrink:0;margin-top:var(--cc-alert-icon-margin-top, .125rem)}.cc-alert .cc-alert-icon img{width:var(--cc-alert-icon-size, 1.25rem);height:var(--cc-alert-icon-size, 1.25rem);object-fit:contain}.cc-alert .cc-alert-content{display:flex;flex-direction:column;gap:.25rem;flex-grow:1}.cc-alert .cc-alert-content .cc-alert-title{font-weight:700;font-size:var(--cc-alert-title-size, 1rem);line-height:var(--cc-alert-title-line-height, 1.5rem)}.cc-alert .cc-alert-content .cc-alert-message{font-size:var(--cc-alert-message-size, .875rem);line-height:200%;opacity:.9}.cc-alert.cc-alert-info{background-color:var(--cc-alert-info-bg);color:var(--cc-alert-info-color)}.cc-alert.cc-alert-info .cc-alert-icon{color:#5f6368}.cc-alert.cc-alert-warning{background-color:var(--cc-alert-warning-bg);color:var(--cc-alert-warning-color)}.cc-alert.cc-alert-warning .cc-alert-title,.cc-alert.cc-alert-warning .cc-alert-icon{color:var(--cc-alert-warning-title-color)}.cc-alert.cc-alert-warning-shadow{background-color:var(--cc-alert-warning-bg);color:var(--cc-alert-warning-color);box-shadow:var(--cc-alert-warning-shadow)}.cc-alert.cc-alert-warning-shadow .cc-alert-title,.cc-alert.cc-alert-warning-shadow .cc-alert-icon{color:var(--cc-alert-warning-title-color)}.cc-alert.cc-alert-success{background-color:var(--cc-alert-success-bg);color:var(--cc-alert-success-color)}.cc-alert.cc-alert-error{background-color:var(--cc-alert-error-bg);color:var(--cc-alert-error-color)}.cc-alert.cc-alert-error .cc-alert-icon{color:var(--cc-alert-error-color)}\n"] }]
294
295
  }], ctorParameters: () => [], propDecorators: { variant: [{
295
296
  type: Input
296
297
  }], title: [{
@@ -301,6 +302,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
301
302
  type: Input
302
303
  }], customIcon: [{
303
304
  type: Input
305
+ }], labels: [{
306
+ type: Input
304
307
  }], width: [{
305
308
  type: Input
306
309
  }], height: [{
@@ -367,6 +370,7 @@ class ButtonComponent {
367
370
  color;
368
371
  border;
369
372
  icon = '';
373
+ labels;
370
374
  constructor() { }
371
375
  ngOnInit() {
372
376
  }
@@ -393,11 +397,11 @@ class ButtonComponent {
393
397
  return typeof this.icon === 'object' ? this.icon : { type: '', value: '' };
394
398
  }
395
399
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
396
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ButtonComponent, isStandalone: false, selector: "lib-button", inputs: { variant: "variant", type: "type", disabled: "disabled", width: "width", height: "height", borderRadius: "borderRadius", fontSize: "fontSize", fontWeight: "fontWeight", backgroundColor: "backgroundColor", color: "color", border: "border", icon: "icon" }, ngImport: i0, template: "<button [type]=\"type\" [disabled]=\"disabled\" class=\"cc-btn\" [ngClass]=\"'cc-btn-' + variant\" [style.width]=\"width\"\r\n [style.height]=\"height\" [style.border-radius]=\"borderRadius\" [style.font-size]=\"fontSize\"\r\n [style.font-weight]=\"fontWeight\" [style.background-color]=\"backgroundColor\" [style.color]=\"color\"\r\n [style.border]=\"border\">\r\n <div class=\"cc-btn-icon-wrapper\" *ngIf=\"icon\">\r\n <!-- String Icons -->\r\n <ng-container *ngIf=\"isStringIcon\">\r\n <i *ngIf=\"!isImgIcon\" [ngClass]=\"iconString\" class=\"cc-btn-icon\"></i>\r\n <img *ngIf=\"isImgIcon\" [src]=\"iconString\" alt=\"button icon\" class=\"cc-btn-icon cc-btn-img-icon\" />\r\n </ng-container>\r\n\r\n <!-- Object Icons -->\r\n <ng-container *ngIf=\"isObjectIcon\">\r\n <i *ngIf=\"iconObject.type === 'fontawesome'\" [ngClass]=\"iconObject.value\" class=\"cc-btn-icon\"></i>\r\n <span *ngIf=\"iconObject.type === 'material'\" class=\"material-icons cc-btn-icon\">{{ iconObject.value }}</span>\r\n <img *ngIf=\"iconObject.type === 'img'\" [src]=\"iconObject.value\" alt=\"button icon\"\r\n class=\"cc-btn-icon cc-btn-img-icon\" />\r\n </ng-container>\r\n </div>\r\n <ng-content></ng-content>\r\n</button>", styles: [".cc-btn{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;cursor:pointer;transition:all .2s ease-in-out;font-family:var(--cc-btn-font-family);font-weight:var(--cc-btn-font-weight);font-size:var(--cc-btn-font-size);padding:var(--cc-btn-padding)}.cc-btn:disabled{opacity:var(--cc-btn-disabled-opacity);cursor:var(--cc-btn-disabled-cursor);pointer-events:none}.cc-btn.cc-btn-primary{background-color:var(--cc-btn-primary-bg);color:var(--cc-btn-primary-color);border-radius:var(--cc-btn-primary-radius);border:var(--cc-btn-primary-border)}.cc-btn.cc-btn-warning{background-color:var(--cc-btn-warning-bg);color:var(--cc-btn-warning-color);border-radius:var(--cc-btn-warning-radius);border:var(--cc-btn-warning-border)}.cc-btn.cc-btn-outline{background-color:var(--cc-btn-outline-bg);color:var(--cc-btn-outline-color);border-radius:var(--cc-btn-outline-radius);border:var(--cc-btn-outline-border)}.cc-btn.cc-btn-secondary{background-color:var(--cc-btn-secondary-bg);color:var(--cc-btn-secondary-color);border-radius:var(--cc-btn-secondary-radius);border:var(--cc-btn-secondary-border)}.cc-btn.cc-btn-success{background-color:var(--cc-btn-success-bg);color:var(--cc-btn-success-color);border-radius:var(--cc-btn-success-radius);border:var(--cc-btn-success-border)}.cc-btn.cc-btn-danger{background-color:var(--cc-btn-danger-bg);color:var(--cc-btn-danger-color);border-radius:var(--cc-btn-danger-radius);border:var(--cc-btn-danger-border)}.cc-btn.cc-btn-danger-outline{background-color:var(--cc-btn-danger-outline-bg);color:var(--cc-btn-danger-outline-color);border-radius:var(--cc-btn-danger-outline-radius);border:var(--cc-btn-danger-outline-border)}.cc-btn .cc-btn-icon-wrapper{display:inline-flex;align-items:center;margin-right:.5rem}.cc-btn .cc-btn-icon{font-size:1.1em;line-height:1}.cc-btn .cc-btn-img-icon{width:1.25rem;height:1.25rem;object-fit:contain}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
400
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ButtonComponent, isStandalone: false, selector: "lib-button", inputs: { variant: "variant", type: "type", disabled: "disabled", width: "width", height: "height", borderRadius: "borderRadius", fontSize: "fontSize", fontWeight: "fontWeight", backgroundColor: "backgroundColor", color: "color", border: "border", icon: "icon", labels: "labels" }, ngImport: i0, template: "<button [type]=\"type\" [disabled]=\"disabled\" class=\"cc-btn\" [ngClass]=\"'cc-btn-' + variant\" [style.width]=\"width\"\r\n [style.height]=\"height\" [style.border-radius]=\"borderRadius\" [style.font-size]=\"fontSize\"\r\n [style.font-weight]=\"fontWeight\" [style.background-color]=\"backgroundColor\" [style.color]=\"color\"\r\n [style.border]=\"border\">\r\n <div class=\"cc-btn-icon-wrapper\" *ngIf=\"icon\">\r\n <!-- String Icons -->\r\n <ng-container *ngIf=\"isStringIcon\">\r\n <i *ngIf=\"!isImgIcon\" [ngClass]=\"iconString\" class=\"cc-btn-icon\"></i>\r\n <img *ngIf=\"isImgIcon\" [src]=\"iconString\" [attr.alt]=\"labels?.iconAltText || 'button icon'\"\r\n class=\"cc-btn-icon cc-btn-img-icon\" />\r\n </ng-container>\r\n\r\n <!-- Object Icons -->\r\n <ng-container *ngIf=\"isObjectIcon\">\r\n <i *ngIf=\"iconObject.type === 'fontawesome'\" [ngClass]=\"iconObject.value\" class=\"cc-btn-icon\"></i>\r\n <span *ngIf=\"iconObject.type === 'material'\" class=\"material-icons cc-btn-icon\">{{ iconObject.value }}</span>\r\n <img *ngIf=\"iconObject.type === 'img'\" [src]=\"iconObject.value\" [attr.alt]=\"labels?.iconAltText || 'button icon'\"\r\n class=\"cc-btn-icon cc-btn-img-icon\" />\r\n </ng-container>\r\n </div>\r\n <ng-content></ng-content>\r\n</button>", styles: [".cc-btn{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;cursor:pointer;transition:all .2s ease-in-out;font-family:var(--cc-btn-font-family);font-weight:var(--cc-btn-font-weight);font-size:var(--cc-btn-font-size);padding:var(--cc-btn-padding)}.cc-btn:disabled{opacity:var(--cc-btn-disabled-opacity);cursor:var(--cc-btn-disabled-cursor);pointer-events:none}.cc-btn.cc-btn-primary{background-color:var(--cc-btn-primary-bg);color:var(--cc-btn-primary-color);border-radius:var(--cc-btn-primary-radius);border:var(--cc-btn-primary-border)}.cc-btn.cc-btn-warning{background-color:var(--cc-btn-warning-bg);color:var(--cc-btn-warning-color);border-radius:var(--cc-btn-warning-radius);border:var(--cc-btn-warning-border)}.cc-btn.cc-btn-outline{background-color:var(--cc-btn-outline-bg);color:var(--cc-btn-outline-color);border-radius:var(--cc-btn-outline-radius);border:var(--cc-btn-outline-border)}.cc-btn.cc-btn-secondary{background-color:var(--cc-btn-secondary-bg);color:var(--cc-btn-secondary-color);border-radius:var(--cc-btn-secondary-radius);border:var(--cc-btn-secondary-border)}.cc-btn.cc-btn-success{background-color:var(--cc-btn-success-bg);color:var(--cc-btn-success-color);border-radius:var(--cc-btn-success-radius);border:var(--cc-btn-success-border)}.cc-btn.cc-btn-danger{background-color:var(--cc-btn-danger-bg);color:var(--cc-btn-danger-color);border-radius:var(--cc-btn-danger-radius);border:var(--cc-btn-danger-border)}.cc-btn.cc-btn-danger-outline{background-color:var(--cc-btn-danger-outline-bg);color:var(--cc-btn-danger-outline-color);border-radius:var(--cc-btn-danger-outline-radius);border:var(--cc-btn-danger-outline-border)}.cc-btn .cc-btn-icon-wrapper{display:inline-flex;align-items:center;margin-right:.5rem}.cc-btn .cc-btn-icon{font-size:1.1em;line-height:1}.cc-btn .cc-btn-img-icon{width:1.25rem;height:1.25rem;object-fit:contain}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
397
401
  }
398
402
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ButtonComponent, decorators: [{
399
403
  type: Component,
400
- args: [{ selector: 'lib-button', standalone: false, template: "<button [type]=\"type\" [disabled]=\"disabled\" class=\"cc-btn\" [ngClass]=\"'cc-btn-' + variant\" [style.width]=\"width\"\r\n [style.height]=\"height\" [style.border-radius]=\"borderRadius\" [style.font-size]=\"fontSize\"\r\n [style.font-weight]=\"fontWeight\" [style.background-color]=\"backgroundColor\" [style.color]=\"color\"\r\n [style.border]=\"border\">\r\n <div class=\"cc-btn-icon-wrapper\" *ngIf=\"icon\">\r\n <!-- String Icons -->\r\n <ng-container *ngIf=\"isStringIcon\">\r\n <i *ngIf=\"!isImgIcon\" [ngClass]=\"iconString\" class=\"cc-btn-icon\"></i>\r\n <img *ngIf=\"isImgIcon\" [src]=\"iconString\" alt=\"button icon\" class=\"cc-btn-icon cc-btn-img-icon\" />\r\n </ng-container>\r\n\r\n <!-- Object Icons -->\r\n <ng-container *ngIf=\"isObjectIcon\">\r\n <i *ngIf=\"iconObject.type === 'fontawesome'\" [ngClass]=\"iconObject.value\" class=\"cc-btn-icon\"></i>\r\n <span *ngIf=\"iconObject.type === 'material'\" class=\"material-icons cc-btn-icon\">{{ iconObject.value }}</span>\r\n <img *ngIf=\"iconObject.type === 'img'\" [src]=\"iconObject.value\" alt=\"button icon\"\r\n class=\"cc-btn-icon cc-btn-img-icon\" />\r\n </ng-container>\r\n </div>\r\n <ng-content></ng-content>\r\n</button>", styles: [".cc-btn{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;cursor:pointer;transition:all .2s ease-in-out;font-family:var(--cc-btn-font-family);font-weight:var(--cc-btn-font-weight);font-size:var(--cc-btn-font-size);padding:var(--cc-btn-padding)}.cc-btn:disabled{opacity:var(--cc-btn-disabled-opacity);cursor:var(--cc-btn-disabled-cursor);pointer-events:none}.cc-btn.cc-btn-primary{background-color:var(--cc-btn-primary-bg);color:var(--cc-btn-primary-color);border-radius:var(--cc-btn-primary-radius);border:var(--cc-btn-primary-border)}.cc-btn.cc-btn-warning{background-color:var(--cc-btn-warning-bg);color:var(--cc-btn-warning-color);border-radius:var(--cc-btn-warning-radius);border:var(--cc-btn-warning-border)}.cc-btn.cc-btn-outline{background-color:var(--cc-btn-outline-bg);color:var(--cc-btn-outline-color);border-radius:var(--cc-btn-outline-radius);border:var(--cc-btn-outline-border)}.cc-btn.cc-btn-secondary{background-color:var(--cc-btn-secondary-bg);color:var(--cc-btn-secondary-color);border-radius:var(--cc-btn-secondary-radius);border:var(--cc-btn-secondary-border)}.cc-btn.cc-btn-success{background-color:var(--cc-btn-success-bg);color:var(--cc-btn-success-color);border-radius:var(--cc-btn-success-radius);border:var(--cc-btn-success-border)}.cc-btn.cc-btn-danger{background-color:var(--cc-btn-danger-bg);color:var(--cc-btn-danger-color);border-radius:var(--cc-btn-danger-radius);border:var(--cc-btn-danger-border)}.cc-btn.cc-btn-danger-outline{background-color:var(--cc-btn-danger-outline-bg);color:var(--cc-btn-danger-outline-color);border-radius:var(--cc-btn-danger-outline-radius);border:var(--cc-btn-danger-outline-border)}.cc-btn .cc-btn-icon-wrapper{display:inline-flex;align-items:center;margin-right:.5rem}.cc-btn .cc-btn-icon{font-size:1.1em;line-height:1}.cc-btn .cc-btn-img-icon{width:1.25rem;height:1.25rem;object-fit:contain}\n"] }]
404
+ args: [{ selector: 'lib-button', standalone: false, template: "<button [type]=\"type\" [disabled]=\"disabled\" class=\"cc-btn\" [ngClass]=\"'cc-btn-' + variant\" [style.width]=\"width\"\r\n [style.height]=\"height\" [style.border-radius]=\"borderRadius\" [style.font-size]=\"fontSize\"\r\n [style.font-weight]=\"fontWeight\" [style.background-color]=\"backgroundColor\" [style.color]=\"color\"\r\n [style.border]=\"border\">\r\n <div class=\"cc-btn-icon-wrapper\" *ngIf=\"icon\">\r\n <!-- String Icons -->\r\n <ng-container *ngIf=\"isStringIcon\">\r\n <i *ngIf=\"!isImgIcon\" [ngClass]=\"iconString\" class=\"cc-btn-icon\"></i>\r\n <img *ngIf=\"isImgIcon\" [src]=\"iconString\" [attr.alt]=\"labels?.iconAltText || 'button icon'\"\r\n class=\"cc-btn-icon cc-btn-img-icon\" />\r\n </ng-container>\r\n\r\n <!-- Object Icons -->\r\n <ng-container *ngIf=\"isObjectIcon\">\r\n <i *ngIf=\"iconObject.type === 'fontawesome'\" [ngClass]=\"iconObject.value\" class=\"cc-btn-icon\"></i>\r\n <span *ngIf=\"iconObject.type === 'material'\" class=\"material-icons cc-btn-icon\">{{ iconObject.value }}</span>\r\n <img *ngIf=\"iconObject.type === 'img'\" [src]=\"iconObject.value\" [attr.alt]=\"labels?.iconAltText || 'button icon'\"\r\n class=\"cc-btn-icon cc-btn-img-icon\" />\r\n </ng-container>\r\n </div>\r\n <ng-content></ng-content>\r\n</button>", styles: [".cc-btn{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;cursor:pointer;transition:all .2s ease-in-out;font-family:var(--cc-btn-font-family);font-weight:var(--cc-btn-font-weight);font-size:var(--cc-btn-font-size);padding:var(--cc-btn-padding)}.cc-btn:disabled{opacity:var(--cc-btn-disabled-opacity);cursor:var(--cc-btn-disabled-cursor);pointer-events:none}.cc-btn.cc-btn-primary{background-color:var(--cc-btn-primary-bg);color:var(--cc-btn-primary-color);border-radius:var(--cc-btn-primary-radius);border:var(--cc-btn-primary-border)}.cc-btn.cc-btn-warning{background-color:var(--cc-btn-warning-bg);color:var(--cc-btn-warning-color);border-radius:var(--cc-btn-warning-radius);border:var(--cc-btn-warning-border)}.cc-btn.cc-btn-outline{background-color:var(--cc-btn-outline-bg);color:var(--cc-btn-outline-color);border-radius:var(--cc-btn-outline-radius);border:var(--cc-btn-outline-border)}.cc-btn.cc-btn-secondary{background-color:var(--cc-btn-secondary-bg);color:var(--cc-btn-secondary-color);border-radius:var(--cc-btn-secondary-radius);border:var(--cc-btn-secondary-border)}.cc-btn.cc-btn-success{background-color:var(--cc-btn-success-bg);color:var(--cc-btn-success-color);border-radius:var(--cc-btn-success-radius);border:var(--cc-btn-success-border)}.cc-btn.cc-btn-danger{background-color:var(--cc-btn-danger-bg);color:var(--cc-btn-danger-color);border-radius:var(--cc-btn-danger-radius);border:var(--cc-btn-danger-border)}.cc-btn.cc-btn-danger-outline{background-color:var(--cc-btn-danger-outline-bg);color:var(--cc-btn-danger-outline-color);border-radius:var(--cc-btn-danger-outline-radius);border:var(--cc-btn-danger-outline-border)}.cc-btn .cc-btn-icon-wrapper{display:inline-flex;align-items:center;margin-right:.5rem}.cc-btn .cc-btn-icon{font-size:1.1em;line-height:1}.cc-btn .cc-btn-img-icon{width:1.25rem;height:1.25rem;object-fit:contain}\n"] }]
401
405
  }], ctorParameters: () => [], propDecorators: { variant: [{
402
406
  type: Input
403
407
  }], type: [{
@@ -422,6 +426,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
422
426
  type: Input
423
427
  }], icon: [{
424
428
  type: Input
429
+ }], labels: [{
430
+ type: Input
425
431
  }] } });
426
432
 
427
433
  class ButtonModule {
@@ -460,7 +466,7 @@ class ConfirmationModalComponent {
460
466
  closeOnEsc: true,
461
467
  showCloseButton: true,
462
468
  cancelButton: {
463
- label: 'Cancel',
469
+ label: '',
464
470
  show: true
465
471
  }
466
472
  };
@@ -576,63 +582,2009 @@ class ConfirmationModalComponent {
576
582
  }
577
583
  return 'material';
578
584
  }
579
- getIconValue(icon) {
580
- return typeof icon === 'string' ? icon : icon?.value;
585
+ getIconValue(icon) {
586
+ return typeof icon === 'string' ? icon : icon?.value;
587
+ }
588
+ getIconColor(icon) {
589
+ return typeof icon === 'object' ? icon.color : undefined;
590
+ }
591
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
592
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ConfirmationModalComponent, isStandalone: false, selector: "cc-confirmation-modal", inputs: { config: "config", isOpen: "isOpen" }, outputs: { confirm: "confirm", cancel: "cancel", close: "close", showCodeSnippet: "showCodeSnippet" }, host: { listeners: { "document:keydown.escape": "handleEscape($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"isOpen\" class=\"cc-modal-backdrop\" (click)=\"onBackdropClick($event)\" role=\"dialog\" [attr.aria-modal]=\"true\"\r\n [attr.aria-labelledby]=\"'modal-title-' + mergedConfig.title\" [attr.aria-label]=\"mergedConfig.ariaLabel\"\r\n [attr.aria-describedby]=\"mergedConfig.ariaDescribedBy\">\r\n\r\n <div class=\"cc-modal-container {{ mergedConfig.customClass }}\" [style.width]=\"getModalWidth()\"\r\n [style.background-color]=\"mergedConfig.backgroundColor\" [style.border-radius]=\"mergedConfig.borderRadius\"\r\n [style.border-top-left-radius]=\"mergedConfig.borderTopLeftRadius\"\r\n [style.border-top-right-radius]=\"mergedConfig.borderTopRightRadius\"\r\n [style.border-bottom-left-radius]=\"mergedConfig.borderBottomLeftRadius\"\r\n [style.border-bottom-right-radius]=\"mergedConfig.borderBottomRightRadius\" (click)=\"$event.stopPropagation()\">\r\n\r\n <!-- Header -->\r\n <div [ngClass]=\"getHeaderClass()\" [style.background-color]=\"mergedConfig.headerBackgroundColor\"\r\n [style.border-bottom]=\"mergedConfig.headerBorderBottom\">\r\n <div class=\"modal-header__content\">\r\n <!-- Icon (Optional) -->\r\n <span *ngIf=\"mergedConfig.icon\" class=\"modal-header__icon\">\r\n <ng-container [ngSwitch]=\"resolveIconType(mergedConfig.icon)\">\r\n <mat-icon *ngSwitchCase=\"'material'\" [style.color]=\"getIconColor(mergedConfig.icon)\">\r\n {{ getIconValue(mergedConfig.icon) }}\r\n </mat-icon>\r\n <img *ngSwitchCase=\"'custom'\" [src]=\"getIconValue(mergedConfig.icon)\"\r\n [attr.alt]=\"mergedConfig.labels?.iconAltText || mergedConfig.title + ' icon'\"\r\n class=\"modal-header__custom-icon\">\r\n <img *ngSwitchCase=\"'img'\" [src]=\"getIconValue(mergedConfig.icon)\"\r\n [attr.alt]=\"mergedConfig.labels?.iconAltText || mergedConfig.title + ' icon'\"\r\n class=\"modal-header__custom-icon\">\r\n </ng-container>\r\n </span>\r\n\r\n <!-- Title -->\r\n <h2 class=\"modal-header__title\" [id]=\"'modal-title-' + mergedConfig.title\"\r\n [style.color]=\"mergedConfig.headerTextColor\">\r\n {{ mergedConfig.title }}\r\n </h2>\r\n </div>\r\n\r\n <!-- Code Snippet Button -->\r\n <button *ngIf=\"mergedConfig.showCodeSnippetButton\" type=\"button\" class=\"modal-header__code-btn\"\r\n (click)=\"onShowCodeSnippet()\" [attr.aria-label]=\"mergedConfig.labels?.codeSnippetAriaLabel\"\r\n [attr.title]=\"mergedConfig.labels?.codeSnippetTitle\">\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n\r\n <!-- Close Button -->\r\n <button *ngIf=\"mergedConfig.showCloseButton\" type=\"button\" class=\"modal-header__close\" (click)=\"onClose()\"\r\n [attr.aria-label]=\"mergedConfig.labels?.closeAriaLabel\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Body (Content Projection) -->\r\n <div class=\"cc-modal-body\" [style.padding]=\"mergedConfig.padding\" [style.color]=\"mergedConfig.bodyTextColor\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"cc-modal-footer\" [style.background-color]=\"mergedConfig.footerBackgroundColor\"\r\n [style.border-top]=\"mergedConfig.footerBorderTop\">\r\n\r\n <ng-container *ngIf=\"!mergedConfig.customFooter\">\r\n <button *ngIf=\"mergedConfig.cancelButton?.show\" type=\"button\" class=\"cc-btn cc-btn-secondary\"\r\n (click)=\"onCancel()\">\r\n {{ mergedConfig.cancelButton?.label }}\r\n </button>\r\n\r\n <button type=\"button\" [ngClass]=\"getConfirmButtonClass()\"\r\n [disabled]=\"mergedConfig.confirmButton.disabled || mergedConfig.confirmButton.loading\"\r\n (click)=\"onConfirm()\">\r\n <span *ngIf=\"mergedConfig.confirmButton.loading\" class=\"cc-btn-spinner\"></span>\r\n {{ mergedConfig.confirmButton.label }}\r\n </button>\r\n </ng-container>\r\n\r\n <ng-content select=\"[cc-modal-footer]\"></ng-content>\r\n </div>\r\n </div>\r\n</div>", styles: [".cc-modal-backdrop{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;animation:fadeIn .2s ease-in-out}.cc-modal-container{background:var(--cc-modal-bg);border-radius:var(--cc-modal-radius);box-shadow:var(--cc-modal-shadow);border:var(--cc-modal-border, none);display:flex;flex-direction:column;max-height:90vh;max-width:90vw;animation:slideIn .3s ease-out;overflow:hidden}.modal-header{display:flex;align-items:center;justify-content:space-between;padding:var(--cc-modal-header-padding);border-bottom:var(--cc-modal-header-border-bottom)}.modal-header__content{display:flex;align-items:center;gap:.75rem;flex:1}.modal-header__icon{display:flex;align-items:center;justify-content:center}.modal-header__icon mat-icon{font-size:var(--cc-modal-icon-size, 1.5rem);width:var(--cc-modal-icon-size, 1.5rem);height:var(--cc-modal-icon-size, 1.5rem)}.modal-header__custom-icon{width:var(--cc-modal-icon-size, 1.5rem);height:var(--cc-modal-icon-size, 1.5rem);object-fit:contain}.modal-header__title{margin:0;font-size:var(--cc-modal-title-size);font-weight:var(--cc-modal-title-weight);line-height:1.4;color:var(--cc-modal-title-color)}.modal-header__close{background:none;border:none;padding:.25rem;cursor:pointer;color:#6b7280;transition:color .2s;display:flex;align-items:center}.modal-header__close:hover{color:#111827}.modal-header__close mat-icon{font-size:var(--cc-modal-close-icon-size, 1.25rem);width:var(--cc-modal-close-icon-size, 1.25rem);height:var(--cc-modal-close-icon-size, 1.25rem)}.modal-header__code-btn{background:none;border:none;padding:.25rem;margin-right:.5rem;cursor:pointer;color:#6b7280;transition:all .2s;display:flex;align-items:center}.modal-header__code-btn:hover{color:#ef4444;transform:scale(1.1)}.modal-header__code-btn mat-icon{font-size:1.15rem;width:1.15rem;height:1.15rem}.modal-header--dark{background-color:var(--cc-modal-header-bg-dark);border-bottom:none}.modal-header--dark .modal-header__title{color:var(--cc-modal-header-title-color-dark)}.modal-header--dark .modal-header__close{color:#ffffffb3}.modal-header--dark .modal-header__close:hover{color:#fff}.modal-header--dark .modal-header__code-btn{color:#ffffffb3}.modal-header--dark .modal-header__code-btn:hover{color:#fff}.cc-modal-body{padding:var(--cc-modal-body-padding);overflow-y:auto;flex:1;color:var(--cc-modal-body-color);font-size:.875rem;line-height:1.6}.cc-modal-body ::ng-deep input[type=text],.cc-modal-body ::ng-deep textarea,.cc-modal-body ::ng-deep select{width:100%;padding:var(--cc-modal-input-padding, .625rem .75rem);border:.0625rem solid #D1D5DB;border-radius:var(--cc-modal-input-radius, .375rem);font-size:var(--cc-modal-input-font-size, .875rem);transition:border-color .2s}.cc-modal-body ::ng-deep input[type=text]:focus,.cc-modal-body ::ng-deep textarea:focus,.cc-modal-body ::ng-deep select:focus{outline:none;border-color:var(--cc-btn-primary-bg, #3b82f6);box-shadow:0 0 0 .1875rem #3b82f61a}.cc-modal-body ::ng-deep textarea{resize:vertical;min-height:var(--cc-modal-textarea-min-height, 6.25rem)}.cc-modal-body ::ng-deep label{display:block;margin-bottom:var(--cc-modal-label-margin-bottom, .5rem);font-weight:500;color:var(--cc-modal-body-color)}.cc-modal-body ::ng-deep .required:after{content:\" *\";color:#ef4444}.cc-modal-footer{display:flex;align-items:center;justify-content:flex-end;gap:.75rem;padding:var(--cc-modal-footer-padding);border-top:var(--cc-modal-footer-border-top);background:var(--cc-modal-footer-bg)}.cc-btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;padding:var(--cc-btn-padding, .5rem 1rem);font-family:var(--cc-btn-font-family, inherit);font-weight:var(--cc-btn-font-weight, 500);font-size:var(--cc-btn-font-size, .875rem);cursor:pointer;transition:all .2s;min-width:5rem}.cc-btn:disabled{opacity:var(--cc-btn-disabled-opacity, .6);cursor:var(--cc-btn-disabled-cursor, not-allowed)}.cc-btn-secondary{background:var(--cc-btn-secondary-bg);color:var(--cc-btn-secondary-color);border:var(--cc-btn-secondary-border);border-radius:var(--cc-btn-secondary-radius)}.cc-btn-primary{background:var(--cc-btn-primary-bg);color:var(--cc-btn-primary-color);border:var(--cc-btn-primary-border);border-radius:var(--cc-btn-primary-radius)}.cc-btn-danger{background:var(--cc-btn-danger-bg);color:var(--cc-btn-danger-color);border:var(--cc-btn-danger-border);border-radius:var(--cc-btn-danger-radius)}.cc-btn-warning{background:var(--cc-btn-warning-bg);color:var(--cc-btn-warning-color);border:var(--cc-btn-warning-border);border-radius:var(--cc-btn-warning-radius)}.cc-btn-spinner{width:var(--cc-modal-spinner-size, 1rem);height:var(--cc-modal-spinner-size, 1rem);border:.125rem solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin .6s linear infinite}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideIn{0%{transform:translateY(-1.25rem);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes spin{to{transform:rotate(360deg)}}@media(max-width:40rem){.cc-modal-container{width:95vw!important;max-height:95vh}.modal-header,.cc-modal-body{padding:1rem}.cc-modal-footer{padding:.75rem 1rem;flex-direction:column}.cc-modal-footer .cc-btn{width:100%}}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
593
+ }
594
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalComponent, decorators: [{
595
+ type: Component,
596
+ args: [{ selector: 'cc-confirmation-modal', standalone: false, template: "<div *ngIf=\"isOpen\" class=\"cc-modal-backdrop\" (click)=\"onBackdropClick($event)\" role=\"dialog\" [attr.aria-modal]=\"true\"\r\n [attr.aria-labelledby]=\"'modal-title-' + mergedConfig.title\" [attr.aria-label]=\"mergedConfig.ariaLabel\"\r\n [attr.aria-describedby]=\"mergedConfig.ariaDescribedBy\">\r\n\r\n <div class=\"cc-modal-container {{ mergedConfig.customClass }}\" [style.width]=\"getModalWidth()\"\r\n [style.background-color]=\"mergedConfig.backgroundColor\" [style.border-radius]=\"mergedConfig.borderRadius\"\r\n [style.border-top-left-radius]=\"mergedConfig.borderTopLeftRadius\"\r\n [style.border-top-right-radius]=\"mergedConfig.borderTopRightRadius\"\r\n [style.border-bottom-left-radius]=\"mergedConfig.borderBottomLeftRadius\"\r\n [style.border-bottom-right-radius]=\"mergedConfig.borderBottomRightRadius\" (click)=\"$event.stopPropagation()\">\r\n\r\n <!-- Header -->\r\n <div [ngClass]=\"getHeaderClass()\" [style.background-color]=\"mergedConfig.headerBackgroundColor\"\r\n [style.border-bottom]=\"mergedConfig.headerBorderBottom\">\r\n <div class=\"modal-header__content\">\r\n <!-- Icon (Optional) -->\r\n <span *ngIf=\"mergedConfig.icon\" class=\"modal-header__icon\">\r\n <ng-container [ngSwitch]=\"resolveIconType(mergedConfig.icon)\">\r\n <mat-icon *ngSwitchCase=\"'material'\" [style.color]=\"getIconColor(mergedConfig.icon)\">\r\n {{ getIconValue(mergedConfig.icon) }}\r\n </mat-icon>\r\n <img *ngSwitchCase=\"'custom'\" [src]=\"getIconValue(mergedConfig.icon)\"\r\n [attr.alt]=\"mergedConfig.labels?.iconAltText || mergedConfig.title + ' icon'\"\r\n class=\"modal-header__custom-icon\">\r\n <img *ngSwitchCase=\"'img'\" [src]=\"getIconValue(mergedConfig.icon)\"\r\n [attr.alt]=\"mergedConfig.labels?.iconAltText || mergedConfig.title + ' icon'\"\r\n class=\"modal-header__custom-icon\">\r\n </ng-container>\r\n </span>\r\n\r\n <!-- Title -->\r\n <h2 class=\"modal-header__title\" [id]=\"'modal-title-' + mergedConfig.title\"\r\n [style.color]=\"mergedConfig.headerTextColor\">\r\n {{ mergedConfig.title }}\r\n </h2>\r\n </div>\r\n\r\n <!-- Code Snippet Button -->\r\n <button *ngIf=\"mergedConfig.showCodeSnippetButton\" type=\"button\" class=\"modal-header__code-btn\"\r\n (click)=\"onShowCodeSnippet()\" [attr.aria-label]=\"mergedConfig.labels?.codeSnippetAriaLabel\"\r\n [attr.title]=\"mergedConfig.labels?.codeSnippetTitle\">\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n\r\n <!-- Close Button -->\r\n <button *ngIf=\"mergedConfig.showCloseButton\" type=\"button\" class=\"modal-header__close\" (click)=\"onClose()\"\r\n [attr.aria-label]=\"mergedConfig.labels?.closeAriaLabel\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Body (Content Projection) -->\r\n <div class=\"cc-modal-body\" [style.padding]=\"mergedConfig.padding\" [style.color]=\"mergedConfig.bodyTextColor\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"cc-modal-footer\" [style.background-color]=\"mergedConfig.footerBackgroundColor\"\r\n [style.border-top]=\"mergedConfig.footerBorderTop\">\r\n\r\n <ng-container *ngIf=\"!mergedConfig.customFooter\">\r\n <button *ngIf=\"mergedConfig.cancelButton?.show\" type=\"button\" class=\"cc-btn cc-btn-secondary\"\r\n (click)=\"onCancel()\">\r\n {{ mergedConfig.cancelButton?.label }}\r\n </button>\r\n\r\n <button type=\"button\" [ngClass]=\"getConfirmButtonClass()\"\r\n [disabled]=\"mergedConfig.confirmButton.disabled || mergedConfig.confirmButton.loading\"\r\n (click)=\"onConfirm()\">\r\n <span *ngIf=\"mergedConfig.confirmButton.loading\" class=\"cc-btn-spinner\"></span>\r\n {{ mergedConfig.confirmButton.label }}\r\n </button>\r\n </ng-container>\r\n\r\n <ng-content select=\"[cc-modal-footer]\"></ng-content>\r\n </div>\r\n </div>\r\n</div>", styles: [".cc-modal-backdrop{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;animation:fadeIn .2s ease-in-out}.cc-modal-container{background:var(--cc-modal-bg);border-radius:var(--cc-modal-radius);box-shadow:var(--cc-modal-shadow);border:var(--cc-modal-border, none);display:flex;flex-direction:column;max-height:90vh;max-width:90vw;animation:slideIn .3s ease-out;overflow:hidden}.modal-header{display:flex;align-items:center;justify-content:space-between;padding:var(--cc-modal-header-padding);border-bottom:var(--cc-modal-header-border-bottom)}.modal-header__content{display:flex;align-items:center;gap:.75rem;flex:1}.modal-header__icon{display:flex;align-items:center;justify-content:center}.modal-header__icon mat-icon{font-size:var(--cc-modal-icon-size, 1.5rem);width:var(--cc-modal-icon-size, 1.5rem);height:var(--cc-modal-icon-size, 1.5rem)}.modal-header__custom-icon{width:var(--cc-modal-icon-size, 1.5rem);height:var(--cc-modal-icon-size, 1.5rem);object-fit:contain}.modal-header__title{margin:0;font-size:var(--cc-modal-title-size);font-weight:var(--cc-modal-title-weight);line-height:1.4;color:var(--cc-modal-title-color)}.modal-header__close{background:none;border:none;padding:.25rem;cursor:pointer;color:#6b7280;transition:color .2s;display:flex;align-items:center}.modal-header__close:hover{color:#111827}.modal-header__close mat-icon{font-size:var(--cc-modal-close-icon-size, 1.25rem);width:var(--cc-modal-close-icon-size, 1.25rem);height:var(--cc-modal-close-icon-size, 1.25rem)}.modal-header__code-btn{background:none;border:none;padding:.25rem;margin-right:.5rem;cursor:pointer;color:#6b7280;transition:all .2s;display:flex;align-items:center}.modal-header__code-btn:hover{color:#ef4444;transform:scale(1.1)}.modal-header__code-btn mat-icon{font-size:1.15rem;width:1.15rem;height:1.15rem}.modal-header--dark{background-color:var(--cc-modal-header-bg-dark);border-bottom:none}.modal-header--dark .modal-header__title{color:var(--cc-modal-header-title-color-dark)}.modal-header--dark .modal-header__close{color:#ffffffb3}.modal-header--dark .modal-header__close:hover{color:#fff}.modal-header--dark .modal-header__code-btn{color:#ffffffb3}.modal-header--dark .modal-header__code-btn:hover{color:#fff}.cc-modal-body{padding:var(--cc-modal-body-padding);overflow-y:auto;flex:1;color:var(--cc-modal-body-color);font-size:.875rem;line-height:1.6}.cc-modal-body ::ng-deep input[type=text],.cc-modal-body ::ng-deep textarea,.cc-modal-body ::ng-deep select{width:100%;padding:var(--cc-modal-input-padding, .625rem .75rem);border:.0625rem solid #D1D5DB;border-radius:var(--cc-modal-input-radius, .375rem);font-size:var(--cc-modal-input-font-size, .875rem);transition:border-color .2s}.cc-modal-body ::ng-deep input[type=text]:focus,.cc-modal-body ::ng-deep textarea:focus,.cc-modal-body ::ng-deep select:focus{outline:none;border-color:var(--cc-btn-primary-bg, #3b82f6);box-shadow:0 0 0 .1875rem #3b82f61a}.cc-modal-body ::ng-deep textarea{resize:vertical;min-height:var(--cc-modal-textarea-min-height, 6.25rem)}.cc-modal-body ::ng-deep label{display:block;margin-bottom:var(--cc-modal-label-margin-bottom, .5rem);font-weight:500;color:var(--cc-modal-body-color)}.cc-modal-body ::ng-deep .required:after{content:\" *\";color:#ef4444}.cc-modal-footer{display:flex;align-items:center;justify-content:flex-end;gap:.75rem;padding:var(--cc-modal-footer-padding);border-top:var(--cc-modal-footer-border-top);background:var(--cc-modal-footer-bg)}.cc-btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;padding:var(--cc-btn-padding, .5rem 1rem);font-family:var(--cc-btn-font-family, inherit);font-weight:var(--cc-btn-font-weight, 500);font-size:var(--cc-btn-font-size, .875rem);cursor:pointer;transition:all .2s;min-width:5rem}.cc-btn:disabled{opacity:var(--cc-btn-disabled-opacity, .6);cursor:var(--cc-btn-disabled-cursor, not-allowed)}.cc-btn-secondary{background:var(--cc-btn-secondary-bg);color:var(--cc-btn-secondary-color);border:var(--cc-btn-secondary-border);border-radius:var(--cc-btn-secondary-radius)}.cc-btn-primary{background:var(--cc-btn-primary-bg);color:var(--cc-btn-primary-color);border:var(--cc-btn-primary-border);border-radius:var(--cc-btn-primary-radius)}.cc-btn-danger{background:var(--cc-btn-danger-bg);color:var(--cc-btn-danger-color);border:var(--cc-btn-danger-border);border-radius:var(--cc-btn-danger-radius)}.cc-btn-warning{background:var(--cc-btn-warning-bg);color:var(--cc-btn-warning-color);border:var(--cc-btn-warning-border);border-radius:var(--cc-btn-warning-radius)}.cc-btn-spinner{width:var(--cc-modal-spinner-size, 1rem);height:var(--cc-modal-spinner-size, 1rem);border:.125rem solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin .6s linear infinite}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideIn{0%{transform:translateY(-1.25rem);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes spin{to{transform:rotate(360deg)}}@media(max-width:40rem){.cc-modal-container{width:95vw!important;max-height:95vh}.modal-header,.cc-modal-body{padding:1rem}.cc-modal-footer{padding:.75rem 1rem;flex-direction:column}.cc-modal-footer .cc-btn{width:100%}}\n"] }]
597
+ }], propDecorators: { config: [{
598
+ type: Input
599
+ }], isOpen: [{
600
+ type: Input
601
+ }], confirm: [{
602
+ type: Output
603
+ }], cancel: [{
604
+ type: Output
605
+ }], close: [{
606
+ type: Output
607
+ }], showCodeSnippet: [{
608
+ type: Output
609
+ }], handleEscape: [{
610
+ type: HostListener,
611
+ args: ['document:keydown.escape', ['$event']]
612
+ }] } });
613
+
614
+ class ConfirmationModalModule {
615
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
616
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, declarations: [ConfirmationModalComponent], imports: [CommonModule,
617
+ MatIconModule, // For material icons support
618
+ FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
619
+ ], exports: [ConfirmationModalComponent] });
620
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, imports: [CommonModule,
621
+ MatIconModule, // For material icons support
622
+ FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
623
+ ] });
624
+ }
625
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, decorators: [{
626
+ type: NgModule,
627
+ args: [{
628
+ declarations: [
629
+ ConfirmationModalComponent
630
+ ],
631
+ imports: [
632
+ CommonModule,
633
+ MatIconModule, // For material icons support
634
+ FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
635
+ ],
636
+ exports: [
637
+ ConfirmationModalComponent
638
+ ]
639
+ }]
640
+ }] });
641
+
642
+ class InputComponent {
643
+ config;
644
+ labels;
645
+ type = 'text';
646
+ label = '';
647
+ placeholder = '';
648
+ disabled = false;
649
+ required = false;
650
+ readonly = false;
651
+ clearable = true;
652
+ maxLength;
653
+ minLength;
654
+ min;
655
+ max;
656
+ pattern;
657
+ errorMessage = '';
658
+ helperText = '';
659
+ rows = 3;
660
+ prefixIcon;
661
+ suffixIcon;
662
+ value = '';
663
+ // Style inputs
664
+ width;
665
+ height;
666
+ borderRadius;
667
+ fontSize;
668
+ gap;
669
+ fontFamily;
670
+ labelColor;
671
+ labelFontSize;
672
+ labelFontWeight;
673
+ backgroundColor;
674
+ borderColor;
675
+ borderWidth;
676
+ padding;
677
+ fontWeight;
678
+ color;
679
+ placeholderColor;
680
+ focusBorderColor;
681
+ errorColor;
682
+ disabledBackgroundColor;
683
+ disabledColor;
684
+ boxShadow;
685
+ valueChange = new EventEmitter();
686
+ inputBlur = new EventEmitter();
687
+ inputFocus = new EventEmitter();
688
+ showPassword = false;
689
+ focused = false;
690
+ onChange = () => { };
691
+ onTouched = () => { };
692
+ ngOnInit() {
693
+ this.updateFromConfig();
694
+ this.updateFromLabels();
695
+ }
696
+ ngOnChanges(changes) {
697
+ if (changes['config']) {
698
+ this.updateFromConfig();
699
+ }
700
+ if (changes['labels']) {
701
+ this.updateFromLabels();
702
+ }
703
+ }
704
+ updateFromConfig() {
705
+ if (this.config) {
706
+ this.type = this.config.type ?? this.type;
707
+ this.label = this.config.label ?? this.label;
708
+ this.placeholder = this.config.placeholder ?? this.placeholder;
709
+ this.disabled = this.config.disabled ?? this.disabled;
710
+ this.required = this.config.required ?? this.required;
711
+ this.readonly = this.config.readonly ?? this.readonly;
712
+ this.maxLength = this.config.maxLength ?? this.maxLength;
713
+ this.minLength = this.config.minLength ?? this.minLength;
714
+ this.min = this.config.min ?? this.min;
715
+ this.max = this.config.max ?? this.max;
716
+ this.pattern = this.config.pattern ?? this.pattern;
717
+ this.errorMessage = this.config.errorMessage ?? this.errorMessage;
718
+ this.helperText = this.config.helperText ?? this.helperText;
719
+ this.rows = this.config.rows ?? this.rows;
720
+ this.prefixIcon = this.config.prefixIcon ?? this.prefixIcon;
721
+ this.suffixIcon = this.config.suffixIcon ?? this.suffixIcon;
722
+ // Style inputs
723
+ this.width = this.config.width ?? this.width;
724
+ this.height = this.config.height ?? this.height;
725
+ this.borderRadius = this.config.borderRadius ?? this.borderRadius;
726
+ this.fontSize = this.config.fontSize ?? this.fontSize;
727
+ this.gap = this.config.gap ?? this.gap;
728
+ this.fontFamily = this.config.fontFamily ?? this.fontFamily;
729
+ this.labelColor = this.config.labelColor ?? this.labelColor;
730
+ this.labelFontSize = this.config.labelFontSize ?? this.labelFontSize;
731
+ this.labelFontWeight = this.config.labelFontWeight ?? this.labelFontWeight;
732
+ this.backgroundColor = this.config.backgroundColor ?? this.backgroundColor;
733
+ this.borderColor = this.config.borderColor ?? this.borderColor;
734
+ this.borderWidth = this.config.borderWidth ?? this.borderWidth;
735
+ this.padding = this.config.padding ?? this.padding;
736
+ this.fontWeight = this.config.fontWeight ?? this.fontWeight;
737
+ this.color = this.config.color ?? this.color;
738
+ this.placeholderColor = this.config.placeholderColor ?? this.placeholderColor;
739
+ this.focusBorderColor = this.config.focusBorderColor ?? this.focusBorderColor;
740
+ this.errorColor = this.config.errorColor ?? this.errorColor;
741
+ this.disabledBackgroundColor = this.config.disabledBackgroundColor ?? this.disabledBackgroundColor;
742
+ this.disabledColor = this.config.disabledColor ?? this.disabledColor;
743
+ this.boxShadow = this.config.boxShadow ?? this.boxShadow;
744
+ if (this.config.value !== undefined) {
745
+ this.value = this.config.value;
746
+ }
747
+ }
748
+ }
749
+ updateFromLabels() {
750
+ if (this.labels) {
751
+ this.label = this.labels.label || this.label;
752
+ this.placeholder = this.labels.placeholder || this.placeholder;
753
+ this.errorMessage = this.labels.errorMessage || this.errorMessage;
754
+ this.helperText = this.labels.helperText || this.helperText;
755
+ }
756
+ }
757
+ get requiredMarker() {
758
+ return this.labels?.requiredMarker || '*';
759
+ }
760
+ writeValue(value) {
761
+ this.value = value;
762
+ }
763
+ registerOnChange(fn) {
764
+ this.onChange = fn;
765
+ }
766
+ registerOnTouched(fn) {
767
+ this.onTouched = fn;
768
+ }
769
+ setDisabledState(isDisabled) {
770
+ this.disabled = isDisabled;
771
+ }
772
+ onInputChange(event) {
773
+ const value = event.target.value;
774
+ this.value = this.type === 'number' ? (value ? Number(value) : null) : value;
775
+ this.onChange(this.value);
776
+ this.valueChange.emit(this.value);
777
+ }
778
+ onBlur() {
779
+ this.focused = false;
780
+ this.onTouched();
781
+ this.inputBlur.emit();
782
+ }
783
+ onFocus() {
784
+ this.focused = true;
785
+ this.inputFocus.emit();
786
+ }
787
+ togglePasswordVisibility() {
788
+ this.showPassword = !this.showPassword;
789
+ }
790
+ getIconType(icon) {
791
+ if (!icon)
792
+ return 'none';
793
+ if (typeof icon === 'string') {
794
+ if (icon.includes('/') || icon.includes('.') || icon.startsWith('http')) {
795
+ return 'img';
796
+ }
797
+ return 'material';
798
+ }
799
+ return icon.type || 'material';
800
+ }
801
+ getIconValue(icon) {
802
+ if (typeof icon === 'string')
803
+ return icon;
804
+ return icon?.value || '';
805
+ }
806
+ get inputType() {
807
+ if (this.type === 'password' && this.showPassword) {
808
+ return 'text';
809
+ }
810
+ return this.type === 'textarea' ? 'text' : this.type;
811
+ }
812
+ getStyleValue(value) {
813
+ return value ? `${value}` : undefined;
814
+ }
815
+ get wrapperStyles() {
816
+ return {
817
+ 'width': this.getStyleValue(this.width),
818
+ '--cc-input-label-gap': this.getStyleValue(this.gap),
819
+ '--cc-input-font-family': this.getStyleValue(this.fontFamily)
820
+ };
821
+ }
822
+ get labelStyles() {
823
+ return {
824
+ '--cc-input-label-color': this.getStyleValue(this.labelColor),
825
+ '--cc-input-label-font-size': this.getStyleValue(this.labelFontSize),
826
+ '--cc-input-label-font-weight': this.getStyleValue(this.labelFontWeight)
827
+ };
828
+ }
829
+ get fieldStyles() {
830
+ return {
831
+ '--cc-input-bg': this.getStyleValue(this.backgroundColor),
832
+ '--cc-input-border-radius': this.getStyleValue(this.borderRadius),
833
+ '--cc-input-border-color': this.getStyleValue(this.borderColor),
834
+ '--cc-input-border-width': this.getStyleValue(this.borderWidth),
835
+ '--cc-input-height': this.getStyleValue(this.height),
836
+ '--cc-input-padding': this.getStyleValue(this.padding),
837
+ '--cc-input-font-size': this.getStyleValue(this.fontSize),
838
+ '--cc-input-font-weight': this.getStyleValue(this.fontWeight),
839
+ '--cc-input-color': this.getStyleValue(this.color),
840
+ '--cc-input-placeholder-color': this.getStyleValue(this.placeholderColor),
841
+ '--cc-input-focus-border-color': this.getStyleValue(this.focusBorderColor),
842
+ '--cc-input-error-color': this.getStyleValue(this.errorColor),
843
+ '--cc-input-disabled-bg': this.getStyleValue(this.disabledBackgroundColor),
844
+ '--cc-input-disabled-color': this.getStyleValue(this.disabledColor),
845
+ 'box-shadow': this.getStyleValue(this.boxShadow)
846
+ };
847
+ }
848
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: InputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
849
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: InputComponent, isStandalone: false, selector: "lib-input", inputs: { config: "config", labels: "labels", type: "type", label: "label", placeholder: "placeholder", disabled: "disabled", required: "required", readonly: "readonly", clearable: "clearable", maxLength: "maxLength", minLength: "minLength", min: "min", max: "max", pattern: "pattern", errorMessage: "errorMessage", helperText: "helperText", rows: "rows", prefixIcon: "prefixIcon", suffixIcon: "suffixIcon", value: "value", width: "width", height: "height", borderRadius: "borderRadius", fontSize: "fontSize", gap: "gap", fontFamily: "fontFamily", labelColor: "labelColor", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight", backgroundColor: "backgroundColor", borderColor: "borderColor", borderWidth: "borderWidth", padding: "padding", fontWeight: "fontWeight", color: "color", placeholderColor: "placeholderColor", focusBorderColor: "focusBorderColor", errorColor: "errorColor", disabledBackgroundColor: "disabledBackgroundColor", disabledColor: "disabledColor", boxShadow: "boxShadow" }, outputs: { valueChange: "valueChange", inputBlur: "inputBlur", inputFocus: "inputFocus" }, providers: [
850
+ {
851
+ provide: NG_VALUE_ACCESSOR,
852
+ useExisting: forwardRef(() => InputComponent),
853
+ multi: true
854
+ }
855
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-input-container\" [ngStyle]=\"wrapperStyles\">\r\n <label *ngIf=\"label\" class=\"cc-input-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <div class=\"cc-input-wrapper\" [class.focused]=\"focused\" [class.disabled]=\"disabled\" [class.error]=\"errorMessage\"\r\n [ngStyle]=\"fieldStyles\">\r\n\r\n <!-- Prefix Icon -->\r\n <span class=\"cc-input-prefix\" *ngIf=\"prefixIcon\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(prefixIcon) === 'material'\">{{ getIconValue(prefixIcon)\r\n }}</span>\r\n <i *ngIf=\"getIconType(prefixIcon) === 'fontawesome'\" [class]=\"getIconValue(prefixIcon)\"></i>\r\n <img *ngIf=\"getIconType(prefixIcon) === 'img'\" [src]=\"getIconValue(prefixIcon)\" class=\"cc-icon-img\"\r\n [attr.alt]=\"labels?.prefixAltText || 'prefix'\" />\r\n </span>\r\n\r\n <!-- Input -->\r\n <input *ngIf=\"type !== 'textarea'\" class=\"cc-input-element\" [type]=\"inputType\" [value]=\"value\"\r\n [placeholder]=\"placeholder\" [disabled]=\"disabled\" [required]=\"required\" [readonly]=\"readonly\"\r\n [maxLength]=\"maxLength || 524288\" [minLength]=\"minLength || 0\" [min]=\"min\" [max]=\"max\" [pattern]=\"pattern\"\r\n (input)=\"onInputChange($event)\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" [attr.aria-invalid]=\"!!errorMessage\"\r\n [attr.aria-describedby]=\"helperText ? 'helper-text' : null\" />\r\n\r\n <!-- Textarea -->\r\n <textarea *ngIf=\"type === 'textarea'\" class=\"cc-input-element cc-textarea\" [value]=\"value\"\r\n [placeholder]=\"placeholder\" [disabled]=\"disabled\" [required]=\"required\" [readonly]=\"readonly\"\r\n [maxLength]=\"maxLength || 524288\" [minLength]=\"minLength || 0\" [rows]=\"rows\" (input)=\"onInputChange($event)\"\r\n (blur)=\"onBlur()\" (focus)=\"onFocus()\" [attr.aria-invalid]=\"!!errorMessage\"></textarea>\r\n\r\n <!-- Suffix Icon / Password Toggle -->\r\n <span class=\"cc-input-suffix\">\r\n <button *ngIf=\"type === 'password'\" type=\"button\" class=\"cc-icon-btn\" (click)=\"togglePasswordVisibility()\"\r\n [attr.aria-label]=\"labels?.passwordToggleAriaLabel\">\r\n <span class=\"material-icons\">{{ showPassword ? 'visibility_off' : 'visibility' }}</span>\r\n </button>\r\n\r\n <ng-container *ngIf=\"suffixIcon && type !== 'password'\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(suffixIcon) === 'material'\">{{ getIconValue(suffixIcon)\r\n }}</span>\r\n <i *ngIf=\"getIconType(suffixIcon) === 'fontawesome'\" [class]=\"getIconValue(suffixIcon)\"></i>\r\n <img *ngIf=\"getIconType(suffixIcon) === 'img'\" [src]=\"getIconValue(suffixIcon)\" class=\"cc-icon-img\"\r\n [attr.alt]=\"labels?.suffixAltText || 'suffix'\" />\r\n </ng-container>\r\n </span>\r\n </div>\r\n\r\n <div class=\"cc-helper-text\" *ngIf=\"helperText\" id=\"helper-text\">{{ helperText }}</div>\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-input-container{display:flex;flex-direction:column;gap:var(--cc-input-label-gap, .5rem);width:100%;font-family:var(--cc-input-font-family, inherit)}.cc-input-label{font-size:var(--cc-input-label-font-size, .875rem);font-weight:var(--cc-input-label-font-weight, 500);color:var(--cc-input-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-input-required-color, #D93025);margin-left:.25rem}.cc-input-wrapper{display:flex;align-items:center;width:100%;box-sizing:border-box;background-color:var(--cc-input-bg, #FEFEFE);border:var(--cc-input-border-width, 1px) solid var(--cc-input-border-color, #BDC1C6);border-radius:var(--cc-input-border-radius, .4375rem);padding:var(--cc-input-padding, .5rem .75rem);min-height:var(--cc-input-height, 2.5rem);transition:border-color .2s,box-shadow .2s}.cc-input-wrapper.focused{border-color:var(--cc-input-focus-border-color, #1A73E8)}.cc-input-wrapper.error{border-color:var(--cc-input-error-color, #D93025)}.cc-input-wrapper.disabled{background-color:var(--cc-input-disabled-bg, #F1F3F4);cursor:not-allowed}.cc-input-wrapper.disabled .cc-input-element{cursor:not-allowed;color:var(--cc-input-disabled-color, #80868B)}.cc-input-wrapper.disabled .material-icons,.cc-input-wrapper.disabled i,.cc-input-wrapper.disabled img{opacity:.5}.cc-input-element{flex:1;border:none;background:none;outline:none;font-family:inherit;font-size:var(--cc-input-font-size, .875rem);font-weight:var(--cc-input-font-weight, 400);color:var(--cc-input-color, #202124);padding:0;margin:0;width:100%}.cc-input-element::placeholder{color:var(--cc-input-placeholder-color, #80868B)}.cc-input-element.cc-textarea{resize:vertical;min-height:4rem}.cc-input-prefix,.cc-input-suffix{display:flex;align-items:center;color:var(--cc-input-icon-color, #5F6368)}.cc-input-prefix{margin-right:.5rem}.cc-input-suffix{margin-left:.5rem}.cc-icon-img{width:1.25rem;height:1.25rem;object-fit:contain}.cc-icon-btn{background:none;border:none;cursor:pointer;padding:0;display:flex;align-items:center;color:inherit}.cc-icon-btn:focus{outline:none}.cc-helper-text{font-size:.75rem;color:#5f6368;margin-top:.25rem}.cc-error-message{font-size:.75rem;color:var(--cc-input-error-color, #D93025);margin-top:.25rem}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
856
+ }
857
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: InputComponent, decorators: [{
858
+ type: Component,
859
+ args: [{ selector: 'lib-input', standalone: false, providers: [
860
+ {
861
+ provide: NG_VALUE_ACCESSOR,
862
+ useExisting: forwardRef(() => InputComponent),
863
+ multi: true
864
+ }
865
+ ], template: "<div class=\"cc-input-container\" [ngStyle]=\"wrapperStyles\">\r\n <label *ngIf=\"label\" class=\"cc-input-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <div class=\"cc-input-wrapper\" [class.focused]=\"focused\" [class.disabled]=\"disabled\" [class.error]=\"errorMessage\"\r\n [ngStyle]=\"fieldStyles\">\r\n\r\n <!-- Prefix Icon -->\r\n <span class=\"cc-input-prefix\" *ngIf=\"prefixIcon\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(prefixIcon) === 'material'\">{{ getIconValue(prefixIcon)\r\n }}</span>\r\n <i *ngIf=\"getIconType(prefixIcon) === 'fontawesome'\" [class]=\"getIconValue(prefixIcon)\"></i>\r\n <img *ngIf=\"getIconType(prefixIcon) === 'img'\" [src]=\"getIconValue(prefixIcon)\" class=\"cc-icon-img\"\r\n [attr.alt]=\"labels?.prefixAltText || 'prefix'\" />\r\n </span>\r\n\r\n <!-- Input -->\r\n <input *ngIf=\"type !== 'textarea'\" class=\"cc-input-element\" [type]=\"inputType\" [value]=\"value\"\r\n [placeholder]=\"placeholder\" [disabled]=\"disabled\" [required]=\"required\" [readonly]=\"readonly\"\r\n [maxLength]=\"maxLength || 524288\" [minLength]=\"minLength || 0\" [min]=\"min\" [max]=\"max\" [pattern]=\"pattern\"\r\n (input)=\"onInputChange($event)\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" [attr.aria-invalid]=\"!!errorMessage\"\r\n [attr.aria-describedby]=\"helperText ? 'helper-text' : null\" />\r\n\r\n <!-- Textarea -->\r\n <textarea *ngIf=\"type === 'textarea'\" class=\"cc-input-element cc-textarea\" [value]=\"value\"\r\n [placeholder]=\"placeholder\" [disabled]=\"disabled\" [required]=\"required\" [readonly]=\"readonly\"\r\n [maxLength]=\"maxLength || 524288\" [minLength]=\"minLength || 0\" [rows]=\"rows\" (input)=\"onInputChange($event)\"\r\n (blur)=\"onBlur()\" (focus)=\"onFocus()\" [attr.aria-invalid]=\"!!errorMessage\"></textarea>\r\n\r\n <!-- Suffix Icon / Password Toggle -->\r\n <span class=\"cc-input-suffix\">\r\n <button *ngIf=\"type === 'password'\" type=\"button\" class=\"cc-icon-btn\" (click)=\"togglePasswordVisibility()\"\r\n [attr.aria-label]=\"labels?.passwordToggleAriaLabel\">\r\n <span class=\"material-icons\">{{ showPassword ? 'visibility_off' : 'visibility' }}</span>\r\n </button>\r\n\r\n <ng-container *ngIf=\"suffixIcon && type !== 'password'\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(suffixIcon) === 'material'\">{{ getIconValue(suffixIcon)\r\n }}</span>\r\n <i *ngIf=\"getIconType(suffixIcon) === 'fontawesome'\" [class]=\"getIconValue(suffixIcon)\"></i>\r\n <img *ngIf=\"getIconType(suffixIcon) === 'img'\" [src]=\"getIconValue(suffixIcon)\" class=\"cc-icon-img\"\r\n [attr.alt]=\"labels?.suffixAltText || 'suffix'\" />\r\n </ng-container>\r\n </span>\r\n </div>\r\n\r\n <div class=\"cc-helper-text\" *ngIf=\"helperText\" id=\"helper-text\">{{ helperText }}</div>\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-input-container{display:flex;flex-direction:column;gap:var(--cc-input-label-gap, .5rem);width:100%;font-family:var(--cc-input-font-family, inherit)}.cc-input-label{font-size:var(--cc-input-label-font-size, .875rem);font-weight:var(--cc-input-label-font-weight, 500);color:var(--cc-input-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-input-required-color, #D93025);margin-left:.25rem}.cc-input-wrapper{display:flex;align-items:center;width:100%;box-sizing:border-box;background-color:var(--cc-input-bg, #FEFEFE);border:var(--cc-input-border-width, 1px) solid var(--cc-input-border-color, #BDC1C6);border-radius:var(--cc-input-border-radius, .4375rem);padding:var(--cc-input-padding, .5rem .75rem);min-height:var(--cc-input-height, 2.5rem);transition:border-color .2s,box-shadow .2s}.cc-input-wrapper.focused{border-color:var(--cc-input-focus-border-color, #1A73E8)}.cc-input-wrapper.error{border-color:var(--cc-input-error-color, #D93025)}.cc-input-wrapper.disabled{background-color:var(--cc-input-disabled-bg, #F1F3F4);cursor:not-allowed}.cc-input-wrapper.disabled .cc-input-element{cursor:not-allowed;color:var(--cc-input-disabled-color, #80868B)}.cc-input-wrapper.disabled .material-icons,.cc-input-wrapper.disabled i,.cc-input-wrapper.disabled img{opacity:.5}.cc-input-element{flex:1;border:none;background:none;outline:none;font-family:inherit;font-size:var(--cc-input-font-size, .875rem);font-weight:var(--cc-input-font-weight, 400);color:var(--cc-input-color, #202124);padding:0;margin:0;width:100%}.cc-input-element::placeholder{color:var(--cc-input-placeholder-color, #80868B)}.cc-input-element.cc-textarea{resize:vertical;min-height:4rem}.cc-input-prefix,.cc-input-suffix{display:flex;align-items:center;color:var(--cc-input-icon-color, #5F6368)}.cc-input-prefix{margin-right:.5rem}.cc-input-suffix{margin-left:.5rem}.cc-icon-img{width:1.25rem;height:1.25rem;object-fit:contain}.cc-icon-btn{background:none;border:none;cursor:pointer;padding:0;display:flex;align-items:center;color:inherit}.cc-icon-btn:focus{outline:none}.cc-helper-text{font-size:.75rem;color:#5f6368;margin-top:.25rem}.cc-error-message{font-size:.75rem;color:var(--cc-input-error-color, #D93025);margin-top:.25rem}\n"] }]
866
+ }], propDecorators: { config: [{
867
+ type: Input
868
+ }], labels: [{
869
+ type: Input
870
+ }], type: [{
871
+ type: Input
872
+ }], label: [{
873
+ type: Input
874
+ }], placeholder: [{
875
+ type: Input
876
+ }], disabled: [{
877
+ type: Input
878
+ }], required: [{
879
+ type: Input
880
+ }], readonly: [{
881
+ type: Input
882
+ }], clearable: [{
883
+ type: Input
884
+ }], maxLength: [{
885
+ type: Input
886
+ }], minLength: [{
887
+ type: Input
888
+ }], min: [{
889
+ type: Input
890
+ }], max: [{
891
+ type: Input
892
+ }], pattern: [{
893
+ type: Input
894
+ }], errorMessage: [{
895
+ type: Input
896
+ }], helperText: [{
897
+ type: Input
898
+ }], rows: [{
899
+ type: Input
900
+ }], prefixIcon: [{
901
+ type: Input
902
+ }], suffixIcon: [{
903
+ type: Input
904
+ }], value: [{
905
+ type: Input
906
+ }], width: [{
907
+ type: Input
908
+ }], height: [{
909
+ type: Input
910
+ }], borderRadius: [{
911
+ type: Input
912
+ }], fontSize: [{
913
+ type: Input
914
+ }], gap: [{
915
+ type: Input
916
+ }], fontFamily: [{
917
+ type: Input
918
+ }], labelColor: [{
919
+ type: Input
920
+ }], labelFontSize: [{
921
+ type: Input
922
+ }], labelFontWeight: [{
923
+ type: Input
924
+ }], backgroundColor: [{
925
+ type: Input
926
+ }], borderColor: [{
927
+ type: Input
928
+ }], borderWidth: [{
929
+ type: Input
930
+ }], padding: [{
931
+ type: Input
932
+ }], fontWeight: [{
933
+ type: Input
934
+ }], color: [{
935
+ type: Input
936
+ }], placeholderColor: [{
937
+ type: Input
938
+ }], focusBorderColor: [{
939
+ type: Input
940
+ }], errorColor: [{
941
+ type: Input
942
+ }], disabledBackgroundColor: [{
943
+ type: Input
944
+ }], disabledColor: [{
945
+ type: Input
946
+ }], boxShadow: [{
947
+ type: Input
948
+ }], valueChange: [{
949
+ type: Output
950
+ }], inputBlur: [{
951
+ type: Output
952
+ }], inputFocus: [{
953
+ type: Output
954
+ }] } });
955
+
956
+ class ClickOutsideDirective {
957
+ elementRef;
958
+ libClickOutside = new EventEmitter();
959
+ constructor(elementRef) {
960
+ this.elementRef = elementRef;
961
+ }
962
+ onClick(target) {
963
+ const clickedInside = this.elementRef.nativeElement.contains(target);
964
+ if (!clickedInside) {
965
+ this.libClickOutside.emit();
966
+ }
967
+ }
968
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ClickOutsideDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
969
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: ClickOutsideDirective, isStandalone: false, selector: "[libClickOutside]", outputs: { libClickOutside: "libClickOutside" }, host: { listeners: { "document:click": "onClick($event.target)" } }, ngImport: i0 });
970
+ }
971
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ClickOutsideDirective, decorators: [{
972
+ type: Directive,
973
+ args: [{
974
+ selector: '[libClickOutside]',
975
+ standalone: false
976
+ }]
977
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { libClickOutside: [{
978
+ type: Output
979
+ }], onClick: [{
980
+ type: HostListener,
981
+ args: ['document:click', ['$event.target']]
982
+ }] } });
983
+
984
+ class DropdownComponent {
985
+ config;
986
+ labels;
987
+ options = [];
988
+ placeholder = '';
989
+ label = '';
990
+ multiple = false;
991
+ searchable = false;
992
+ clearable = false;
993
+ disabled = false;
994
+ required = false;
995
+ errorMessage = '';
996
+ // Configurable styles
997
+ width;
998
+ height;
999
+ borderRadius;
1000
+ fontSize;
1001
+ // Additional style inputs inferred from template/getters
1002
+ gap;
1003
+ fontFamily;
1004
+ labelColor;
1005
+ labelFontSize;
1006
+ labelFontWeight;
1007
+ backgroundColor;
1008
+ borderColor;
1009
+ borderWidth;
1010
+ padding;
1011
+ fontWeight;
1012
+ color;
1013
+ placeholderColor;
1014
+ focusBorderColor;
1015
+ errorColor;
1016
+ disabledBackgroundColor;
1017
+ disabledColor;
1018
+ boxShadow;
1019
+ selectionChange = new EventEmitter();
1020
+ viewport;
1021
+ searchInput;
1022
+ filteredOptions = [];
1023
+ searchTerm = '';
1024
+ value = null;
1025
+ isOpen = false;
1026
+ focusedIndex = -1;
1027
+ onChange = () => { };
1028
+ onTouched = () => { };
1029
+ ngOnInit() {
1030
+ this.updateFromConfig();
1031
+ this.updateFromLabels();
1032
+ this.filteredOptions = [...this.options];
1033
+ }
1034
+ ngOnChanges(changes) {
1035
+ if (changes['config']) {
1036
+ this.updateFromConfig();
1037
+ }
1038
+ if (changes['labels']) {
1039
+ this.updateFromLabels();
1040
+ }
1041
+ if (changes['config'] || changes['options']) {
1042
+ this.filteredOptions = [...this.options];
1043
+ }
1044
+ }
1045
+ updateFromConfig() {
1046
+ if (this.config) {
1047
+ this.options = this.config.options || this.options;
1048
+ this.placeholder = this.config.placeholder ?? this.placeholder;
1049
+ this.label = this.config.label ?? this.label;
1050
+ this.multiple = this.config.multiple ?? this.multiple;
1051
+ this.searchable = this.config.searchable ?? this.searchable;
1052
+ this.clearable = this.config.clearable ?? this.clearable;
1053
+ this.disabled = this.config.disabled ?? this.disabled;
1054
+ this.required = this.config.required ?? this.required;
1055
+ this.errorMessage = this.config.errorMessage ?? this.errorMessage;
1056
+ this.width = this.config.width ?? this.width;
1057
+ this.height = this.config.height ?? this.height;
1058
+ this.borderRadius = this.config.borderRadius ?? this.borderRadius;
1059
+ this.fontSize = this.config.fontSize ?? this.fontSize;
1060
+ this.gap = this.config.gap ?? this.gap;
1061
+ this.fontFamily = this.config.fontFamily ?? this.fontFamily;
1062
+ this.labelColor = this.config.labelColor ?? this.labelColor;
1063
+ this.labelFontSize = this.config.labelFontSize ?? this.labelFontSize;
1064
+ this.labelFontWeight = this.config.labelFontWeight ?? this.labelFontWeight;
1065
+ this.backgroundColor = this.config.backgroundColor ?? this.backgroundColor;
1066
+ this.borderColor = this.config.borderColor ?? this.borderColor;
1067
+ this.borderWidth = this.config.borderWidth ?? this.borderWidth;
1068
+ this.padding = this.config.padding ?? this.padding;
1069
+ this.fontWeight = this.config.fontWeight ?? this.fontWeight;
1070
+ this.color = this.config.color ?? this.color;
1071
+ this.placeholderColor = this.config.placeholderColor ?? this.placeholderColor;
1072
+ this.focusBorderColor = this.config.focusBorderColor ?? this.focusBorderColor;
1073
+ this.errorColor = this.config.errorColor ?? this.errorColor;
1074
+ this.disabledBackgroundColor = this.config.disabledBackgroundColor ?? this.disabledBackgroundColor;
1075
+ this.disabledColor = this.config.disabledColor ?? this.disabledColor;
1076
+ this.boxShadow = this.config.boxShadow ?? this.boxShadow;
1077
+ }
1078
+ }
1079
+ updateFromLabels() {
1080
+ if (this.labels) {
1081
+ this.label = this.labels.label || this.label;
1082
+ this.placeholder = this.labels.placeholder || this.placeholder;
1083
+ this.errorMessage = this.labels.errorMessage || this.errorMessage;
1084
+ }
1085
+ }
1086
+ get requiredMarker() {
1087
+ return this.labels?.requiredMarker || '*';
1088
+ }
1089
+ get searchPlaceholder() {
1090
+ return this.labels?.searchPlaceholder || 'Search...';
1091
+ }
1092
+ get selectedSuffix() {
1093
+ return this.labels?.selectedSuffix || 'selected';
1094
+ }
1095
+ get clearAriaLabel() {
1096
+ return this.labels?.clearAriaLabel || 'Clear selection';
1097
+ }
1098
+ writeValue(value) {
1099
+ this.value = value;
1100
+ }
1101
+ registerOnChange(fn) {
1102
+ this.onChange = fn;
1103
+ }
1104
+ registerOnTouched(fn) {
1105
+ this.onTouched = fn;
1106
+ }
1107
+ setDisabledState(isDisabled) {
1108
+ this.disabled = isDisabled;
1109
+ }
1110
+ toggle() {
1111
+ if (this.disabled)
1112
+ return;
1113
+ this.isOpen = !this.isOpen;
1114
+ if (this.isOpen) {
1115
+ this.focusedIndex = -1;
1116
+ setTimeout(() => {
1117
+ if (this.searchable && this.searchInput) {
1118
+ this.searchInput.nativeElement.focus();
1119
+ }
1120
+ else if (this.viewport) {
1121
+ this.viewport.elementRef.nativeElement.focus();
1122
+ }
1123
+ });
1124
+ }
1125
+ else {
1126
+ this.onTouched();
1127
+ }
1128
+ }
1129
+ close() {
1130
+ if (this.isOpen) {
1131
+ this.isOpen = false;
1132
+ this.onTouched();
1133
+ }
1134
+ }
1135
+ selectOption(option) {
1136
+ if (option.disabled)
1137
+ return;
1138
+ if (this.multiple) {
1139
+ const currentValues = Array.isArray(this.value) ? [...this.value] : [];
1140
+ const index = currentValues.indexOf(option.value);
1141
+ if (index > -1) {
1142
+ currentValues.splice(index, 1);
1143
+ }
1144
+ else {
1145
+ currentValues.push(option.value);
1146
+ }
1147
+ this.value = currentValues;
1148
+ }
1149
+ else {
1150
+ this.value = option.value;
1151
+ this.close();
1152
+ }
1153
+ this.onChange(this.value);
1154
+ this.selectionChange.emit(this.value);
1155
+ }
1156
+ isSelected(option) {
1157
+ if (this.multiple) {
1158
+ return Array.isArray(this.value) && this.value.includes(option.value);
1159
+ }
1160
+ return this.value === option.value;
1161
+ }
1162
+ onSearch(term) {
1163
+ this.searchTerm = term;
1164
+ if (!term) {
1165
+ this.filteredOptions = [...this.options];
1166
+ }
1167
+ else {
1168
+ this.filteredOptions = this.options.filter(option => option.label.toLowerCase().includes(term.toLowerCase()));
1169
+ }
1170
+ this.focusedIndex = -1;
1171
+ }
1172
+ clearSelection(event) {
1173
+ if (event) {
1174
+ event.stopPropagation();
1175
+ }
1176
+ this.value = this.multiple ? [] : null;
1177
+ this.onChange(this.value);
1178
+ this.selectionChange.emit(this.value);
1179
+ }
1180
+ getIconType(icon) {
1181
+ if (!icon)
1182
+ return 'none';
1183
+ if (typeof icon === 'string') {
1184
+ if (icon.includes('/') || icon.includes('.') || icon.startsWith('http')) {
1185
+ return 'img';
1186
+ }
1187
+ return 'material';
1188
+ }
1189
+ return icon.type || 'material';
1190
+ }
1191
+ getIconValue(icon) {
1192
+ if (typeof icon === 'string')
1193
+ return icon;
1194
+ return icon?.value || '';
1195
+ }
1196
+ getSelectedLabel() {
1197
+ if (this.multiple) {
1198
+ const count = Array.isArray(this.value) ? this.value.length : 0;
1199
+ return count > 0 ? `${count} ${this.selectedSuffix}` : '';
1200
+ }
1201
+ if (!this.value)
1202
+ return '';
1203
+ const selected = this.options.find(opt => opt.value === this.value);
1204
+ return selected?.label || '';
1205
+ }
1206
+ hasValue() {
1207
+ if (this.multiple) {
1208
+ return Array.isArray(this.value) && this.value.length > 0;
1209
+ }
1210
+ return this.value !== null && this.value !== undefined && this.value !== '';
1211
+ }
1212
+ handleKeyboardEvent(event) {
1213
+ if (this.disabled)
1214
+ return;
1215
+ if (event.key === 'Escape') {
1216
+ this.close();
1217
+ return;
1218
+ }
1219
+ if (!this.isOpen && (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown')) {
1220
+ this.toggle();
1221
+ event.preventDefault();
1222
+ return;
1223
+ }
1224
+ if (!this.isOpen)
1225
+ return;
1226
+ switch (event.key) {
1227
+ case 'ArrowDown':
1228
+ this.focusedIndex = Math.min(this.focusedIndex + 1, this.filteredOptions.length - 1);
1229
+ this.scrollToIndex(this.focusedIndex);
1230
+ event.preventDefault();
1231
+ break;
1232
+ case 'ArrowUp':
1233
+ this.focusedIndex = Math.max(this.focusedIndex - 1, 0);
1234
+ this.scrollToIndex(this.focusedIndex);
1235
+ event.preventDefault();
1236
+ break;
1237
+ case 'Enter':
1238
+ if (this.focusedIndex > -1) {
1239
+ this.selectOption(this.filteredOptions[this.focusedIndex]);
1240
+ }
1241
+ event.preventDefault();
1242
+ break;
1243
+ }
1244
+ }
1245
+ scrollToIndex(index) {
1246
+ if (this.viewport) {
1247
+ this.viewport.scrollToIndex(index);
1248
+ }
1249
+ }
1250
+ getStyleValue(value) {
1251
+ return value ? `${value}` : undefined;
1252
+ }
1253
+ get wrapperStyles() {
1254
+ return {
1255
+ 'width': this.getStyleValue(this.width),
1256
+ '--cc-dropdown-label-gap': this.getStyleValue(this.gap),
1257
+ '--cc-dropdown-font-family': this.getStyleValue(this.fontFamily)
1258
+ };
1259
+ }
1260
+ get labelStyles() {
1261
+ return {
1262
+ '--cc-dropdown-label-color': this.getStyleValue(this.labelColor),
1263
+ '--cc-dropdown-font-size': this.getStyleValue(this.labelFontSize),
1264
+ '--cc-dropdown-font-weight': this.getStyleValue(this.labelFontWeight)
1265
+ };
1266
+ }
1267
+ get fieldStyles() {
1268
+ return {
1269
+ '--cc-dropdown-bg': this.getStyleValue(this.backgroundColor),
1270
+ '--cc-dropdown-border-radius': this.getStyleValue(this.borderRadius),
1271
+ '--cc-dropdown-border-color': this.getStyleValue(this.borderColor),
1272
+ '--cc-dropdown-border-width': this.getStyleValue(this.borderWidth),
1273
+ '--cc-dropdown-height': this.getStyleValue(this.height),
1274
+ '--cc-dropdown-padding': this.getStyleValue(this.padding),
1275
+ '--cc-dropdown-font-size': this.getStyleValue(this.fontSize),
1276
+ '--cc-dropdown-font-weight': this.getStyleValue(this.fontWeight),
1277
+ '--cc-dropdown-color': this.getStyleValue(this.color),
1278
+ '--cc-dropdown-placeholder-color': this.getStyleValue(this.placeholderColor),
1279
+ '--cc-dropdown-focus-border-color': this.getStyleValue(this.focusBorderColor),
1280
+ '--cc-dropdown-error-color': this.getStyleValue(this.errorColor),
1281
+ '--cc-dropdown-disabled-bg': this.getStyleValue(this.disabledBackgroundColor),
1282
+ '--cc-dropdown-disabled-color': this.getStyleValue(this.disabledColor),
1283
+ 'box-shadow': this.getStyleValue(this.boxShadow)
1284
+ };
1285
+ }
1286
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1287
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DropdownComponent, isStandalone: false, selector: "lib-dropdown", inputs: { config: "config", labels: "labels", options: "options", placeholder: "placeholder", label: "label", multiple: "multiple", searchable: "searchable", clearable: "clearable", disabled: "disabled", required: "required", errorMessage: "errorMessage", width: "width", height: "height", borderRadius: "borderRadius", fontSize: "fontSize", gap: "gap", fontFamily: "fontFamily", labelColor: "labelColor", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight", backgroundColor: "backgroundColor", borderColor: "borderColor", borderWidth: "borderWidth", padding: "padding", fontWeight: "fontWeight", color: "color", placeholderColor: "placeholderColor", focusBorderColor: "focusBorderColor", errorColor: "errorColor", disabledBackgroundColor: "disabledBackgroundColor", disabledColor: "disabledColor", boxShadow: "boxShadow" }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "keydown": "handleKeyboardEvent($event)" } }, providers: [
1288
+ {
1289
+ provide: NG_VALUE_ACCESSOR,
1290
+ useExisting: forwardRef(() => DropdownComponent),
1291
+ multi: true
1292
+ }
1293
+ ], viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-dropdown-wrapper\" [ngStyle]=\"wrapperStyles\" libClickOutside (libClickOutside)=\"close()\">\r\n <!-- Label -->\r\n <label *ngIf=\"label\" class=\"cc-dropdown-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <!-- Trigger -->\r\n <div class=\"cc-dropdown-trigger\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\" [class.error]=\"errorMessage\"\r\n (click)=\"toggle()\" tabindex=\"0\" (keydown)=\"handleKeyboardEvent($event)\" [ngStyle]=\"fieldStyles\">\r\n\r\n <div class=\"cc-selected-value\" *ngIf=\"hasValue()\">\r\n {{ multiple ? value.length + ' ' + selectedSuffix : getSelectedLabel() }}\r\n </div>\r\n <div class=\"cc-placeholder\" *ngIf=\"!hasValue()\">{{ placeholder }}</div>\r\n\r\n <div class=\"cc-actions\">\r\n <span *ngIf=\"clearable && hasValue() && !disabled\" class=\"cc-clear-btn\" (click)=\"clearSelection($event)\"\r\n [attr.aria-label]=\"clearAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </span>\r\n <span class=\"cc-arrow material-icons\">expand_more</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Dropdown Menu -->\r\n <div class=\"cc-dropdown-menu\" *ngIf=\"isOpen\">\r\n <!-- Search -->\r\n <div class=\"cc-search-container\" *ngIf=\"searchable\">\r\n <input type=\"text\" #searchInput [placeholder]=\"searchPlaceholder\"\r\n (input)=\"onSearch($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\r\n class=\"cc-dropdown-search-input\" />\r\n </div>\r\n\r\n <!-- Options Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport itemSize=\"40\" class=\"cc-virtual-scroll\"\r\n [style.height.px]=\"filteredOptions.length * 40 > 240 ? 240 : (filteredOptions.length * 40 || 40)\">\r\n\r\n <div *cdkVirtualFor=\"let option of filteredOptions; let i = index\" class=\"cc-option\"\r\n [class.selected]=\"isSelected(option)\" [class.focused]=\"i === focusedIndex\"\r\n [class.disabled]=\"option.disabled\" (click)=\"selectOption(option)\">\r\n\r\n <!-- Multi-select checkbox visual -->\r\n <span class=\"cc-multi-check\" *ngIf=\"multiple\">\r\n <span class=\"material-icons\" *ngIf=\"isSelected(option)\">check_box</span>\r\n <span class=\"material-icons\" *ngIf=\"!isSelected(option)\">check_box_outline_blank</span>\r\n </span>\r\n\r\n <!-- Icon -->\r\n <span class=\"cc-option-icon-wrapper\" *ngIf=\"option.icon\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(option.icon) === 'material'\">{{\r\n getIconValue(option.icon) }}</span>\r\n <i *ngIf=\"getIconType(option.icon) === 'fontawesome'\" [class]=\"getIconValue(option.icon)\"></i>\r\n <img *ngIf=\"getIconType(option.icon) === 'img'\" [src]=\"getIconValue(option.icon)\"\r\n class=\"cc-option-img\" alt=\"icon\" />\r\n </span>\r\n\r\n <span class=\"cc-option-label\">{{ option.label }}</span>\r\n\r\n <!-- Single-select check visual -->\r\n <span class=\"cc-single-check\" *ngIf=\"!multiple && isSelected(option)\">\r\n <span class=\"material-icons\">check</span>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"cc-no-results\">{{ labels?.noResultsFound || 'No results\r\n found' }}</div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-dropdown-wrapper{display:flex;flex-direction:column;width:100%;position:relative;font-family:var(--cc-dropdown-font-family, inherit);gap:var(--cc-dropdown-label-gap, .5rem)}.cc-dropdown-label{font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 500);color:var(--cc-dropdown-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-dropdown-required-color, #D93025);margin-left:.25rem}.cc-dropdown-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;min-height:var(--cc-dropdown-height, 2.5rem);padding:var(--cc-dropdown-padding, .5rem .75rem);background-color:var(--cc-dropdown-bg, #FEFEFE);border:var(--cc-dropdown-border-width, 1px) solid var(--cc-dropdown-border-color, #BDC1C6);border-radius:var(--cc-dropdown-border-radius, .4375rem);cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box;transition:all .2s}.cc-dropdown-trigger:focus{outline:none;border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.open{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.error{border-color:var(--cc-dropdown-error-color, #D93025)}.cc-dropdown-trigger.disabled{background-color:var(--cc-dropdown-disabled-bg, #F1F3F4);cursor:not-allowed;color:var(--cc-dropdown-disabled-color, #80868B)}.cc-dropdown-trigger.disabled .cc-arrow,.cc-dropdown-trigger.disabled .cc-clear-btn{color:var(--cc-dropdown-disabled-color, #80868B)}.cc-selected-value{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 400)}.cc-placeholder{flex:1;color:var(--cc-dropdown-placeholder-color, #80868B);font-size:var(--cc-dropdown-font-size, .875rem)}.cc-actions{display:flex;align-items:center;gap:.5rem}.cc-arrow{color:var(--cc-dropdown-arrow-color, #5F6368);transition:transform .2s;font-size:1.25rem}.cc-dropdown-trigger.open .cc-arrow{transform:rotate(180deg)}.cc-clear-btn{display:flex;align-items:center;justify-content:center;color:var(--cc-dropdown-arrow-color, #5F6368);cursor:pointer}.cc-clear-btn:hover{color:#202124}.cc-clear-btn .material-icons{font-size:1.125rem}.cc-dropdown-menu{position:absolute;top:100%;left:0;width:100%;background-color:#fff;border:1px solid #BDC1C6;border-radius:0 0 4px 4px;box-shadow:0 2px 4px #0000001a;z-index:1000;margin-top:2px;overflow:hidden;animation:fadeIn .1s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-search-container{padding:.5rem;border-bottom:1px solid var(--cc-dropdown-divider-color, #E0E0E0)}.cc-dropdown-search-input{width:100%;padding:.5rem;border:1px solid #BDC1C6;border-radius:4px;outline:none;box-sizing:border-box;font-size:.875rem}.cc-dropdown-search-input:focus{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-virtual-scroll{width:100%;max-height:240px}.cc-option{display:flex;align-items:center;padding:0 .75rem;height:40px;cursor:pointer;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);transition:background-color .1s;box-sizing:border-box}.cc-option:hover,.cc-option.focused{background-color:#f1f3f4}.cc-option.selected{background-color:#e8f0fe;color:#1a73e8}.cc-option.disabled{opacity:.5;cursor:not-allowed;background-color:transparent}.cc-multi-check{margin-right:.5rem;color:var(--cc-dropdown-arrow-color, #5F6368);display:flex;align-items:center}.cc-multi-check .material-icons{font-size:1.25rem}.cc-option.selected .cc-multi-check{color:#1a73e8}.cc-option-icon-wrapper{margin-right:.5rem;display:flex;align-items:center}.cc-option-icon-wrapper .material-icons{font-size:1.25rem}.cc-option-img{width:1.25rem;height:1.25rem;object-fit:contain}.cc-option-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cc-single-check{margin-left:.5rem;color:#1a73e8;display:flex;align-items:center}.cc-single-check .material-icons{font-size:1.125rem}.cc-no-results{padding:.75rem;color:#80868b;text-align:center;font-size:.875rem}.cc-error-message{font-size:.75rem;color:var(--cc-dropdown-error-color, #D93025);margin-top:.25rem}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2$1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2$1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2$1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: ClickOutsideDirective, selector: "[libClickOutside]", outputs: ["libClickOutside"] }] });
1294
+ }
1295
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DropdownComponent, decorators: [{
1296
+ type: Component,
1297
+ args: [{ selector: 'lib-dropdown', standalone: false, providers: [
1298
+ {
1299
+ provide: NG_VALUE_ACCESSOR,
1300
+ useExisting: forwardRef(() => DropdownComponent),
1301
+ multi: true
1302
+ }
1303
+ ], template: "<div class=\"cc-dropdown-wrapper\" [ngStyle]=\"wrapperStyles\" libClickOutside (libClickOutside)=\"close()\">\r\n <!-- Label -->\r\n <label *ngIf=\"label\" class=\"cc-dropdown-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <!-- Trigger -->\r\n <div class=\"cc-dropdown-trigger\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\" [class.error]=\"errorMessage\"\r\n (click)=\"toggle()\" tabindex=\"0\" (keydown)=\"handleKeyboardEvent($event)\" [ngStyle]=\"fieldStyles\">\r\n\r\n <div class=\"cc-selected-value\" *ngIf=\"hasValue()\">\r\n {{ multiple ? value.length + ' ' + selectedSuffix : getSelectedLabel() }}\r\n </div>\r\n <div class=\"cc-placeholder\" *ngIf=\"!hasValue()\">{{ placeholder }}</div>\r\n\r\n <div class=\"cc-actions\">\r\n <span *ngIf=\"clearable && hasValue() && !disabled\" class=\"cc-clear-btn\" (click)=\"clearSelection($event)\"\r\n [attr.aria-label]=\"clearAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </span>\r\n <span class=\"cc-arrow material-icons\">expand_more</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Dropdown Menu -->\r\n <div class=\"cc-dropdown-menu\" *ngIf=\"isOpen\">\r\n <!-- Search -->\r\n <div class=\"cc-search-container\" *ngIf=\"searchable\">\r\n <input type=\"text\" #searchInput [placeholder]=\"searchPlaceholder\"\r\n (input)=\"onSearch($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\r\n class=\"cc-dropdown-search-input\" />\r\n </div>\r\n\r\n <!-- Options Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport itemSize=\"40\" class=\"cc-virtual-scroll\"\r\n [style.height.px]=\"filteredOptions.length * 40 > 240 ? 240 : (filteredOptions.length * 40 || 40)\">\r\n\r\n <div *cdkVirtualFor=\"let option of filteredOptions; let i = index\" class=\"cc-option\"\r\n [class.selected]=\"isSelected(option)\" [class.focused]=\"i === focusedIndex\"\r\n [class.disabled]=\"option.disabled\" (click)=\"selectOption(option)\">\r\n\r\n <!-- Multi-select checkbox visual -->\r\n <span class=\"cc-multi-check\" *ngIf=\"multiple\">\r\n <span class=\"material-icons\" *ngIf=\"isSelected(option)\">check_box</span>\r\n <span class=\"material-icons\" *ngIf=\"!isSelected(option)\">check_box_outline_blank</span>\r\n </span>\r\n\r\n <!-- Icon -->\r\n <span class=\"cc-option-icon-wrapper\" *ngIf=\"option.icon\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(option.icon) === 'material'\">{{\r\n getIconValue(option.icon) }}</span>\r\n <i *ngIf=\"getIconType(option.icon) === 'fontawesome'\" [class]=\"getIconValue(option.icon)\"></i>\r\n <img *ngIf=\"getIconType(option.icon) === 'img'\" [src]=\"getIconValue(option.icon)\"\r\n class=\"cc-option-img\" alt=\"icon\" />\r\n </span>\r\n\r\n <span class=\"cc-option-label\">{{ option.label }}</span>\r\n\r\n <!-- Single-select check visual -->\r\n <span class=\"cc-single-check\" *ngIf=\"!multiple && isSelected(option)\">\r\n <span class=\"material-icons\">check</span>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"cc-no-results\">{{ labels?.noResultsFound || 'No results\r\n found' }}</div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-dropdown-wrapper{display:flex;flex-direction:column;width:100%;position:relative;font-family:var(--cc-dropdown-font-family, inherit);gap:var(--cc-dropdown-label-gap, .5rem)}.cc-dropdown-label{font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 500);color:var(--cc-dropdown-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-dropdown-required-color, #D93025);margin-left:.25rem}.cc-dropdown-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;min-height:var(--cc-dropdown-height, 2.5rem);padding:var(--cc-dropdown-padding, .5rem .75rem);background-color:var(--cc-dropdown-bg, #FEFEFE);border:var(--cc-dropdown-border-width, 1px) solid var(--cc-dropdown-border-color, #BDC1C6);border-radius:var(--cc-dropdown-border-radius, .4375rem);cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box;transition:all .2s}.cc-dropdown-trigger:focus{outline:none;border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.open{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.error{border-color:var(--cc-dropdown-error-color, #D93025)}.cc-dropdown-trigger.disabled{background-color:var(--cc-dropdown-disabled-bg, #F1F3F4);cursor:not-allowed;color:var(--cc-dropdown-disabled-color, #80868B)}.cc-dropdown-trigger.disabled .cc-arrow,.cc-dropdown-trigger.disabled .cc-clear-btn{color:var(--cc-dropdown-disabled-color, #80868B)}.cc-selected-value{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 400)}.cc-placeholder{flex:1;color:var(--cc-dropdown-placeholder-color, #80868B);font-size:var(--cc-dropdown-font-size, .875rem)}.cc-actions{display:flex;align-items:center;gap:.5rem}.cc-arrow{color:var(--cc-dropdown-arrow-color, #5F6368);transition:transform .2s;font-size:1.25rem}.cc-dropdown-trigger.open .cc-arrow{transform:rotate(180deg)}.cc-clear-btn{display:flex;align-items:center;justify-content:center;color:var(--cc-dropdown-arrow-color, #5F6368);cursor:pointer}.cc-clear-btn:hover{color:#202124}.cc-clear-btn .material-icons{font-size:1.125rem}.cc-dropdown-menu{position:absolute;top:100%;left:0;width:100%;background-color:#fff;border:1px solid #BDC1C6;border-radius:0 0 4px 4px;box-shadow:0 2px 4px #0000001a;z-index:1000;margin-top:2px;overflow:hidden;animation:fadeIn .1s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-search-container{padding:.5rem;border-bottom:1px solid var(--cc-dropdown-divider-color, #E0E0E0)}.cc-dropdown-search-input{width:100%;padding:.5rem;border:1px solid #BDC1C6;border-radius:4px;outline:none;box-sizing:border-box;font-size:.875rem}.cc-dropdown-search-input:focus{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-virtual-scroll{width:100%;max-height:240px}.cc-option{display:flex;align-items:center;padding:0 .75rem;height:40px;cursor:pointer;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);transition:background-color .1s;box-sizing:border-box}.cc-option:hover,.cc-option.focused{background-color:#f1f3f4}.cc-option.selected{background-color:#e8f0fe;color:#1a73e8}.cc-option.disabled{opacity:.5;cursor:not-allowed;background-color:transparent}.cc-multi-check{margin-right:.5rem;color:var(--cc-dropdown-arrow-color, #5F6368);display:flex;align-items:center}.cc-multi-check .material-icons{font-size:1.25rem}.cc-option.selected .cc-multi-check{color:#1a73e8}.cc-option-icon-wrapper{margin-right:.5rem;display:flex;align-items:center}.cc-option-icon-wrapper .material-icons{font-size:1.25rem}.cc-option-img{width:1.25rem;height:1.25rem;object-fit:contain}.cc-option-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cc-single-check{margin-left:.5rem;color:#1a73e8;display:flex;align-items:center}.cc-single-check .material-icons{font-size:1.125rem}.cc-no-results{padding:.75rem;color:#80868b;text-align:center;font-size:.875rem}.cc-error-message{font-size:.75rem;color:var(--cc-dropdown-error-color, #D93025);margin-top:.25rem}\n"] }]
1304
+ }], propDecorators: { config: [{
1305
+ type: Input
1306
+ }], labels: [{
1307
+ type: Input
1308
+ }], options: [{
1309
+ type: Input
1310
+ }], placeholder: [{
1311
+ type: Input
1312
+ }], label: [{
1313
+ type: Input
1314
+ }], multiple: [{
1315
+ type: Input
1316
+ }], searchable: [{
1317
+ type: Input
1318
+ }], clearable: [{
1319
+ type: Input
1320
+ }], disabled: [{
1321
+ type: Input
1322
+ }], required: [{
1323
+ type: Input
1324
+ }], errorMessage: [{
1325
+ type: Input
1326
+ }], width: [{
1327
+ type: Input
1328
+ }], height: [{
1329
+ type: Input
1330
+ }], borderRadius: [{
1331
+ type: Input
1332
+ }], fontSize: [{
1333
+ type: Input
1334
+ }], gap: [{
1335
+ type: Input
1336
+ }], fontFamily: [{
1337
+ type: Input
1338
+ }], labelColor: [{
1339
+ type: Input
1340
+ }], labelFontSize: [{
1341
+ type: Input
1342
+ }], labelFontWeight: [{
1343
+ type: Input
1344
+ }], backgroundColor: [{
1345
+ type: Input
1346
+ }], borderColor: [{
1347
+ type: Input
1348
+ }], borderWidth: [{
1349
+ type: Input
1350
+ }], padding: [{
1351
+ type: Input
1352
+ }], fontWeight: [{
1353
+ type: Input
1354
+ }], color: [{
1355
+ type: Input
1356
+ }], placeholderColor: [{
1357
+ type: Input
1358
+ }], focusBorderColor: [{
1359
+ type: Input
1360
+ }], errorColor: [{
1361
+ type: Input
1362
+ }], disabledBackgroundColor: [{
1363
+ type: Input
1364
+ }], disabledColor: [{
1365
+ type: Input
1366
+ }], boxShadow: [{
1367
+ type: Input
1368
+ }], selectionChange: [{
1369
+ type: Output
1370
+ }], viewport: [{
1371
+ type: ViewChild,
1372
+ args: [CdkVirtualScrollViewport]
1373
+ }], searchInput: [{
1374
+ type: ViewChild,
1375
+ args: ['searchInput']
1376
+ }], handleKeyboardEvent: [{
1377
+ type: HostListener,
1378
+ args: ['keydown', ['$event']]
1379
+ }] } });
1380
+
1381
+ class CheckboxComponent {
1382
+ config = {};
1383
+ labels;
1384
+ label = '';
1385
+ checked = false;
1386
+ disabled = false;
1387
+ required = false;
1388
+ indeterminate = false;
1389
+ options = [];
1390
+ labelPosition = 'after';
1391
+ color = '#007bff';
1392
+ borderRadius = '4px';
1393
+ value = null;
1394
+ errorMessage = '';
1395
+ // Style inputs
1396
+ width;
1397
+ height;
1398
+ fontSize;
1399
+ fontWeight;
1400
+ labelColor;
1401
+ labelFontSize;
1402
+ labelFontWeight;
1403
+ gap;
1404
+ fontFamily;
1405
+ backgroundColor;
1406
+ borderColor;
1407
+ borderWidth;
1408
+ padding;
1409
+ placeholderColor;
1410
+ focusBorderColor;
1411
+ errorColor;
1412
+ disabledBackgroundColor;
1413
+ disabledColor;
1414
+ boxShadow;
1415
+ size;
1416
+ checkedColor;
1417
+ uncheckedColor;
1418
+ groupLabelColor;
1419
+ groupLabelFontSize;
1420
+ groupLabelFontWeight;
1421
+ checkedChange = new EventEmitter();
1422
+ onChange = () => { };
1423
+ onTouched = () => { };
1424
+ ngOnInit() {
1425
+ this.updateFromConfig();
1426
+ this.updateFromLabels();
1427
+ if (this.isGroup) {
1428
+ this.value = this.options
1429
+ .filter(opt => opt.checked)
1430
+ .map(opt => opt.value);
1431
+ }
1432
+ else {
1433
+ this.value = this.checked;
1434
+ }
1435
+ }
1436
+ ngOnChanges(changes) {
1437
+ if (changes['config']) {
1438
+ this.updateFromConfig();
1439
+ }
1440
+ if (changes['labels']) {
1441
+ this.updateFromLabels();
1442
+ }
1443
+ }
1444
+ updateFromConfig() {
1445
+ if (this.config) {
1446
+ this.label = this.config.label ?? this.label;
1447
+ this.checked = this.config.checked ?? this.checked;
1448
+ this.disabled = this.config.disabled ?? this.disabled;
1449
+ this.required = this.config.required ?? this.required;
1450
+ this.indeterminate = this.config.indeterminate ?? this.indeterminate;
1451
+ this.options = this.config.options || this.options;
1452
+ this.labelPosition = this.config.labelPosition ?? this.labelPosition;
1453
+ this.color = this.config.color ?? this.color;
1454
+ this.borderRadius = this.config.borderRadius ?? this.borderRadius;
1455
+ this.size = this.config.size ?? this.size;
1456
+ this.checkedColor = this.config.checkedColor ?? this.checkedColor;
1457
+ this.uncheckedColor = this.config.uncheckedColor ?? this.uncheckedColor;
1458
+ this.groupLabelColor = this.config.groupLabelColor ?? this.groupLabelColor;
1459
+ this.groupLabelFontSize = this.config.groupLabelFontSize ?? this.groupLabelFontSize;
1460
+ this.groupLabelFontWeight = this.config.groupLabelFontWeight ?? this.groupLabelFontWeight;
1461
+ this.labelFontSize = this.config.labelFontSize ?? this.labelFontSize;
1462
+ this.labelFontWeight = this.config.labelFontWeight ?? this.labelFontWeight;
1463
+ this.labelColor = this.config.labelColor ?? this.labelColor;
1464
+ this.gap = this.config.gap ?? this.gap;
1465
+ this.fontFamily = this.config.fontFamily ?? this.fontFamily;
1466
+ }
1467
+ }
1468
+ updateFromLabels() {
1469
+ if (this.labels) {
1470
+ this.label = this.labels.label || this.label;
1471
+ }
1472
+ }
1473
+ get isGroup() {
1474
+ return this.options && this.options.length > 0;
1475
+ }
1476
+ get requiredMarker() {
1477
+ return this.labels?.requiredMarker || '*';
1478
+ }
1479
+ writeValue(value) {
1480
+ if (this.isGroup) {
1481
+ this.value = Array.isArray(value) ? value : [];
1482
+ this.options.forEach(opt => {
1483
+ opt.checked = this.value.includes(opt.value);
1484
+ });
1485
+ }
1486
+ else {
1487
+ this.value = !!value;
1488
+ this.checked = this.value;
1489
+ }
1490
+ }
1491
+ registerOnChange(fn) {
1492
+ this.onChange = fn;
1493
+ }
1494
+ registerOnTouched(fn) {
1495
+ this.onTouched = fn;
1496
+ }
1497
+ setDisabledState(isDisabled) {
1498
+ this.disabled = isDisabled;
1499
+ }
1500
+ onCheckboxChange(event) {
1501
+ const checked = event.target.checked;
1502
+ this.value = checked;
1503
+ this.checked = checked;
1504
+ this.onChange(this.value);
1505
+ this.onTouched();
1506
+ this.checkedChange.emit(this.value);
1507
+ }
1508
+ onGroupCheckboxChange(option, event) {
1509
+ const checked = event.target.checked;
1510
+ option.checked = checked;
1511
+ const valueArray = this.value;
1512
+ if (checked) {
1513
+ if (!valueArray.includes(option.value)) {
1514
+ this.value = [...valueArray, option.value];
1515
+ }
1516
+ }
1517
+ else {
1518
+ this.value = valueArray.filter(v => v !== option.value);
1519
+ }
1520
+ this.onChange(this.value);
1521
+ this.onTouched();
1522
+ this.checkedChange.emit(this.value);
1523
+ }
1524
+ getStyleValue(value) {
1525
+ return value ? `${value}` : undefined;
1526
+ }
1527
+ get wrapperStyles() {
1528
+ return {
1529
+ '--cc-checkbox-font-family': this.getStyleValue(this.fontFamily),
1530
+ '--cc-checkbox-font-size': this.getStyleValue(this.fontSize),
1531
+ '--cc-checkbox-font-weight': this.getStyleValue(this.fontWeight),
1532
+ '--cc-checkbox-label-color': this.getStyleValue(this.labelColor),
1533
+ '--cc-checkbox-size': this.getStyleValue(this.size),
1534
+ '--cc-checkbox-checked-color': this.getStyleValue(this.checkedColor),
1535
+ '--cc-checkbox-unchecked-color': this.getStyleValue(this.uncheckedColor),
1536
+ '--cc-checkbox-disabled-color': this.getStyleValue(this.disabledColor),
1537
+ '--cc-checkbox-error-color': this.getStyleValue(this.errorColor),
1538
+ '--cc-checkbox-group-gap': this.getStyleValue(this.gap),
1539
+ '--cc-checkbox-group-label-color': this.getStyleValue(this.groupLabelColor),
1540
+ '--cc-checkbox-group-label-font-size': this.getStyleValue(this.groupLabelFontSize),
1541
+ '--cc-checkbox-group-label-font-weight': this.getStyleValue(this.groupLabelFontWeight),
1542
+ '--cc-checkbox-label-font-size': this.getStyleValue(this.labelFontSize),
1543
+ '--cc-checkbox-label-font-weight': this.getStyleValue(this.labelFontWeight),
1544
+ '--cc-checkbox-border-radius': this.getStyleValue(this.borderRadius)
1545
+ };
1546
+ }
1547
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1548
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: CheckboxComponent, isStandalone: false, selector: "lib-checkbox", inputs: { config: "config", labels: "labels", label: "label", checked: "checked", disabled: "disabled", required: "required", indeterminate: "indeterminate", options: "options", labelPosition: "labelPosition", color: "color", borderRadius: "borderRadius", value: "value", errorMessage: "errorMessage", width: "width", height: "height", fontSize: "fontSize", fontWeight: "fontWeight", labelColor: "labelColor", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight", gap: "gap", fontFamily: "fontFamily", backgroundColor: "backgroundColor", borderColor: "borderColor", borderWidth: "borderWidth", padding: "padding", placeholderColor: "placeholderColor", focusBorderColor: "focusBorderColor", errorColor: "errorColor", disabledBackgroundColor: "disabledBackgroundColor", disabledColor: "disabledColor", boxShadow: "boxShadow", size: "size", checkedColor: "checkedColor", uncheckedColor: "uncheckedColor", groupLabelColor: "groupLabelColor", groupLabelFontSize: "groupLabelFontSize", groupLabelFontWeight: "groupLabelFontWeight" }, outputs: { checkedChange: "checkedChange" }, providers: [
1549
+ {
1550
+ provide: NG_VALUE_ACCESSOR,
1551
+ useExisting: forwardRef(() => CheckboxComponent),
1552
+ multi: true
1553
+ }
1554
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-checkbox-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n\r\n <!-- Single Checkbox -->\r\n <label *ngIf=\"!isGroup\" class=\"cc-checkbox-label\" [class.label-before]=\"labelPosition === 'before'\"\r\n [class.disabled]=\"disabled\" [class.checked]=\"checked\">\r\n <input type=\"checkbox\" class=\"cc-native-checkbox\" [checked]=\"checked\" [disabled]=\"disabled\"\r\n [required]=\"required\" [indeterminate]=\"indeterminate\" (change)=\"onCheckboxChange($event)\" />\r\n <span class=\"cc-checkmark\"></span>\r\n <span class=\"cc-text\" *ngIf=\"label\">{{ label }}</span>\r\n </label>\r\n\r\n <!-- Checkbox Group -->\r\n <div *ngIf=\"isGroup\" class=\"cc-checkbox-group\">\r\n <label *ngIf=\"label\" class=\"cc-checkbox-group-label\" [class.label-before]=\"labelPosition === 'before'\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <label *ngFor=\"let option of options\" class=\"cc-checkbox-label\" [class.disabled]=\"disabled || option.disabled\"\r\n [class.checked]=\"option.checked\">\r\n <input type=\"checkbox\" class=\"cc-native-checkbox\" [checked]=\"option.checked\"\r\n [disabled]=\"disabled || option.disabled\" (change)=\"onGroupCheckboxChange(option, $event)\" />\r\n <span class=\"cc-checkmark\"></span>\r\n <span class=\"cc-text\">{{ option.label }}</span>\r\n </label>\r\n </div>\r\n\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-checkbox-wrapper{display:flex;flex-direction:column;font-family:var(--cc-checkbox-font-family, inherit)}.cc-checkbox-label{display:inline-flex;align-items:center;position:relative;cursor:pointer;font-size:var(--cc-checkbox-label-font-size, var(--cc-checkbox-font-size, .875rem));font-weight:var(--cc-checkbox-label-font-weight, var(--cc-checkbox-font-weight, 400));color:var(--cc-checkbox-label-color, #202124);-webkit-user-select:none;user-select:none;margin-bottom:var(--cc-checkbox-margin-bottom, .5rem)}.cc-checkbox-label.label-before{flex-direction:row-reverse}.cc-checkbox-label.label-before .cc-checkmark{margin-right:0;margin-left:.5rem}.cc-checkbox-label.disabled{cursor:not-allowed;color:var(--cc-checkbox-disabled-color, #80868B)}.cc-checkbox-label.disabled .cc-checkmark{border-color:var(--cc-checkbox-disabled-color, #80868B);background-color:transparent}.cc-native-checkbox{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.cc-native-checkbox:checked~.cc-checkmark{background-color:var(--cc-checkbox-checked-color, #1A73E8);border-color:var(--cc-checkbox-checked-color, #1A73E8)}.cc-native-checkbox:checked~.cc-checkmark:after{display:block}.cc-native-checkbox:disabled:checked~.cc-checkmark{background-color:var(--cc-checkbox-disabled-color, #80868B);border-color:var(--cc-checkbox-disabled-color, #80868B)}.cc-checkmark{position:relative;height:var(--cc-checkbox-size, 1.125rem);width:var(--cc-checkbox-size, 1.125rem);background-color:transparent;border:2px solid var(--cc-checkbox-unchecked-color, #BDC1C6);border-radius:var(--cc-checkbox-border-radius, 2px);transition:all .2s ease-in-out;margin-right:.5rem;flex-shrink:0}.cc-checkmark:after{content:\"\";position:absolute;display:none;left:50%;top:45%;width:30%;height:60%;border:solid white;border-width:0 2px 2px 0;transform:translate(-50%,-50%) rotate(45deg)}.cc-checkbox-group{display:flex;flex-direction:column;gap:var(--cc-checkbox-group-gap, .75rem)}.cc-checkbox-group-label{font-size:var(--cc-checkbox-group-label-font-size, .875rem);font-weight:var(--cc-checkbox-group-label-font-weight, 500);color:var(--cc-checkbox-group-label-color, #202124);margin-bottom:.5rem}.cc-required{color:var(--cc-checkbox-required-color, #D93025);margin-left:.25rem}.cc-error-message{font-size:.75rem;color:var(--cc-checkbox-error-color, #D93025);margin-top:.25rem}\n"], dependencies: [{ 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"] }] });
1555
+ }
1556
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CheckboxComponent, decorators: [{
1557
+ type: Component,
1558
+ args: [{ selector: 'lib-checkbox', standalone: false, providers: [
1559
+ {
1560
+ provide: NG_VALUE_ACCESSOR,
1561
+ useExisting: forwardRef(() => CheckboxComponent),
1562
+ multi: true
1563
+ }
1564
+ ], template: "<div class=\"cc-checkbox-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n\r\n <!-- Single Checkbox -->\r\n <label *ngIf=\"!isGroup\" class=\"cc-checkbox-label\" [class.label-before]=\"labelPosition === 'before'\"\r\n [class.disabled]=\"disabled\" [class.checked]=\"checked\">\r\n <input type=\"checkbox\" class=\"cc-native-checkbox\" [checked]=\"checked\" [disabled]=\"disabled\"\r\n [required]=\"required\" [indeterminate]=\"indeterminate\" (change)=\"onCheckboxChange($event)\" />\r\n <span class=\"cc-checkmark\"></span>\r\n <span class=\"cc-text\" *ngIf=\"label\">{{ label }}</span>\r\n </label>\r\n\r\n <!-- Checkbox Group -->\r\n <div *ngIf=\"isGroup\" class=\"cc-checkbox-group\">\r\n <label *ngIf=\"label\" class=\"cc-checkbox-group-label\" [class.label-before]=\"labelPosition === 'before'\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <label *ngFor=\"let option of options\" class=\"cc-checkbox-label\" [class.disabled]=\"disabled || option.disabled\"\r\n [class.checked]=\"option.checked\">\r\n <input type=\"checkbox\" class=\"cc-native-checkbox\" [checked]=\"option.checked\"\r\n [disabled]=\"disabled || option.disabled\" (change)=\"onGroupCheckboxChange(option, $event)\" />\r\n <span class=\"cc-checkmark\"></span>\r\n <span class=\"cc-text\">{{ option.label }}</span>\r\n </label>\r\n </div>\r\n\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-checkbox-wrapper{display:flex;flex-direction:column;font-family:var(--cc-checkbox-font-family, inherit)}.cc-checkbox-label{display:inline-flex;align-items:center;position:relative;cursor:pointer;font-size:var(--cc-checkbox-label-font-size, var(--cc-checkbox-font-size, .875rem));font-weight:var(--cc-checkbox-label-font-weight, var(--cc-checkbox-font-weight, 400));color:var(--cc-checkbox-label-color, #202124);-webkit-user-select:none;user-select:none;margin-bottom:var(--cc-checkbox-margin-bottom, .5rem)}.cc-checkbox-label.label-before{flex-direction:row-reverse}.cc-checkbox-label.label-before .cc-checkmark{margin-right:0;margin-left:.5rem}.cc-checkbox-label.disabled{cursor:not-allowed;color:var(--cc-checkbox-disabled-color, #80868B)}.cc-checkbox-label.disabled .cc-checkmark{border-color:var(--cc-checkbox-disabled-color, #80868B);background-color:transparent}.cc-native-checkbox{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.cc-native-checkbox:checked~.cc-checkmark{background-color:var(--cc-checkbox-checked-color, #1A73E8);border-color:var(--cc-checkbox-checked-color, #1A73E8)}.cc-native-checkbox:checked~.cc-checkmark:after{display:block}.cc-native-checkbox:disabled:checked~.cc-checkmark{background-color:var(--cc-checkbox-disabled-color, #80868B);border-color:var(--cc-checkbox-disabled-color, #80868B)}.cc-checkmark{position:relative;height:var(--cc-checkbox-size, 1.125rem);width:var(--cc-checkbox-size, 1.125rem);background-color:transparent;border:2px solid var(--cc-checkbox-unchecked-color, #BDC1C6);border-radius:var(--cc-checkbox-border-radius, 2px);transition:all .2s ease-in-out;margin-right:.5rem;flex-shrink:0}.cc-checkmark:after{content:\"\";position:absolute;display:none;left:50%;top:45%;width:30%;height:60%;border:solid white;border-width:0 2px 2px 0;transform:translate(-50%,-50%) rotate(45deg)}.cc-checkbox-group{display:flex;flex-direction:column;gap:var(--cc-checkbox-group-gap, .75rem)}.cc-checkbox-group-label{font-size:var(--cc-checkbox-group-label-font-size, .875rem);font-weight:var(--cc-checkbox-group-label-font-weight, 500);color:var(--cc-checkbox-group-label-color, #202124);margin-bottom:.5rem}.cc-required{color:var(--cc-checkbox-required-color, #D93025);margin-left:.25rem}.cc-error-message{font-size:.75rem;color:var(--cc-checkbox-error-color, #D93025);margin-top:.25rem}\n"] }]
1565
+ }], propDecorators: { config: [{
1566
+ type: Input
1567
+ }], labels: [{
1568
+ type: Input
1569
+ }], label: [{
1570
+ type: Input
1571
+ }], checked: [{
1572
+ type: Input
1573
+ }], disabled: [{
1574
+ type: Input
1575
+ }], required: [{
1576
+ type: Input
1577
+ }], indeterminate: [{
1578
+ type: Input
1579
+ }], options: [{
1580
+ type: Input
1581
+ }], labelPosition: [{
1582
+ type: Input
1583
+ }], color: [{
1584
+ type: Input
1585
+ }], borderRadius: [{
1586
+ type: Input
1587
+ }], value: [{
1588
+ type: Input
1589
+ }], errorMessage: [{
1590
+ type: Input
1591
+ }], width: [{
1592
+ type: Input
1593
+ }], height: [{
1594
+ type: Input
1595
+ }], fontSize: [{
1596
+ type: Input
1597
+ }], fontWeight: [{
1598
+ type: Input
1599
+ }], labelColor: [{
1600
+ type: Input
1601
+ }], labelFontSize: [{
1602
+ type: Input
1603
+ }], labelFontWeight: [{
1604
+ type: Input
1605
+ }], gap: [{
1606
+ type: Input
1607
+ }], fontFamily: [{
1608
+ type: Input
1609
+ }], backgroundColor: [{
1610
+ type: Input
1611
+ }], borderColor: [{
1612
+ type: Input
1613
+ }], borderWidth: [{
1614
+ type: Input
1615
+ }], padding: [{
1616
+ type: Input
1617
+ }], placeholderColor: [{
1618
+ type: Input
1619
+ }], focusBorderColor: [{
1620
+ type: Input
1621
+ }], errorColor: [{
1622
+ type: Input
1623
+ }], disabledBackgroundColor: [{
1624
+ type: Input
1625
+ }], disabledColor: [{
1626
+ type: Input
1627
+ }], boxShadow: [{
1628
+ type: Input
1629
+ }], size: [{
1630
+ type: Input
1631
+ }], checkedColor: [{
1632
+ type: Input
1633
+ }], uncheckedColor: [{
1634
+ type: Input
1635
+ }], groupLabelColor: [{
1636
+ type: Input
1637
+ }], groupLabelFontSize: [{
1638
+ type: Input
1639
+ }], groupLabelFontWeight: [{
1640
+ type: Input
1641
+ }], checkedChange: [{
1642
+ type: Output
1643
+ }] } });
1644
+
1645
+ class RadioComponent {
1646
+ config;
1647
+ label = '';
1648
+ options = [];
1649
+ disabled = false;
1650
+ required = false;
1651
+ labelPosition = 'after';
1652
+ color = 'primary';
1653
+ layout = 'vertical';
1654
+ // i18n Labels
1655
+ labels = {};
1656
+ // Customization — Layout
1657
+ gap;
1658
+ // Customization — Colors
1659
+ labelColor;
1660
+ checkedColor;
1661
+ uncheckedColor;
1662
+ // Customization — Typography
1663
+ fontSize;
1664
+ fontWeight;
1665
+ fontFamily;
1666
+ // Customization — Group label
1667
+ groupLabelColor;
1668
+ groupLabelFontSize;
1669
+ groupLabelFontWeight;
1670
+ // Customization — States
1671
+ disabledColor;
1672
+ errorColor;
1673
+ // Customization — Size
1674
+ size;
1675
+ borderRadius;
1676
+ // Customization — Synonyms for Playground
1677
+ labelFontSize;
1678
+ labelFontWeight;
1679
+ selectionChange = new EventEmitter();
1680
+ value;
1681
+ uuid = `radio-group-${Math.random().toString(36).substr(2, 9)}`;
1682
+ onChange = () => { };
1683
+ onTouched = () => { };
1684
+ ngOnInit() {
1685
+ this.updateFromConfig();
1686
+ // i18n labels override
1687
+ if (this.labels) {
1688
+ this.label = this.labels.label || this.label;
1689
+ }
1690
+ }
1691
+ ngOnChanges(changes) {
1692
+ if (changes.config) {
1693
+ this.updateFromConfig();
1694
+ }
1695
+ }
1696
+ updateFromConfig() {
1697
+ if (this.config) {
1698
+ this.label = this.config.label ?? this.label;
1699
+ this.options = this.config.options || this.options;
1700
+ this.disabled = this.config.disabled ?? this.disabled;
1701
+ this.required = this.config.required ?? this.required;
1702
+ this.labelPosition = this.config.labelPosition ?? this.labelPosition;
1703
+ this.color = this.config.color ?? this.color;
1704
+ this.layout = this.config.layout ?? this.layout;
1705
+ this.value = this.config.value;
1706
+ // Style mappings
1707
+ this.gap = this.config.gap ?? this.gap;
1708
+ this.labelColor = this.config.labelColor ?? this.labelColor;
1709
+ this.checkedColor = this.config.checkedColor ?? this.checkedColor;
1710
+ this.uncheckedColor = this.config.uncheckedColor ?? this.uncheckedColor;
1711
+ this.fontSize = this.config.fontSize ?? this.fontSize;
1712
+ this.fontWeight = this.config.fontWeight ?? this.fontWeight;
1713
+ this.fontFamily = this.config.fontFamily ?? this.fontFamily;
1714
+ this.groupLabelColor = this.config.groupLabelColor ?? this.groupLabelColor;
1715
+ this.groupLabelFontSize = this.config.groupLabelFontSize ?? this.groupLabelFontSize;
1716
+ this.groupLabelFontWeight = this.config.groupLabelFontWeight ?? this.groupLabelFontWeight;
1717
+ this.disabledColor = this.config.disabledColor ?? this.disabledColor;
1718
+ this.errorColor = this.config.errorColor ?? this.errorColor;
1719
+ this.size = this.config.size ?? this.size;
1720
+ this.borderRadius = this.config.borderRadius ?? this.borderRadius;
1721
+ this.labelFontSize = this.config.labelFontSize ?? this.labelFontSize;
1722
+ this.labelFontWeight = this.config.labelFontWeight ?? this.labelFontWeight;
1723
+ }
1724
+ }
1725
+ get requiredMarker() {
1726
+ return this.labels?.requiredMarker || '*';
1727
+ }
1728
+ writeValue(value) {
1729
+ this.value = value;
1730
+ }
1731
+ registerOnChange(fn) {
1732
+ this.onChange = fn;
1733
+ }
1734
+ registerOnTouched(fn) {
1735
+ this.onTouched = fn;
1736
+ }
1737
+ setDisabledState(isDisabled) {
1738
+ this.disabled = isDisabled;
1739
+ }
1740
+ onRadioChange(event) {
1741
+ this.value = event.target.value;
1742
+ this.onChange(this.value);
1743
+ this.onTouched();
1744
+ this.selectionChange.emit(this.value);
1745
+ }
1746
+ getStyleValue(value) {
1747
+ return value ? `${value}` : undefined;
1748
+ }
1749
+ get wrapperStyles() {
1750
+ return {
1751
+ '--cc-radio-font-family': this.getStyleValue(this.fontFamily),
1752
+ '--cc-radio-font-size': this.getStyleValue(this.fontSize || this.labelFontSize),
1753
+ '--cc-radio-font-weight': this.getStyleValue(this.fontWeight || this.labelFontWeight),
1754
+ '--cc-radio-label-color': this.getStyleValue(this.labelColor),
1755
+ '--cc-radio-size': this.getStyleValue(this.size),
1756
+ '--cc-radio-border-radius': this.getStyleValue(this.borderRadius),
1757
+ '--cc-radio-checked-color': this.getStyleValue(this.checkedColor),
1758
+ '--cc-radio-unchecked-color': this.getStyleValue(this.uncheckedColor),
1759
+ '--cc-radio-disabled-color': this.getStyleValue(this.disabledColor),
1760
+ '--cc-radio-error-color': this.getStyleValue(this.errorColor),
1761
+ '--cc-radio-group-gap': this.getStyleValue(this.gap),
1762
+ '--cc-radio-group-label-color': this.getStyleValue(this.groupLabelColor),
1763
+ '--cc-radio-group-label-font-size': this.getStyleValue(this.groupLabelFontSize),
1764
+ '--cc-radio-group-label-font-weight': this.getStyleValue(this.groupLabelFontWeight)
1765
+ };
1766
+ }
1767
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RadioComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1768
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: RadioComponent, isStandalone: false, selector: "lib-radio", inputs: { config: "config", label: "label", options: "options", disabled: "disabled", required: "required", labelPosition: "labelPosition", color: "color", layout: "layout", labels: "labels", gap: "gap", labelColor: "labelColor", checkedColor: "checkedColor", uncheckedColor: "uncheckedColor", fontSize: "fontSize", fontWeight: "fontWeight", fontFamily: "fontFamily", groupLabelColor: "groupLabelColor", groupLabelFontSize: "groupLabelFontSize", groupLabelFontWeight: "groupLabelFontWeight", disabledColor: "disabledColor", errorColor: "errorColor", size: "size", borderRadius: "borderRadius", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight" }, outputs: { selectionChange: "selectionChange" }, providers: [
1769
+ {
1770
+ provide: NG_VALUE_ACCESSOR,
1771
+ useExisting: forwardRef(() => RadioComponent),
1772
+ multi: true
1773
+ }
1774
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-radio-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n <label *ngIf=\"label\" class=\"cc-radio-group-label\" [class.disabled]=\"disabled\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <div class=\"cc-radio-group\" [class.horizontal]=\"layout === 'horizontal'\" [class.vertical]=\"layout === 'vertical'\"\r\n role=\"radiogroup\">\r\n\r\n <label class=\"cc-radio-label\" *ngFor=\"let option of options; let i = index\"\r\n [class.disabled]=\"disabled || option.disabled\" [class.checked]=\"value === option.value\"\r\n [class.label-before]=\"labelPosition === 'before'\">\r\n\r\n <input type=\"radio\" [name]=\"uuid\" [value]=\"option.value\" [checked]=\"value === option.value\"\r\n [disabled]=\"disabled || option.disabled\" (change)=\"onRadioChange($event)\" class=\"cc-native-radio\"\r\n [id]=\"uuid + '-' + i\">\r\n\r\n <span class=\"cc-radio-circle\"></span>\r\n <span class=\"cc-text\">{{ option.label }}</span>\r\n </label>\r\n </div>\r\n</div>", styles: [".cc-radio-wrapper{display:block;width:100%;font-family:var(--cc-radio-font-family, inherit)}.cc-radio-group-label{display:block;font-size:var(--cc-radio-group-label-font-size, 14px);font-weight:var(--cc-radio-group-label-font-weight, 500);color:var(--cc-radio-group-label-color, #202124);margin-bottom:8px}.cc-radio-group{display:flex;gap:var(--cc-radio-group-gap, 12px)}.cc-radio-group.vertical{flex-direction:column}.cc-radio-group.horizontal{flex-direction:row;flex-wrap:wrap}.cc-radio-label{display:flex;align-items:center;cursor:pointer;font-size:var(--cc-radio-font-size, 14px);color:var(--cc-radio-label-color, #202124);-webkit-user-select:none;user-select:none;padding:4px 0}.cc-native-radio{position:absolute;left:-9999px}.cc-radio-circle{width:var(--cc-radio-size, 20px);height:var(--cc-radio-size, 20px);border:2px solid var(--cc-radio-unchecked-color, #5F6368);border-radius:var(--cc-radio-border-radius, 50%);margin-right:8px;flex-shrink:0;position:relative;background:#fff;box-sizing:border-box}.cc-radio-circle:after{content:\"\";width:calc(var(--cc-radio-size, 20px) * .5);height:calc(var(--cc-radio-size, 20px) * .5);background:var(--cc-radio-checked-color, #1A73E8);border-radius:var(--cc-radio-border-radius, 50%);position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) scale(0);transition:transform .2s}.cc-native-radio:checked+.cc-radio-circle{border-color:var(--cc-radio-checked-color, #1A73E8)}.cc-native-radio:checked+.cc-radio-circle:after{transform:translate(-50%,-50%) scale(1)}.cc-text{line-height:1.5}.cc-radio-label.disabled{opacity:.5;cursor:not-allowed}\n"], dependencies: [{ 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"] }] });
1775
+ }
1776
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RadioComponent, decorators: [{
1777
+ type: Component,
1778
+ args: [{ selector: 'lib-radio', standalone: false, providers: [
1779
+ {
1780
+ provide: NG_VALUE_ACCESSOR,
1781
+ useExisting: forwardRef(() => RadioComponent),
1782
+ multi: true
1783
+ }
1784
+ ], template: "<div class=\"cc-radio-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n <label *ngIf=\"label\" class=\"cc-radio-group-label\" [class.disabled]=\"disabled\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <div class=\"cc-radio-group\" [class.horizontal]=\"layout === 'horizontal'\" [class.vertical]=\"layout === 'vertical'\"\r\n role=\"radiogroup\">\r\n\r\n <label class=\"cc-radio-label\" *ngFor=\"let option of options; let i = index\"\r\n [class.disabled]=\"disabled || option.disabled\" [class.checked]=\"value === option.value\"\r\n [class.label-before]=\"labelPosition === 'before'\">\r\n\r\n <input type=\"radio\" [name]=\"uuid\" [value]=\"option.value\" [checked]=\"value === option.value\"\r\n [disabled]=\"disabled || option.disabled\" (change)=\"onRadioChange($event)\" class=\"cc-native-radio\"\r\n [id]=\"uuid + '-' + i\">\r\n\r\n <span class=\"cc-radio-circle\"></span>\r\n <span class=\"cc-text\">{{ option.label }}</span>\r\n </label>\r\n </div>\r\n</div>", styles: [".cc-radio-wrapper{display:block;width:100%;font-family:var(--cc-radio-font-family, inherit)}.cc-radio-group-label{display:block;font-size:var(--cc-radio-group-label-font-size, 14px);font-weight:var(--cc-radio-group-label-font-weight, 500);color:var(--cc-radio-group-label-color, #202124);margin-bottom:8px}.cc-radio-group{display:flex;gap:var(--cc-radio-group-gap, 12px)}.cc-radio-group.vertical{flex-direction:column}.cc-radio-group.horizontal{flex-direction:row;flex-wrap:wrap}.cc-radio-label{display:flex;align-items:center;cursor:pointer;font-size:var(--cc-radio-font-size, 14px);color:var(--cc-radio-label-color, #202124);-webkit-user-select:none;user-select:none;padding:4px 0}.cc-native-radio{position:absolute;left:-9999px}.cc-radio-circle{width:var(--cc-radio-size, 20px);height:var(--cc-radio-size, 20px);border:2px solid var(--cc-radio-unchecked-color, #5F6368);border-radius:var(--cc-radio-border-radius, 50%);margin-right:8px;flex-shrink:0;position:relative;background:#fff;box-sizing:border-box}.cc-radio-circle:after{content:\"\";width:calc(var(--cc-radio-size, 20px) * .5);height:calc(var(--cc-radio-size, 20px) * .5);background:var(--cc-radio-checked-color, #1A73E8);border-radius:var(--cc-radio-border-radius, 50%);position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) scale(0);transition:transform .2s}.cc-native-radio:checked+.cc-radio-circle{border-color:var(--cc-radio-checked-color, #1A73E8)}.cc-native-radio:checked+.cc-radio-circle:after{transform:translate(-50%,-50%) scale(1)}.cc-text{line-height:1.5}.cc-radio-label.disabled{opacity:.5;cursor:not-allowed}\n"] }]
1785
+ }], propDecorators: { config: [{
1786
+ type: Input
1787
+ }], label: [{
1788
+ type: Input
1789
+ }], options: [{
1790
+ type: Input
1791
+ }], disabled: [{
1792
+ type: Input
1793
+ }], required: [{
1794
+ type: Input
1795
+ }], labelPosition: [{
1796
+ type: Input
1797
+ }], color: [{
1798
+ type: Input
1799
+ }], layout: [{
1800
+ type: Input
1801
+ }], labels: [{
1802
+ type: Input
1803
+ }], gap: [{
1804
+ type: Input
1805
+ }], labelColor: [{
1806
+ type: Input
1807
+ }], checkedColor: [{
1808
+ type: Input
1809
+ }], uncheckedColor: [{
1810
+ type: Input
1811
+ }], fontSize: [{
1812
+ type: Input
1813
+ }], fontWeight: [{
1814
+ type: Input
1815
+ }], fontFamily: [{
1816
+ type: Input
1817
+ }], groupLabelColor: [{
1818
+ type: Input
1819
+ }], groupLabelFontSize: [{
1820
+ type: Input
1821
+ }], groupLabelFontWeight: [{
1822
+ type: Input
1823
+ }], disabledColor: [{
1824
+ type: Input
1825
+ }], errorColor: [{
1826
+ type: Input
1827
+ }], size: [{
1828
+ type: Input
1829
+ }], borderRadius: [{
1830
+ type: Input
1831
+ }], labelFontSize: [{
1832
+ type: Input
1833
+ }], labelFontWeight: [{
1834
+ type: Input
1835
+ }], selectionChange: [{
1836
+ type: Output
1837
+ }] } });
1838
+
1839
+ class ToggleComponent {
1840
+ config;
1841
+ labels;
1842
+ label = '';
1843
+ checked = false;
1844
+ disabled = false;
1845
+ required = false;
1846
+ labelPosition = 'after';
1847
+ color = '#1A73E8';
1848
+ // Customization — Colors
1849
+ labelColor;
1850
+ uncheckedColor;
1851
+ checkedColor;
1852
+ thumbColor;
1853
+ checkedThumbColor;
1854
+ // Customization — Typography
1855
+ fontSize;
1856
+ fontWeight;
1857
+ fontFamily;
1858
+ // Customization — Size
1859
+ toggleWidth;
1860
+ toggleHeight;
1861
+ gap;
1862
+ // Customization — Slider
1863
+ sliderColor;
1864
+ // Customization — Label
1865
+ labelFontSize;
1866
+ labelFontWeight;
1867
+ // Customization — States
1868
+ disabledColor;
1869
+ toggleChange = new EventEmitter();
1870
+ value = false;
1871
+ onChange = () => { };
1872
+ onTouched = () => { };
1873
+ ngOnInit() {
1874
+ this.updateFromConfig();
1875
+ this.updateFromLabels();
1876
+ this.value = this.checked;
1877
+ }
1878
+ ngOnChanges(changes) {
1879
+ if (changes['config']) {
1880
+ this.updateFromConfig();
1881
+ }
1882
+ if (changes['labels']) {
1883
+ this.updateFromLabels();
1884
+ }
1885
+ if (changes['checked']) {
1886
+ this.value = this.checked;
1887
+ }
1888
+ }
1889
+ updateFromConfig() {
1890
+ if (this.config) {
1891
+ this.label = this.config.label ?? this.label;
1892
+ this.checked = this.config.checked ?? this.checked;
1893
+ this.disabled = this.config.disabled ?? this.disabled;
1894
+ this.required = this.config.required ?? this.required;
1895
+ this.labelPosition = this.config.labelPosition ?? this.labelPosition;
1896
+ this.color = this.config.color ?? this.color;
1897
+ this.uncheckedColor = this.config.uncheckedColor ?? this.uncheckedColor;
1898
+ this.checkedColor = this.config.checkedColor ?? this.checkedColor;
1899
+ this.thumbColor = this.config.thumbColor ?? this.thumbColor;
1900
+ this.checkedThumbColor = this.config.checkedThumbColor ?? this.checkedThumbColor;
1901
+ this.fontSize = this.config.fontSize ?? this.fontSize;
1902
+ this.fontWeight = this.config.fontWeight ?? this.fontWeight;
1903
+ this.toggleWidth = this.config.toggleWidth ?? this.toggleWidth;
1904
+ this.toggleHeight = this.config.toggleHeight ?? this.toggleHeight;
1905
+ this.gap = this.config.gap ?? this.gap;
1906
+ this.fontFamily = this.config.fontFamily ?? this.fontFamily;
1907
+ this.labelColor = this.config.labelColor ?? this.labelColor;
1908
+ this.labelFontSize = this.config.labelFontSize ?? this.labelFontSize;
1909
+ this.labelFontWeight = this.config.labelFontWeight ?? this.labelFontWeight;
1910
+ }
1911
+ }
1912
+ updateFromLabels() {
1913
+ if (this.labels) {
1914
+ this.label = this.labels.label || this.label;
1915
+ }
1916
+ }
1917
+ writeValue(value) {
1918
+ this.value = !!value;
1919
+ this.checked = this.value;
1920
+ }
1921
+ registerOnChange(fn) {
1922
+ this.onChange = fn;
1923
+ }
1924
+ registerOnTouched(fn) {
1925
+ this.onTouched = fn;
1926
+ }
1927
+ setDisabledState(isDisabled) {
1928
+ this.disabled = isDisabled;
1929
+ }
1930
+ onToggleChange(event) {
1931
+ this.value = event.target.checked;
1932
+ this.checked = this.value;
1933
+ this.onChange(this.value);
1934
+ this.onTouched();
1935
+ this.toggleChange.emit(this.value);
1936
+ }
1937
+ getStyleValue(value) {
1938
+ return value ? `${value}` : undefined;
1939
+ }
1940
+ get wrapperStyles() {
1941
+ return {
1942
+ '--cc-toggle-font-family': this.getStyleValue(this.fontFamily),
1943
+ '--cc-toggle-font-size': this.getStyleValue(this.fontSize || this.labelFontSize),
1944
+ '--cc-toggle-font-weight': this.getStyleValue(this.fontWeight || this.labelFontWeight),
1945
+ '--cc-toggle-label-color': this.getStyleValue(this.labelColor),
1946
+ '--cc-toggle-width': this.getStyleValue(this.toggleWidth),
1947
+ '--cc-toggle-height': this.getStyleValue(this.toggleHeight),
1948
+ '--cc-toggle-gap': this.getStyleValue(this.gap),
1949
+ '--cc-toggle-unchecked-bg': this.getStyleValue(this.uncheckedColor),
1950
+ '--cc-toggle-checked-bg': this.getStyleValue(this.checkedColor || this.color),
1951
+ '--cc-toggle-thumb-color': this.getStyleValue(this.thumbColor || this.sliderColor),
1952
+ '--cc-toggle-checked-thumb-color': this.getStyleValue(this.checkedThumbColor),
1953
+ '--cc-toggle-disabled-color': this.getStyleValue(this.disabledColor)
1954
+ };
1955
+ }
1956
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ToggleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1957
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ToggleComponent, isStandalone: false, selector: "lib-toggle", inputs: { config: "config", labels: "labels", label: "label", checked: "checked", disabled: "disabled", required: "required", labelPosition: "labelPosition", color: "color", labelColor: "labelColor", uncheckedColor: "uncheckedColor", checkedColor: "checkedColor", thumbColor: "thumbColor", checkedThumbColor: "checkedThumbColor", fontSize: "fontSize", fontWeight: "fontWeight", fontFamily: "fontFamily", toggleWidth: "toggleWidth", toggleHeight: "toggleHeight", gap: "gap", sliderColor: "sliderColor", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight", disabledColor: "disabledColor" }, outputs: { toggleChange: "toggleChange" }, providers: [
1958
+ {
1959
+ provide: NG_VALUE_ACCESSOR,
1960
+ useExisting: forwardRef(() => ToggleComponent),
1961
+ multi: true
1962
+ }
1963
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-toggle-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n <label class=\"cc-toggle-label\" [class.label-before]=\"labelPosition === 'before'\" [class.disabled]=\"disabled\">\r\n\r\n <span class=\"cc-label-text\" *ngIf=\"label && labelPosition === 'before'\">{{ label }}</span>\r\n\r\n <span class=\"cc-toggle-switch\">\r\n <input type=\"checkbox\" class=\"cc-native-toggle\" [checked]=\"checked\" [disabled]=\"disabled\"\r\n (change)=\"onToggleChange($event)\" />\r\n <span class=\"cc-toggle-track\"></span>\r\n <span class=\"cc-toggle-thumb\"></span>\r\n </span>\r\n\r\n <span class=\"cc-label-text\" *ngIf=\"label && labelPosition === 'after'\">{{ label }}</span>\r\n </label>\r\n</div>", styles: [".cc-toggle-wrapper{display:flex;flex-direction:column;font-family:var(--cc-toggle-font-family, inherit)}.cc-toggle-label{display:inline-flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;font-size:var(--cc-toggle-font-size, .875rem);font-weight:var(--cc-toggle-font-weight, 400);color:var(--cc-toggle-label-color, #202124);gap:.5rem}.cc-toggle-label.disabled{cursor:not-allowed;color:var(--cc-toggle-disabled-color, #80868B)}.cc-toggle-label.disabled .cc-toggle-track{background-color:var(--cc-toggle-disabled-color, #E0E0E0);opacity:.5}.cc-toggle-label.disabled .cc-toggle-thumb{background-color:#bdbdbd}.cc-toggle-switch{position:relative;width:var(--cc-toggle-width, 2.25rem);height:var(--cc-toggle-height, 1.25rem)}.cc-native-toggle{position:absolute;opacity:0;width:0;height:0}.cc-native-toggle:checked~.cc-toggle-track{background-color:var(--cc-toggle-checked-bg, #1A73E8)}.cc-native-toggle:checked~.cc-toggle-thumb{left:calc(100% - var(--cc-toggle-height, 1.25rem) + 2px);background-color:var(--cc-toggle-checked-thumb-color, #FEFEFE)}.cc-toggle-track{position:absolute;inset:0;background-color:var(--cc-toggle-unchecked-bg, #BDC1C6);border-radius:1rem;transition:.2s}.cc-toggle-thumb{position:absolute;top:50%;left:2px;width:calc(var(--cc-toggle-height, 1.25rem) - 4px);height:calc(var(--cc-toggle-height, 1.25rem) - 4px);transform:translateY(-50%);background-color:var(--cc-toggle-thumb-color, #FEFEFE);border-radius:50%;transition:.2s;box-shadow:0 1px 3px #0003}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1964
+ }
1965
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ToggleComponent, decorators: [{
1966
+ type: Component,
1967
+ args: [{ selector: 'lib-toggle', standalone: false, providers: [
1968
+ {
1969
+ provide: NG_VALUE_ACCESSOR,
1970
+ useExisting: forwardRef(() => ToggleComponent),
1971
+ multi: true
1972
+ }
1973
+ ], template: "<div class=\"cc-toggle-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n <label class=\"cc-toggle-label\" [class.label-before]=\"labelPosition === 'before'\" [class.disabled]=\"disabled\">\r\n\r\n <span class=\"cc-label-text\" *ngIf=\"label && labelPosition === 'before'\">{{ label }}</span>\r\n\r\n <span class=\"cc-toggle-switch\">\r\n <input type=\"checkbox\" class=\"cc-native-toggle\" [checked]=\"checked\" [disabled]=\"disabled\"\r\n (change)=\"onToggleChange($event)\" />\r\n <span class=\"cc-toggle-track\"></span>\r\n <span class=\"cc-toggle-thumb\"></span>\r\n </span>\r\n\r\n <span class=\"cc-label-text\" *ngIf=\"label && labelPosition === 'after'\">{{ label }}</span>\r\n </label>\r\n</div>", styles: [".cc-toggle-wrapper{display:flex;flex-direction:column;font-family:var(--cc-toggle-font-family, inherit)}.cc-toggle-label{display:inline-flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;font-size:var(--cc-toggle-font-size, .875rem);font-weight:var(--cc-toggle-font-weight, 400);color:var(--cc-toggle-label-color, #202124);gap:.5rem}.cc-toggle-label.disabled{cursor:not-allowed;color:var(--cc-toggle-disabled-color, #80868B)}.cc-toggle-label.disabled .cc-toggle-track{background-color:var(--cc-toggle-disabled-color, #E0E0E0);opacity:.5}.cc-toggle-label.disabled .cc-toggle-thumb{background-color:#bdbdbd}.cc-toggle-switch{position:relative;width:var(--cc-toggle-width, 2.25rem);height:var(--cc-toggle-height, 1.25rem)}.cc-native-toggle{position:absolute;opacity:0;width:0;height:0}.cc-native-toggle:checked~.cc-toggle-track{background-color:var(--cc-toggle-checked-bg, #1A73E8)}.cc-native-toggle:checked~.cc-toggle-thumb{left:calc(100% - var(--cc-toggle-height, 1.25rem) + 2px);background-color:var(--cc-toggle-checked-thumb-color, #FEFEFE)}.cc-toggle-track{position:absolute;inset:0;background-color:var(--cc-toggle-unchecked-bg, #BDC1C6);border-radius:1rem;transition:.2s}.cc-toggle-thumb{position:absolute;top:50%;left:2px;width:calc(var(--cc-toggle-height, 1.25rem) - 4px);height:calc(var(--cc-toggle-height, 1.25rem) - 4px);transform:translateY(-50%);background-color:var(--cc-toggle-thumb-color, #FEFEFE);border-radius:50%;transition:.2s;box-shadow:0 1px 3px #0003}\n"] }]
1974
+ }], propDecorators: { config: [{
1975
+ type: Input
1976
+ }], labels: [{
1977
+ type: Input
1978
+ }], label: [{
1979
+ type: Input
1980
+ }], checked: [{
1981
+ type: Input
1982
+ }], disabled: [{
1983
+ type: Input
1984
+ }], required: [{
1985
+ type: Input
1986
+ }], labelPosition: [{
1987
+ type: Input
1988
+ }], color: [{
1989
+ type: Input
1990
+ }], labelColor: [{
1991
+ type: Input
1992
+ }], uncheckedColor: [{
1993
+ type: Input
1994
+ }], checkedColor: [{
1995
+ type: Input
1996
+ }], thumbColor: [{
1997
+ type: Input
1998
+ }], checkedThumbColor: [{
1999
+ type: Input
2000
+ }], fontSize: [{
2001
+ type: Input
2002
+ }], fontWeight: [{
2003
+ type: Input
2004
+ }], fontFamily: [{
2005
+ type: Input
2006
+ }], toggleWidth: [{
2007
+ type: Input
2008
+ }], toggleHeight: [{
2009
+ type: Input
2010
+ }], gap: [{
2011
+ type: Input
2012
+ }], sliderColor: [{
2013
+ type: Input
2014
+ }], labelFontSize: [{
2015
+ type: Input
2016
+ }], labelFontWeight: [{
2017
+ type: Input
2018
+ }], disabledColor: [{
2019
+ type: Input
2020
+ }], toggleChange: [{
2021
+ type: Output
2022
+ }] } });
2023
+
2024
+ class DatepickerComponent {
2025
+ config;
2026
+ labels;
2027
+ label = '';
2028
+ placeholder = '';
2029
+ disabled = false;
2030
+ required = false;
2031
+ minDate; // Support string for native input
2032
+ maxDate; // Support string for native input
2033
+ isRange = false;
2034
+ startView = 'month';
2035
+ value = null;
2036
+ startDate;
2037
+ endDate;
2038
+ errorMessage = '';
2039
+ // Style inputs
2040
+ width;
2041
+ height;
2042
+ borderRadius;
2043
+ fontSize;
2044
+ gap;
2045
+ fontFamily;
2046
+ labelColor;
2047
+ labelFontSize;
2048
+ labelFontWeight;
2049
+ backgroundColor;
2050
+ borderColor;
2051
+ borderWidth;
2052
+ padding;
2053
+ fontWeight;
2054
+ color;
2055
+ placeholderColor;
2056
+ focusBorderColor;
2057
+ errorColor;
2058
+ disabledBackgroundColor;
2059
+ disabledColor;
2060
+ boxShadow;
2061
+ dateChange = new EventEmitter();
2062
+ onChange = () => { };
2063
+ onTouched = () => { };
2064
+ focused = false;
2065
+ ngOnInit() {
2066
+ this.updateFromConfig();
2067
+ this.updateFromLabels();
2068
+ }
2069
+ ngOnChanges(changes) {
2070
+ if (changes['config']) {
2071
+ this.updateFromConfig();
2072
+ }
2073
+ if (changes['labels']) {
2074
+ this.updateFromLabels();
2075
+ }
2076
+ }
2077
+ updateFromConfig() {
2078
+ if (this.config) {
2079
+ this.label = this.config.label ?? this.label;
2080
+ this.placeholder = this.config.placeholder ?? this.placeholder;
2081
+ this.disabled = this.config.disabled ?? this.disabled;
2082
+ this.required = this.config.required ?? this.required;
2083
+ this.minDate = this.config.minDate ?? this.minDate;
2084
+ this.maxDate = this.config.maxDate ?? this.maxDate;
2085
+ this.isRange = this.config.isRange ?? this.isRange;
2086
+ this.width = this.config.width ?? this.width;
2087
+ this.borderRadius = this.config.borderRadius ?? this.borderRadius;
2088
+ this.fontSize = this.config.fontSize ?? this.fontSize;
2089
+ this.errorMessage = this.config.errorMessage ?? this.errorMessage;
2090
+ this.gap = this.config.gap ?? this.gap;
2091
+ this.fontFamily = this.config.fontFamily ?? this.fontFamily;
2092
+ this.labelColor = this.config.labelColor ?? this.labelColor;
2093
+ this.labelFontSize = this.config.labelFontSize ?? this.labelFontSize;
2094
+ this.labelFontWeight = this.config.labelFontWeight ?? this.labelFontWeight;
2095
+ this.backgroundColor = this.config.backgroundColor ?? this.backgroundColor;
2096
+ this.borderColor = this.config.borderColor ?? this.borderColor;
2097
+ this.borderWidth = this.config.borderWidth ?? this.borderWidth;
2098
+ this.padding = this.config.padding ?? this.padding;
2099
+ this.fontWeight = this.config.fontWeight ?? this.fontWeight;
2100
+ this.color = this.config.color ?? this.color;
2101
+ this.placeholderColor = this.config.placeholderColor ?? this.placeholderColor;
2102
+ this.focusBorderColor = this.config.focusBorderColor ?? this.focusBorderColor;
2103
+ this.errorColor = this.config.errorColor ?? this.errorColor;
2104
+ this.disabledBackgroundColor = this.config.disabledBackgroundColor ?? this.disabledBackgroundColor;
2105
+ this.disabledColor = this.config.disabledColor ?? this.disabledColor;
2106
+ this.boxShadow = this.config.boxShadow ?? this.boxShadow;
2107
+ this.height = this.config.height ?? this.height;
2108
+ if (this.config.value !== undefined) {
2109
+ this.value = this.config.value;
2110
+ }
2111
+ if (this.config.startDate) {
2112
+ this.startDate = this.config.startDate;
2113
+ }
2114
+ if (this.config.endDate) {
2115
+ this.endDate = this.config.endDate;
2116
+ }
2117
+ }
2118
+ }
2119
+ updateFromLabels() {
2120
+ if (this.labels) {
2121
+ this.label = this.labels.label || this.label;
2122
+ this.placeholder = this.labels.placeholder || this.placeholder;
2123
+ }
2124
+ }
2125
+ get requiredMarker() {
2126
+ return this.labels?.requiredMarker || '*';
2127
+ }
2128
+ get startDateLabel() {
2129
+ return this.labels?.startDateLabel || 'Start Date';
2130
+ }
2131
+ get endDateLabel() {
2132
+ return this.labels?.endDateLabel || 'End Date';
2133
+ }
2134
+ // Helper to format Date or string to YYYY-MM-DD for native input
2135
+ formatDate(date) {
2136
+ if (!date)
2137
+ return '';
2138
+ if (typeof date === 'string')
2139
+ return date; // Assume already formatted or ISO
2140
+ try {
2141
+ return date.toISOString().split('T')[0];
2142
+ }
2143
+ catch (e) {
2144
+ return '';
2145
+ }
2146
+ }
2147
+ get formattedValue() {
2148
+ return this.formatDate(this.value);
2149
+ }
2150
+ get formattedStartDate() {
2151
+ return this.formatDate(this.startDate);
2152
+ }
2153
+ get formattedEndDate() {
2154
+ return this.formatDate(this.endDate);
2155
+ }
2156
+ get formattedMin() {
2157
+ return this.formatDate(this.minDate);
2158
+ }
2159
+ get formattedMax() {
2160
+ return this.formatDate(this.maxDate);
2161
+ }
2162
+ writeValue(value) {
2163
+ if (this.isRange && value && typeof value === 'object' && 'start' in value) {
2164
+ this.startDate = value.start;
2165
+ this.endDate = value.end;
2166
+ }
2167
+ else {
2168
+ this.value = value;
2169
+ }
2170
+ }
2171
+ registerOnChange(fn) {
2172
+ this.onChange = fn;
2173
+ }
2174
+ registerOnTouched(fn) {
2175
+ this.onTouched = fn;
2176
+ }
2177
+ setDisabledState(isDisabled) {
2178
+ this.disabled = isDisabled;
2179
+ }
2180
+ onDateInput(event) {
2181
+ const value = event.target.value;
2182
+ this.value = value; // Keep as string or convert if needed
2183
+ this.onChange(this.value);
2184
+ this.dateChange.emit(this.value);
2185
+ }
2186
+ onBlur() {
2187
+ this.focused = false;
2188
+ this.onTouched();
2189
+ }
2190
+ onFocus() {
2191
+ this.focused = true;
2192
+ }
2193
+ onRangeStartInput(event) {
2194
+ this.startDate = event.target.value;
2195
+ this.updateRangeValue();
2196
+ }
2197
+ onRangeEndInput(event) {
2198
+ this.endDate = event.target.value;
2199
+ this.updateRangeValue();
2200
+ }
2201
+ updateRangeValue() {
2202
+ const rangeValue = { start: this.startDate, end: this.endDate };
2203
+ this.onChange(rangeValue);
2204
+ this.dateChange.emit(rangeValue);
2205
+ }
2206
+ getStyleValue(value) {
2207
+ return value ? `${value}` : undefined;
2208
+ }
2209
+ get wrapperStyles() {
2210
+ return {
2211
+ 'width': this.getStyleValue(this.width),
2212
+ '--cc-datepicker-label-gap': this.getStyleValue(this.gap),
2213
+ '--cc-datepicker-font-family': this.getStyleValue(this.fontFamily)
2214
+ };
2215
+ }
2216
+ get labelStyles() {
2217
+ return {
2218
+ '--cc-datepicker-label-color': this.getStyleValue(this.labelColor),
2219
+ '--cc-datepicker-label-font-size': this.getStyleValue(this.labelFontSize),
2220
+ '--cc-datepicker-label-font-weight': this.getStyleValue(this.labelFontWeight)
2221
+ };
2222
+ }
2223
+ get fieldStyles() {
2224
+ return {
2225
+ '--cc-datepicker-bg': this.getStyleValue(this.backgroundColor),
2226
+ '--cc-datepicker-border-radius': this.getStyleValue(this.borderRadius),
2227
+ '--cc-datepicker-border-color': this.getStyleValue(this.borderColor),
2228
+ '--cc-datepicker-border-width': this.getStyleValue(this.borderWidth),
2229
+ '--cc-datepicker-height': this.getStyleValue(this.height),
2230
+ '--cc-datepicker-padding': this.getStyleValue(this.padding),
2231
+ '--cc-datepicker-font-size': this.getStyleValue(this.fontSize),
2232
+ '--cc-datepicker-font-weight': this.getStyleValue(this.fontWeight),
2233
+ '--cc-datepicker-color': this.getStyleValue(this.color),
2234
+ '--cc-datepicker-placeholder-color': this.getStyleValue(this.placeholderColor),
2235
+ '--cc-datepicker-focus-border-color': this.getStyleValue(this.focusBorderColor),
2236
+ '--cc-datepicker-error-color': this.getStyleValue(this.errorColor),
2237
+ '--cc-datepicker-disabled-bg': this.getStyleValue(this.disabledBackgroundColor),
2238
+ '--cc-datepicker-disabled-color': this.getStyleValue(this.disabledColor),
2239
+ 'box-shadow': this.getStyleValue(this.boxShadow)
2240
+ };
2241
+ }
2242
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DatepickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2243
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DatepickerComponent, isStandalone: false, selector: "lib-datepicker", inputs: { config: "config", labels: "labels", label: "label", placeholder: "placeholder", disabled: "disabled", required: "required", minDate: "minDate", maxDate: "maxDate", isRange: "isRange", startView: "startView", value: "value", startDate: "startDate", endDate: "endDate", errorMessage: "errorMessage", width: "width", height: "height", borderRadius: "borderRadius", fontSize: "fontSize", gap: "gap", fontFamily: "fontFamily", labelColor: "labelColor", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight", backgroundColor: "backgroundColor", borderColor: "borderColor", borderWidth: "borderWidth", padding: "padding", fontWeight: "fontWeight", color: "color", placeholderColor: "placeholderColor", focusBorderColor: "focusBorderColor", errorColor: "errorColor", disabledBackgroundColor: "disabledBackgroundColor", disabledColor: "disabledColor", boxShadow: "boxShadow" }, outputs: { dateChange: "dateChange" }, providers: [
2244
+ {
2245
+ provide: NG_VALUE_ACCESSOR,
2246
+ useExisting: forwardRef(() => DatepickerComponent),
2247
+ multi: true
2248
+ }
2249
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-datepicker-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n <label *ngIf=\"label\" class=\"cc-datepicker-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <!-- Single Date Picker -->\r\n <div *ngIf=\"!isRange\" class=\"cc-datepicker-field\" [class.focused]=\"focused\" [class.disabled]=\"disabled\"\r\n [class.error]=\"errorMessage\" [ngStyle]=\"fieldStyles\">\r\n\r\n <input type=\"date\" class=\"cc-datepicker-input\" #dateInput [value]=\"formattedValue\" [disabled]=\"disabled\"\r\n [required]=\"required\" [min]=\"formattedMin\" [max]=\"formattedMax\" [placeholder]=\"placeholder\"\r\n (input)=\"onDateInput($event)\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" (click)=\"dateInput.showPicker()\" />\r\n\r\n <span class=\"cc-datepicker-icon material-icons\" (click)=\"dateInput.showPicker()\">calendar_today</span>\r\n </div>\r\n\r\n <!-- Range Date Picker -->\r\n <div *ngIf=\"isRange\" class=\"cc-datepicker-range\">\r\n <!-- Start Date -->\r\n <div class=\"cc-datepicker-subfield\">\r\n <label class=\"cc-datepicker-sublabel\">{{ startDateLabel }}</label>\r\n <div class=\"cc-datepicker-field\" [class.disabled]=\"disabled\" [ngStyle]=\"fieldStyles\">\r\n <input type=\"date\" class=\"cc-datepicker-input\" [value]=\"formattedStartDate\" [disabled]=\"disabled\"\r\n [required]=\"required\" [min]=\"formattedMin\" [max]=\"formattedEndDate || formattedMax\"\r\n (input)=\"onRangeStartInput($event)\" />\r\n </div>\r\n </div>\r\n\r\n <!-- End Date -->\r\n <div class=\"cc-datepicker-subfield\">\r\n <label class=\"cc-datepicker-sublabel\">{{ endDateLabel }}</label>\r\n <div class=\"cc-datepicker-field\" [class.disabled]=\"disabled\" [ngStyle]=\"fieldStyles\">\r\n <input type=\"date\" class=\"cc-datepicker-input\" [value]=\"formattedEndDate\" [disabled]=\"disabled\"\r\n [required]=\"required\" [min]=\"formattedStartDate || formattedMin\" [max]=\"formattedMax\"\r\n (input)=\"onRangeEndInput($event)\" />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-datepicker-wrapper{display:flex;flex-direction:column;gap:var(--cc-datepicker-label-gap, .5rem);width:100%;font-family:var(--cc-datepicker-font-family, inherit)}.cc-datepicker-label{font-size:var(--cc-datepicker-label-font-size, .875rem);font-weight:var(--cc-datepicker-label-font-weight, 500);color:var(--cc-datepicker-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-datepicker-required-color, #D93025);margin-left:.25rem}.cc-datepicker-field{display:flex;align-items:center;width:100%;box-sizing:border-box;background-color:var(--cc-datepicker-bg, #FEFEFE);border:var(--cc-datepicker-border-width, 1px) solid var(--cc-datepicker-border-color, #BDC1C6);border-radius:var(--cc-datepicker-border-radius, .4375rem);padding:var(--cc-datepicker-padding, .5rem .75rem);min-height:var(--cc-datepicker-height, 2.5rem);transition:border-color .2s,box-shadow .2s;position:relative}.cc-datepicker-field.focused{border-color:var(--cc-datepicker-focus-border-color, #1A73E8)}.cc-datepicker-field.error{border-color:var(--cc-datepicker-error-color, #D93025)}.cc-datepicker-field.disabled{background-color:var(--cc-datepicker-disabled-bg, #F1F3F4);cursor:not-allowed}.cc-datepicker-field.disabled .cc-datepicker-input{cursor:not-allowed;color:var(--cc-datepicker-disabled-color, #80868B)}.cc-datepicker-field.disabled .cc-datepicker-icon{color:var(--cc-datepicker-disabled-color, #80868B)}.cc-datepicker-input{flex:1;border:none;background:transparent;outline:none;font-family:inherit;font-size:var(--cc-datepicker-font-size, .875rem);font-weight:var(--cc-datepicker-font-weight, 400);color:var(--cc-datepicker-color, #202124);padding:0;margin:0;width:100%;opacity:1}.cc-datepicker-input::-webkit-calendar-picker-indicator{opacity:0;position:absolute;right:0;top:0;bottom:0;width:2.5rem;height:100%;cursor:pointer;z-index:10}.cc-datepicker-icon{margin-left:.5rem;color:var(--cc-datepicker-icon-color, #5F6368);pointer-events:none}.cc-datepicker-range{display:flex;gap:1rem;align-items:flex-start}.cc-datepicker-range .cc-datepicker-subfield{flex:1;display:flex;flex-direction:column;gap:.25rem}.cc-datepicker-range .cc-datepicker-sublabel{font-size:.75rem;color:#5f6368}.cc-error-message{font-size:.75rem;color:var(--cc-datepicker-error-color, #D93025);margin-top:.25rem}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
2250
+ }
2251
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DatepickerComponent, decorators: [{
2252
+ type: Component,
2253
+ args: [{ selector: 'lib-datepicker', standalone: false, providers: [
2254
+ {
2255
+ provide: NG_VALUE_ACCESSOR,
2256
+ useExisting: forwardRef(() => DatepickerComponent),
2257
+ multi: true
2258
+ }
2259
+ ], template: "<div class=\"cc-datepicker-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n <label *ngIf=\"label\" class=\"cc-datepicker-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ requiredMarker }}</span>\r\n </label>\r\n\r\n <!-- Single Date Picker -->\r\n <div *ngIf=\"!isRange\" class=\"cc-datepicker-field\" [class.focused]=\"focused\" [class.disabled]=\"disabled\"\r\n [class.error]=\"errorMessage\" [ngStyle]=\"fieldStyles\">\r\n\r\n <input type=\"date\" class=\"cc-datepicker-input\" #dateInput [value]=\"formattedValue\" [disabled]=\"disabled\"\r\n [required]=\"required\" [min]=\"formattedMin\" [max]=\"formattedMax\" [placeholder]=\"placeholder\"\r\n (input)=\"onDateInput($event)\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" (click)=\"dateInput.showPicker()\" />\r\n\r\n <span class=\"cc-datepicker-icon material-icons\" (click)=\"dateInput.showPicker()\">calendar_today</span>\r\n </div>\r\n\r\n <!-- Range Date Picker -->\r\n <div *ngIf=\"isRange\" class=\"cc-datepicker-range\">\r\n <!-- Start Date -->\r\n <div class=\"cc-datepicker-subfield\">\r\n <label class=\"cc-datepicker-sublabel\">{{ startDateLabel }}</label>\r\n <div class=\"cc-datepicker-field\" [class.disabled]=\"disabled\" [ngStyle]=\"fieldStyles\">\r\n <input type=\"date\" class=\"cc-datepicker-input\" [value]=\"formattedStartDate\" [disabled]=\"disabled\"\r\n [required]=\"required\" [min]=\"formattedMin\" [max]=\"formattedEndDate || formattedMax\"\r\n (input)=\"onRangeStartInput($event)\" />\r\n </div>\r\n </div>\r\n\r\n <!-- End Date -->\r\n <div class=\"cc-datepicker-subfield\">\r\n <label class=\"cc-datepicker-sublabel\">{{ endDateLabel }}</label>\r\n <div class=\"cc-datepicker-field\" [class.disabled]=\"disabled\" [ngStyle]=\"fieldStyles\">\r\n <input type=\"date\" class=\"cc-datepicker-input\" [value]=\"formattedEndDate\" [disabled]=\"disabled\"\r\n [required]=\"required\" [min]=\"formattedStartDate || formattedMin\" [max]=\"formattedMax\"\r\n (input)=\"onRangeEndInput($event)\" />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-datepicker-wrapper{display:flex;flex-direction:column;gap:var(--cc-datepicker-label-gap, .5rem);width:100%;font-family:var(--cc-datepicker-font-family, inherit)}.cc-datepicker-label{font-size:var(--cc-datepicker-label-font-size, .875rem);font-weight:var(--cc-datepicker-label-font-weight, 500);color:var(--cc-datepicker-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-datepicker-required-color, #D93025);margin-left:.25rem}.cc-datepicker-field{display:flex;align-items:center;width:100%;box-sizing:border-box;background-color:var(--cc-datepicker-bg, #FEFEFE);border:var(--cc-datepicker-border-width, 1px) solid var(--cc-datepicker-border-color, #BDC1C6);border-radius:var(--cc-datepicker-border-radius, .4375rem);padding:var(--cc-datepicker-padding, .5rem .75rem);min-height:var(--cc-datepicker-height, 2.5rem);transition:border-color .2s,box-shadow .2s;position:relative}.cc-datepicker-field.focused{border-color:var(--cc-datepicker-focus-border-color, #1A73E8)}.cc-datepicker-field.error{border-color:var(--cc-datepicker-error-color, #D93025)}.cc-datepicker-field.disabled{background-color:var(--cc-datepicker-disabled-bg, #F1F3F4);cursor:not-allowed}.cc-datepicker-field.disabled .cc-datepicker-input{cursor:not-allowed;color:var(--cc-datepicker-disabled-color, #80868B)}.cc-datepicker-field.disabled .cc-datepicker-icon{color:var(--cc-datepicker-disabled-color, #80868B)}.cc-datepicker-input{flex:1;border:none;background:transparent;outline:none;font-family:inherit;font-size:var(--cc-datepicker-font-size, .875rem);font-weight:var(--cc-datepicker-font-weight, 400);color:var(--cc-datepicker-color, #202124);padding:0;margin:0;width:100%;opacity:1}.cc-datepicker-input::-webkit-calendar-picker-indicator{opacity:0;position:absolute;right:0;top:0;bottom:0;width:2.5rem;height:100%;cursor:pointer;z-index:10}.cc-datepicker-icon{margin-left:.5rem;color:var(--cc-datepicker-icon-color, #5F6368);pointer-events:none}.cc-datepicker-range{display:flex;gap:1rem;align-items:flex-start}.cc-datepicker-range .cc-datepicker-subfield{flex:1;display:flex;flex-direction:column;gap:.25rem}.cc-datepicker-range .cc-datepicker-sublabel{font-size:.75rem;color:#5f6368}.cc-error-message{font-size:.75rem;color:var(--cc-datepicker-error-color, #D93025);margin-top:.25rem}\n"] }]
2260
+ }], propDecorators: { config: [{
2261
+ type: Input
2262
+ }], labels: [{
2263
+ type: Input
2264
+ }], label: [{
2265
+ type: Input
2266
+ }], placeholder: [{
2267
+ type: Input
2268
+ }], disabled: [{
2269
+ type: Input
2270
+ }], required: [{
2271
+ type: Input
2272
+ }], minDate: [{
2273
+ type: Input
2274
+ }], maxDate: [{
2275
+ type: Input
2276
+ }], isRange: [{
2277
+ type: Input
2278
+ }], startView: [{
2279
+ type: Input
2280
+ }], value: [{
2281
+ type: Input
2282
+ }], startDate: [{
2283
+ type: Input
2284
+ }], endDate: [{
2285
+ type: Input
2286
+ }], errorMessage: [{
2287
+ type: Input
2288
+ }], width: [{
2289
+ type: Input
2290
+ }], height: [{
2291
+ type: Input
2292
+ }], borderRadius: [{
2293
+ type: Input
2294
+ }], fontSize: [{
2295
+ type: Input
2296
+ }], gap: [{
2297
+ type: Input
2298
+ }], fontFamily: [{
2299
+ type: Input
2300
+ }], labelColor: [{
2301
+ type: Input
2302
+ }], labelFontSize: [{
2303
+ type: Input
2304
+ }], labelFontWeight: [{
2305
+ type: Input
2306
+ }], backgroundColor: [{
2307
+ type: Input
2308
+ }], borderColor: [{
2309
+ type: Input
2310
+ }], borderWidth: [{
2311
+ type: Input
2312
+ }], padding: [{
2313
+ type: Input
2314
+ }], fontWeight: [{
2315
+ type: Input
2316
+ }], color: [{
2317
+ type: Input
2318
+ }], placeholderColor: [{
2319
+ type: Input
2320
+ }], focusBorderColor: [{
2321
+ type: Input
2322
+ }], errorColor: [{
2323
+ type: Input
2324
+ }], disabledBackgroundColor: [{
2325
+ type: Input
2326
+ }], disabledColor: [{
2327
+ type: Input
2328
+ }], boxShadow: [{
2329
+ type: Input
2330
+ }], dateChange: [{
2331
+ type: Output
2332
+ }] } });
2333
+
2334
+ class SearchComponent {
2335
+ config;
2336
+ labels;
2337
+ placeholder = '';
2338
+ label = '';
2339
+ disabled = false;
2340
+ debounceMs = 300;
2341
+ clearable = true;
2342
+ value = '';
2343
+ // Style inputs
2344
+ width;
2345
+ height;
2346
+ borderRadius;
2347
+ fontSize;
2348
+ gap;
2349
+ fontFamily;
2350
+ labelColor;
2351
+ labelFontSize;
2352
+ labelFontWeight;
2353
+ backgroundColor;
2354
+ borderColor;
2355
+ borderWidth;
2356
+ border; // Shorthand
2357
+ padding;
2358
+ fontWeight;
2359
+ color;
2360
+ textColor; // Alias for color or specific text color
2361
+ iconColor;
2362
+ placeholderColor;
2363
+ focusBorderColor;
2364
+ disabledBackgroundColor;
2365
+ disabledColor;
2366
+ boxShadow;
2367
+ search = new EventEmitter();
2368
+ clear = new EventEmitter();
2369
+ searchSubject = new Subject();
2370
+ focused = false;
2371
+ onChange = () => { };
2372
+ onTouched = () => { };
2373
+ ngOnInit() {
2374
+ this.updateFromConfig();
2375
+ this.updateFromLabels();
2376
+ this.searchSubject.pipe(debounceTime(this.debounceMs), distinctUntilChanged()).subscribe(value => {
2377
+ this.search.emit(value);
2378
+ });
2379
+ }
2380
+ ngOnChanges(changes) {
2381
+ if (changes['config']) {
2382
+ this.updateFromConfig();
2383
+ }
2384
+ if (changes['labels']) {
2385
+ this.updateFromLabels();
2386
+ }
2387
+ }
2388
+ updateFromConfig() {
2389
+ if (this.config) {
2390
+ this.placeholder = this.config.placeholder ?? this.placeholder;
2391
+ this.label = this.config.label ?? this.label;
2392
+ this.disabled = this.config.disabled ?? this.disabled;
2393
+ this.debounceMs = this.config.debounceTime ?? this.debounceMs;
2394
+ this.clearable = this.config.clearable ?? this.clearable;
2395
+ this.width = this.config.width ?? this.width;
2396
+ this.height = this.config.height ?? this.height;
2397
+ this.borderRadius = this.config.borderRadius ?? this.borderRadius;
2398
+ this.fontSize = this.config.fontSize ?? this.fontSize;
2399
+ this.gap = this.config.gap ?? this.gap;
2400
+ this.fontFamily = this.config.fontFamily ?? this.fontFamily;
2401
+ this.labelColor = this.config.labelColor ?? this.labelColor;
2402
+ this.labelFontSize = this.config.labelFontSize ?? this.labelFontSize;
2403
+ this.labelFontWeight = this.config.labelFontWeight ?? this.labelFontWeight;
2404
+ this.backgroundColor = this.config.backgroundColor ?? this.backgroundColor;
2405
+ this.borderColor = this.config.borderColor ?? this.borderColor;
2406
+ this.borderWidth = this.config.borderWidth ?? this.borderWidth;
2407
+ this.border = this.config.border ?? this.border;
2408
+ this.padding = this.config.padding ?? this.padding;
2409
+ this.fontWeight = this.config.fontWeight ?? this.fontWeight;
2410
+ this.color = this.config.color ?? this.color;
2411
+ this.textColor = this.config.textColor ?? this.textColor;
2412
+ this.iconColor = this.config.iconColor ?? this.iconColor;
2413
+ this.placeholderColor = this.config.placeholderColor ?? this.placeholderColor;
2414
+ this.focusBorderColor = this.config.focusBorderColor ?? this.focusBorderColor;
2415
+ this.disabledBackgroundColor = this.config.disabledBackgroundColor ?? this.disabledBackgroundColor;
2416
+ this.disabledColor = this.config.disabledColor ?? this.disabledColor;
2417
+ this.boxShadow = this.config.boxShadow ?? this.boxShadow;
2418
+ if (this.config.value) {
2419
+ this.value = this.config.value;
2420
+ }
2421
+ }
2422
+ }
2423
+ updateFromLabels() {
2424
+ if (this.labels) {
2425
+ this.label = this.labels.label || this.label;
2426
+ this.placeholder = this.labels.placeholder || this.placeholder;
2427
+ }
2428
+ }
2429
+ ngOnDestroy() {
2430
+ this.searchSubject.complete();
2431
+ }
2432
+ get clearAriaLabel() {
2433
+ return this.labels?.clearAriaLabel || 'Clear search';
2434
+ }
2435
+ writeValue(value) {
2436
+ this.value = value || '';
2437
+ }
2438
+ registerOnChange(fn) {
2439
+ this.onChange = fn;
2440
+ }
2441
+ registerOnTouched(fn) {
2442
+ this.onTouched = fn;
2443
+ }
2444
+ setDisabledState(isDisabled) {
2445
+ this.disabled = isDisabled;
2446
+ }
2447
+ onInputChange(event) {
2448
+ this.value = event.target.value;
2449
+ this.onChange(this.value);
2450
+ this.searchSubject.next(this.value);
2451
+ }
2452
+ onClear() {
2453
+ this.value = '';
2454
+ this.onChange(this.value);
2455
+ this.searchSubject.next(this.value);
2456
+ this.clear.emit();
2457
+ }
2458
+ onBlur() {
2459
+ this.focused = false;
2460
+ this.onTouched();
2461
+ }
2462
+ onFocus() {
2463
+ this.focused = true;
2464
+ }
2465
+ getStyleValue(value) {
2466
+ return value ? `${value}` : undefined;
2467
+ }
2468
+ get wrapperStyles() {
2469
+ return {
2470
+ 'width': this.getStyleValue(this.width),
2471
+ '--cc-search-label-gap': this.getStyleValue(this.gap),
2472
+ '--cc-search-font-family': this.getStyleValue(this.fontFamily)
2473
+ };
2474
+ }
2475
+ get labelStyles() {
2476
+ return {
2477
+ '--cc-search-label-color': this.getStyleValue(this.labelColor),
2478
+ '--cc-search-label-font-size': this.getStyleValue(this.labelFontSize),
2479
+ '--cc-search-label-font-weight': this.getStyleValue(this.labelFontWeight)
2480
+ };
581
2481
  }
582
- getIconColor(icon) {
583
- return typeof icon === 'object' ? icon.color : undefined;
2482
+ get fieldStyles() {
2483
+ return {
2484
+ '--cc-search-bg': this.getStyleValue(this.backgroundColor),
2485
+ '--cc-search-border-radius': this.getStyleValue(this.borderRadius),
2486
+ '--cc-search-border-color': this.getStyleValue(this.borderColor),
2487
+ '--cc-search-border-width': this.getStyleValue(this.borderWidth),
2488
+ '--cc-search-border': this.getStyleValue(this.border),
2489
+ '--cc-search-height': this.getStyleValue(this.height),
2490
+ '--cc-search-padding': this.getStyleValue(this.padding),
2491
+ '--cc-search-font-size': this.getStyleValue(this.fontSize),
2492
+ '--cc-search-font-weight': this.getStyleValue(this.fontWeight),
2493
+ '--cc-search-color': this.getStyleValue(this.color || this.textColor),
2494
+ '--cc-search-icon-color': this.getStyleValue(this.iconColor),
2495
+ '--cc-search-placeholder-color': this.getStyleValue(this.placeholderColor),
2496
+ '--cc-search-focus-border-color': this.getStyleValue(this.focusBorderColor),
2497
+ '--cc-search-disabled-bg': this.getStyleValue(this.disabledBackgroundColor),
2498
+ '--cc-search-disabled-color': this.getStyleValue(this.disabledColor),
2499
+ 'box-shadow': this.getStyleValue(this.boxShadow)
2500
+ };
584
2501
  }
585
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
586
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ConfirmationModalComponent, isStandalone: false, selector: "cc-confirmation-modal", inputs: { config: "config", isOpen: "isOpen" }, outputs: { confirm: "confirm", cancel: "cancel", close: "close", showCodeSnippet: "showCodeSnippet" }, host: { listeners: { "document:keydown.escape": "handleEscape($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"isOpen\" class=\"cc-modal-backdrop\" (click)=\"onBackdropClick($event)\" role=\"dialog\" [attr.aria-modal]=\"true\"\r\n [attr.aria-labelledby]=\"'modal-title-' + mergedConfig.title\" [attr.aria-label]=\"mergedConfig.ariaLabel\"\r\n [attr.aria-describedby]=\"mergedConfig.ariaDescribedBy\">\r\n\r\n <div class=\"cc-modal-container {{ mergedConfig.customClass }}\" [style.width]=\"getModalWidth()\"\r\n [style.background-color]=\"mergedConfig.backgroundColor\" [style.border-radius]=\"mergedConfig.borderRadius\"\r\n [style.border-top-left-radius]=\"mergedConfig.borderTopLeftRadius\"\r\n [style.border-top-right-radius]=\"mergedConfig.borderTopRightRadius\"\r\n [style.border-bottom-left-radius]=\"mergedConfig.borderBottomLeftRadius\"\r\n [style.border-bottom-right-radius]=\"mergedConfig.borderBottomRightRadius\" (click)=\"$event.stopPropagation()\">\r\n\r\n <!-- Header -->\r\n <div [ngClass]=\"getHeaderClass()\" [style.background-color]=\"mergedConfig.headerBackgroundColor\"\r\n [style.border-bottom]=\"mergedConfig.headerBorderBottom\">\r\n <div class=\"modal-header__content\">\r\n <!-- Icon (Optional) -->\r\n <span *ngIf=\"mergedConfig.icon\" class=\"modal-header__icon\">\r\n <ng-container [ngSwitch]=\"resolveIconType(mergedConfig.icon)\">\r\n <mat-icon *ngSwitchCase=\"'material'\" [style.color]=\"getIconColor(mergedConfig.icon)\">\r\n {{ getIconValue(mergedConfig.icon) }}\r\n </mat-icon>\r\n <img *ngSwitchCase=\"'custom'\" [src]=\"getIconValue(mergedConfig.icon)\"\r\n [alt]=\"mergedConfig.title + ' icon'\" class=\"modal-header__custom-icon\">\r\n <img *ngSwitchCase=\"'img'\" [src]=\"getIconValue(mergedConfig.icon)\"\r\n [alt]=\"mergedConfig.title + ' icon'\" class=\"modal-header__custom-icon\">\r\n </ng-container>\r\n </span>\r\n\r\n <!-- Title -->\r\n <h2 class=\"modal-header__title\" [id]=\"'modal-title-' + mergedConfig.title\"\r\n [style.color]=\"mergedConfig.headerTextColor\">\r\n {{ mergedConfig.title }}\r\n </h2>\r\n </div>\r\n\r\n <!-- Code Snippet Button -->\r\n <button *ngIf=\"mergedConfig.showCodeSnippetButton\" type=\"button\" class=\"modal-header__code-btn\"\r\n (click)=\"onShowCodeSnippet()\" aria-label=\"Show code snippet\" title=\"Show Code Snippet\">\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n\r\n <!-- Close Button -->\r\n <button *ngIf=\"mergedConfig.showCloseButton\" type=\"button\" class=\"modal-header__close\" (click)=\"onClose()\"\r\n aria-label=\"Close modal\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Body (Content Projection) -->\r\n <div class=\"cc-modal-body\" [style.padding]=\"mergedConfig.padding\" [style.color]=\"mergedConfig.bodyTextColor\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"cc-modal-footer\" [style.background-color]=\"mergedConfig.footerBackgroundColor\"\r\n [style.border-top]=\"mergedConfig.footerBorderTop\">\r\n\r\n <ng-container *ngIf=\"!mergedConfig.customFooter\">\r\n <button *ngIf=\"mergedConfig.cancelButton?.show\" type=\"button\" class=\"cc-btn cc-btn-secondary\"\r\n (click)=\"onCancel()\">\r\n {{ mergedConfig.cancelButton?.label || 'Cancel' }}\r\n </button>\r\n\r\n <button type=\"button\" [ngClass]=\"getConfirmButtonClass()\"\r\n [disabled]=\"mergedConfig.confirmButton.disabled || mergedConfig.confirmButton.loading\"\r\n (click)=\"onConfirm()\">\r\n <span *ngIf=\"mergedConfig.confirmButton.loading\" class=\"cc-btn-spinner\"></span>\r\n {{ mergedConfig.confirmButton.label }}\r\n </button>\r\n </ng-container>\r\n\r\n <ng-content select=\"[cc-modal-footer]\"></ng-content>\r\n </div>\r\n </div>\r\n</div>", styles: [".cc-modal-backdrop{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;animation:fadeIn .2s ease-in-out}.cc-modal-container{background:var(--cc-modal-bg);border-radius:var(--cc-modal-radius);box-shadow:var(--cc-modal-shadow);border:var(--cc-modal-border, none);display:flex;flex-direction:column;max-height:90vh;max-width:90vw;animation:slideIn .3s ease-out;overflow:hidden}.modal-header{display:flex;align-items:center;justify-content:space-between;padding:var(--cc-modal-header-padding);border-bottom:var(--cc-modal-header-border-bottom)}.modal-header__content{display:flex;align-items:center;gap:.75rem;flex:1}.modal-header__icon{display:flex;align-items:center;justify-content:center}.modal-header__icon mat-icon{font-size:var(--cc-modal-icon-size, 1.5rem);width:var(--cc-modal-icon-size, 1.5rem);height:var(--cc-modal-icon-size, 1.5rem)}.modal-header__custom-icon{width:var(--cc-modal-icon-size, 1.5rem);height:var(--cc-modal-icon-size, 1.5rem);object-fit:contain}.modal-header__title{margin:0;font-size:var(--cc-modal-title-size);font-weight:var(--cc-modal-title-weight);line-height:1.4;color:var(--cc-modal-title-color)}.modal-header__close{background:none;border:none;padding:.25rem;cursor:pointer;color:#6b7280;transition:color .2s;display:flex;align-items:center}.modal-header__close:hover{color:#111827}.modal-header__close mat-icon{font-size:var(--cc-modal-close-icon-size, 1.25rem);width:var(--cc-modal-close-icon-size, 1.25rem);height:var(--cc-modal-close-icon-size, 1.25rem)}.modal-header__code-btn{background:none;border:none;padding:.25rem;margin-right:.5rem;cursor:pointer;color:#6b7280;transition:all .2s;display:flex;align-items:center}.modal-header__code-btn:hover{color:#ef4444;transform:scale(1.1)}.modal-header__code-btn mat-icon{font-size:1.15rem;width:1.15rem;height:1.15rem}.modal-header--dark{background-color:var(--cc-modal-header-bg-dark);border-bottom:none}.modal-header--dark .modal-header__title{color:var(--cc-modal-header-title-color-dark)}.modal-header--dark .modal-header__close{color:#ffffffb3}.modal-header--dark .modal-header__close:hover{color:#fff}.modal-header--dark .modal-header__code-btn{color:#ffffffb3}.modal-header--dark .modal-header__code-btn:hover{color:#fff}.cc-modal-body{padding:var(--cc-modal-body-padding);overflow-y:auto;flex:1;color:var(--cc-modal-body-color);font-size:.875rem;line-height:1.6}.cc-modal-body ::ng-deep input[type=text],.cc-modal-body ::ng-deep textarea,.cc-modal-body ::ng-deep select{width:100%;padding:var(--cc-modal-input-padding, .625rem .75rem);border:.0625rem solid #D1D5DB;border-radius:var(--cc-modal-input-radius, .375rem);font-size:var(--cc-modal-input-font-size, .875rem);transition:border-color .2s}.cc-modal-body ::ng-deep input[type=text]:focus,.cc-modal-body ::ng-deep textarea:focus,.cc-modal-body ::ng-deep select:focus{outline:none;border-color:var(--cc-btn-primary-bg, #3b82f6);box-shadow:0 0 0 .1875rem #3b82f61a}.cc-modal-body ::ng-deep textarea{resize:vertical;min-height:var(--cc-modal-textarea-min-height, 6.25rem)}.cc-modal-body ::ng-deep label{display:block;margin-bottom:var(--cc-modal-label-margin-bottom, .5rem);font-weight:500;color:var(--cc-modal-body-color)}.cc-modal-body ::ng-deep .required:after{content:\" *\";color:#ef4444}.cc-modal-footer{display:flex;align-items:center;justify-content:flex-end;gap:.75rem;padding:var(--cc-modal-footer-padding);border-top:var(--cc-modal-footer-border-top);background:var(--cc-modal-footer-bg)}.cc-btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;padding:var(--cc-btn-padding, .5rem 1rem);font-family:var(--cc-btn-font-family, inherit);font-weight:var(--cc-btn-font-weight, 500);font-size:var(--cc-btn-font-size, .875rem);cursor:pointer;transition:all .2s;min-width:5rem}.cc-btn:disabled{opacity:var(--cc-btn-disabled-opacity, .6);cursor:var(--cc-btn-disabled-cursor, not-allowed)}.cc-btn-secondary{background:var(--cc-btn-secondary-bg);color:var(--cc-btn-secondary-color);border:var(--cc-btn-secondary-border);border-radius:var(--cc-btn-secondary-radius)}.cc-btn-primary{background:var(--cc-btn-primary-bg);color:var(--cc-btn-primary-color);border:var(--cc-btn-primary-border);border-radius:var(--cc-btn-primary-radius)}.cc-btn-danger{background:var(--cc-btn-danger-bg);color:var(--cc-btn-danger-color);border:var(--cc-btn-danger-border);border-radius:var(--cc-btn-danger-radius)}.cc-btn-warning{background:var(--cc-btn-warning-bg);color:var(--cc-btn-warning-color);border:var(--cc-btn-warning-border);border-radius:var(--cc-btn-warning-radius)}.cc-btn-spinner{width:var(--cc-modal-spinner-size, 1rem);height:var(--cc-modal-spinner-size, 1rem);border:.125rem solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin .6s linear infinite}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideIn{0%{transform:translateY(-1.25rem);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes spin{to{transform:rotate(360deg)}}@media(max-width:40rem){.cc-modal-container{width:95vw!important;max-height:95vh}.modal-header,.cc-modal-body{padding:1rem}.cc-modal-footer{padding:.75rem 1rem;flex-direction:column}.cc-modal-footer .cc-btn{width:100%}}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
2502
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2503
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SearchComponent, isStandalone: false, selector: "lib-search", inputs: { config: "config", labels: "labels", placeholder: "placeholder", label: "label", disabled: "disabled", debounceMs: "debounceMs", clearable: "clearable", value: "value", width: "width", height: "height", borderRadius: "borderRadius", fontSize: "fontSize", gap: "gap", fontFamily: "fontFamily", labelColor: "labelColor", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight", backgroundColor: "backgroundColor", borderColor: "borderColor", borderWidth: "borderWidth", border: "border", padding: "padding", fontWeight: "fontWeight", color: "color", textColor: "textColor", iconColor: "iconColor", placeholderColor: "placeholderColor", focusBorderColor: "focusBorderColor", disabledBackgroundColor: "disabledBackgroundColor", disabledColor: "disabledColor", boxShadow: "boxShadow" }, outputs: { search: "search", clear: "clear" }, providers: [
2504
+ {
2505
+ provide: NG_VALUE_ACCESSOR,
2506
+ useExisting: forwardRef(() => SearchComponent),
2507
+ multi: true
2508
+ }
2509
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-search-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n <label *ngIf=\"label\" class=\"cc-search-label\" [ngStyle]=\"labelStyles\">{{ label }}</label>\r\n\r\n <div class=\"cc-search-field\" [class.focused]=\"focused\" [class.disabled]=\"disabled\" [ngStyle]=\"fieldStyles\">\r\n <span class=\"cc-search-icon material-icons\">search</span>\r\n\r\n <input type=\"text\" class=\"cc-search-input\" [value]=\"value\" [placeholder]=\"placeholder\" [disabled]=\"disabled\"\r\n (input)=\"onInputChange($event)\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" />\r\n\r\n <button *ngIf=\"clearable && value && !disabled\" type=\"button\" class=\"cc-clear-btn\" (click)=\"onClear()\"\r\n [attr.aria-label]=\"clearAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n </div>\r\n</div>", styles: [".cc-search-wrapper{display:flex;flex-direction:column;gap:var(--cc-search-label-gap, .5rem);width:100%;font-family:var(--cc-search-font-family, inherit)}.cc-search-label{font-size:var(--cc-search-label-font-size, .875rem);font-weight:var(--cc-search-label-font-weight, 500);color:var(--cc-search-label-color, #202124);margin:0;line-height:1.4}.cc-search-field{display:flex;align-items:center;width:100%;box-sizing:border-box;background-color:var(--cc-search-bg, #FEFEFE);border:var(--cc-search-border-width, 1px) solid var(--cc-search-border-color, #BDC1C6);border-radius:var(--cc-search-border-radius, .4375rem);padding:var(--cc-search-padding, .5rem .75rem);min-height:var(--cc-search-height, 2.5rem);transition:border-color .2s,box-shadow .2s}.cc-search-field.focused{border-color:var(--cc-search-focus-border-color, #1A73E8)}.cc-search-field.disabled{background-color:var(--cc-search-disabled-bg, #F1F3F4);cursor:not-allowed}.cc-search-field.disabled .cc-search-input{cursor:not-allowed;color:var(--cc-search-disabled-color, #80868B)}.cc-search-field.disabled .cc-search-icon,.cc-search-field.disabled .cc-clear-btn{color:var(--cc-search-disabled-color, #80868B)}.cc-search-icon{margin-right:.5rem;color:var(--cc-search-icon-color, #5F6368);display:flex;align-items:center}.cc-search-input{flex:1;border:none;background:none;outline:none;font-family:inherit;font-size:var(--cc-search-font-size, .875rem);font-weight:var(--cc-search-font-weight, 400);color:var(--cc-search-color, #202124);padding:0;margin:0;width:100%}.cc-search-input::placeholder{color:var(--cc-search-placeholder-color, #80868B)}.cc-clear-btn{background:none;border:none;cursor:pointer;padding:0;margin-left:.5rem;display:flex;align-items:center;color:var(--cc-search-icon-color, #5F6368)}.cc-clear-btn:focus{outline:none}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
587
2510
  }
588
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalComponent, decorators: [{
2511
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SearchComponent, decorators: [{
589
2512
  type: Component,
590
- args: [{ selector: 'cc-confirmation-modal', standalone: false, template: "<div *ngIf=\"isOpen\" class=\"cc-modal-backdrop\" (click)=\"onBackdropClick($event)\" role=\"dialog\" [attr.aria-modal]=\"true\"\r\n [attr.aria-labelledby]=\"'modal-title-' + mergedConfig.title\" [attr.aria-label]=\"mergedConfig.ariaLabel\"\r\n [attr.aria-describedby]=\"mergedConfig.ariaDescribedBy\">\r\n\r\n <div class=\"cc-modal-container {{ mergedConfig.customClass }}\" [style.width]=\"getModalWidth()\"\r\n [style.background-color]=\"mergedConfig.backgroundColor\" [style.border-radius]=\"mergedConfig.borderRadius\"\r\n [style.border-top-left-radius]=\"mergedConfig.borderTopLeftRadius\"\r\n [style.border-top-right-radius]=\"mergedConfig.borderTopRightRadius\"\r\n [style.border-bottom-left-radius]=\"mergedConfig.borderBottomLeftRadius\"\r\n [style.border-bottom-right-radius]=\"mergedConfig.borderBottomRightRadius\" (click)=\"$event.stopPropagation()\">\r\n\r\n <!-- Header -->\r\n <div [ngClass]=\"getHeaderClass()\" [style.background-color]=\"mergedConfig.headerBackgroundColor\"\r\n [style.border-bottom]=\"mergedConfig.headerBorderBottom\">\r\n <div class=\"modal-header__content\">\r\n <!-- Icon (Optional) -->\r\n <span *ngIf=\"mergedConfig.icon\" class=\"modal-header__icon\">\r\n <ng-container [ngSwitch]=\"resolveIconType(mergedConfig.icon)\">\r\n <mat-icon *ngSwitchCase=\"'material'\" [style.color]=\"getIconColor(mergedConfig.icon)\">\r\n {{ getIconValue(mergedConfig.icon) }}\r\n </mat-icon>\r\n <img *ngSwitchCase=\"'custom'\" [src]=\"getIconValue(mergedConfig.icon)\"\r\n [alt]=\"mergedConfig.title + ' icon'\" class=\"modal-header__custom-icon\">\r\n <img *ngSwitchCase=\"'img'\" [src]=\"getIconValue(mergedConfig.icon)\"\r\n [alt]=\"mergedConfig.title + ' icon'\" class=\"modal-header__custom-icon\">\r\n </ng-container>\r\n </span>\r\n\r\n <!-- Title -->\r\n <h2 class=\"modal-header__title\" [id]=\"'modal-title-' + mergedConfig.title\"\r\n [style.color]=\"mergedConfig.headerTextColor\">\r\n {{ mergedConfig.title }}\r\n </h2>\r\n </div>\r\n\r\n <!-- Code Snippet Button -->\r\n <button *ngIf=\"mergedConfig.showCodeSnippetButton\" type=\"button\" class=\"modal-header__code-btn\"\r\n (click)=\"onShowCodeSnippet()\" aria-label=\"Show code snippet\" title=\"Show Code Snippet\">\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n\r\n <!-- Close Button -->\r\n <button *ngIf=\"mergedConfig.showCloseButton\" type=\"button\" class=\"modal-header__close\" (click)=\"onClose()\"\r\n aria-label=\"Close modal\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Body (Content Projection) -->\r\n <div class=\"cc-modal-body\" [style.padding]=\"mergedConfig.padding\" [style.color]=\"mergedConfig.bodyTextColor\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"cc-modal-footer\" [style.background-color]=\"mergedConfig.footerBackgroundColor\"\r\n [style.border-top]=\"mergedConfig.footerBorderTop\">\r\n\r\n <ng-container *ngIf=\"!mergedConfig.customFooter\">\r\n <button *ngIf=\"mergedConfig.cancelButton?.show\" type=\"button\" class=\"cc-btn cc-btn-secondary\"\r\n (click)=\"onCancel()\">\r\n {{ mergedConfig.cancelButton?.label || 'Cancel' }}\r\n </button>\r\n\r\n <button type=\"button\" [ngClass]=\"getConfirmButtonClass()\"\r\n [disabled]=\"mergedConfig.confirmButton.disabled || mergedConfig.confirmButton.loading\"\r\n (click)=\"onConfirm()\">\r\n <span *ngIf=\"mergedConfig.confirmButton.loading\" class=\"cc-btn-spinner\"></span>\r\n {{ mergedConfig.confirmButton.label }}\r\n </button>\r\n </ng-container>\r\n\r\n <ng-content select=\"[cc-modal-footer]\"></ng-content>\r\n </div>\r\n </div>\r\n</div>", styles: [".cc-modal-backdrop{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;animation:fadeIn .2s ease-in-out}.cc-modal-container{background:var(--cc-modal-bg);border-radius:var(--cc-modal-radius);box-shadow:var(--cc-modal-shadow);border:var(--cc-modal-border, none);display:flex;flex-direction:column;max-height:90vh;max-width:90vw;animation:slideIn .3s ease-out;overflow:hidden}.modal-header{display:flex;align-items:center;justify-content:space-between;padding:var(--cc-modal-header-padding);border-bottom:var(--cc-modal-header-border-bottom)}.modal-header__content{display:flex;align-items:center;gap:.75rem;flex:1}.modal-header__icon{display:flex;align-items:center;justify-content:center}.modal-header__icon mat-icon{font-size:var(--cc-modal-icon-size, 1.5rem);width:var(--cc-modal-icon-size, 1.5rem);height:var(--cc-modal-icon-size, 1.5rem)}.modal-header__custom-icon{width:var(--cc-modal-icon-size, 1.5rem);height:var(--cc-modal-icon-size, 1.5rem);object-fit:contain}.modal-header__title{margin:0;font-size:var(--cc-modal-title-size);font-weight:var(--cc-modal-title-weight);line-height:1.4;color:var(--cc-modal-title-color)}.modal-header__close{background:none;border:none;padding:.25rem;cursor:pointer;color:#6b7280;transition:color .2s;display:flex;align-items:center}.modal-header__close:hover{color:#111827}.modal-header__close mat-icon{font-size:var(--cc-modal-close-icon-size, 1.25rem);width:var(--cc-modal-close-icon-size, 1.25rem);height:var(--cc-modal-close-icon-size, 1.25rem)}.modal-header__code-btn{background:none;border:none;padding:.25rem;margin-right:.5rem;cursor:pointer;color:#6b7280;transition:all .2s;display:flex;align-items:center}.modal-header__code-btn:hover{color:#ef4444;transform:scale(1.1)}.modal-header__code-btn mat-icon{font-size:1.15rem;width:1.15rem;height:1.15rem}.modal-header--dark{background-color:var(--cc-modal-header-bg-dark);border-bottom:none}.modal-header--dark .modal-header__title{color:var(--cc-modal-header-title-color-dark)}.modal-header--dark .modal-header__close{color:#ffffffb3}.modal-header--dark .modal-header__close:hover{color:#fff}.modal-header--dark .modal-header__code-btn{color:#ffffffb3}.modal-header--dark .modal-header__code-btn:hover{color:#fff}.cc-modal-body{padding:var(--cc-modal-body-padding);overflow-y:auto;flex:1;color:var(--cc-modal-body-color);font-size:.875rem;line-height:1.6}.cc-modal-body ::ng-deep input[type=text],.cc-modal-body ::ng-deep textarea,.cc-modal-body ::ng-deep select{width:100%;padding:var(--cc-modal-input-padding, .625rem .75rem);border:.0625rem solid #D1D5DB;border-radius:var(--cc-modal-input-radius, .375rem);font-size:var(--cc-modal-input-font-size, .875rem);transition:border-color .2s}.cc-modal-body ::ng-deep input[type=text]:focus,.cc-modal-body ::ng-deep textarea:focus,.cc-modal-body ::ng-deep select:focus{outline:none;border-color:var(--cc-btn-primary-bg, #3b82f6);box-shadow:0 0 0 .1875rem #3b82f61a}.cc-modal-body ::ng-deep textarea{resize:vertical;min-height:var(--cc-modal-textarea-min-height, 6.25rem)}.cc-modal-body ::ng-deep label{display:block;margin-bottom:var(--cc-modal-label-margin-bottom, .5rem);font-weight:500;color:var(--cc-modal-body-color)}.cc-modal-body ::ng-deep .required:after{content:\" *\";color:#ef4444}.cc-modal-footer{display:flex;align-items:center;justify-content:flex-end;gap:.75rem;padding:var(--cc-modal-footer-padding);border-top:var(--cc-modal-footer-border-top);background:var(--cc-modal-footer-bg)}.cc-btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;padding:var(--cc-btn-padding, .5rem 1rem);font-family:var(--cc-btn-font-family, inherit);font-weight:var(--cc-btn-font-weight, 500);font-size:var(--cc-btn-font-size, .875rem);cursor:pointer;transition:all .2s;min-width:5rem}.cc-btn:disabled{opacity:var(--cc-btn-disabled-opacity, .6);cursor:var(--cc-btn-disabled-cursor, not-allowed)}.cc-btn-secondary{background:var(--cc-btn-secondary-bg);color:var(--cc-btn-secondary-color);border:var(--cc-btn-secondary-border);border-radius:var(--cc-btn-secondary-radius)}.cc-btn-primary{background:var(--cc-btn-primary-bg);color:var(--cc-btn-primary-color);border:var(--cc-btn-primary-border);border-radius:var(--cc-btn-primary-radius)}.cc-btn-danger{background:var(--cc-btn-danger-bg);color:var(--cc-btn-danger-color);border:var(--cc-btn-danger-border);border-radius:var(--cc-btn-danger-radius)}.cc-btn-warning{background:var(--cc-btn-warning-bg);color:var(--cc-btn-warning-color);border:var(--cc-btn-warning-border);border-radius:var(--cc-btn-warning-radius)}.cc-btn-spinner{width:var(--cc-modal-spinner-size, 1rem);height:var(--cc-modal-spinner-size, 1rem);border:.125rem solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin .6s linear infinite}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideIn{0%{transform:translateY(-1.25rem);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes spin{to{transform:rotate(360deg)}}@media(max-width:40rem){.cc-modal-container{width:95vw!important;max-height:95vh}.modal-header,.cc-modal-body{padding:1rem}.cc-modal-footer{padding:.75rem 1rem;flex-direction:column}.cc-modal-footer .cc-btn{width:100%}}\n"] }]
2513
+ args: [{ selector: 'lib-search', standalone: false, providers: [
2514
+ {
2515
+ provide: NG_VALUE_ACCESSOR,
2516
+ useExisting: forwardRef(() => SearchComponent),
2517
+ multi: true
2518
+ }
2519
+ ], template: "<div class=\"cc-search-wrapper\" [ngStyle]=\"wrapperStyles\">\r\n <label *ngIf=\"label\" class=\"cc-search-label\" [ngStyle]=\"labelStyles\">{{ label }}</label>\r\n\r\n <div class=\"cc-search-field\" [class.focused]=\"focused\" [class.disabled]=\"disabled\" [ngStyle]=\"fieldStyles\">\r\n <span class=\"cc-search-icon material-icons\">search</span>\r\n\r\n <input type=\"text\" class=\"cc-search-input\" [value]=\"value\" [placeholder]=\"placeholder\" [disabled]=\"disabled\"\r\n (input)=\"onInputChange($event)\" (blur)=\"onBlur()\" (focus)=\"onFocus()\" />\r\n\r\n <button *ngIf=\"clearable && value && !disabled\" type=\"button\" class=\"cc-clear-btn\" (click)=\"onClear()\"\r\n [attr.aria-label]=\"clearAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n </div>\r\n</div>", styles: [".cc-search-wrapper{display:flex;flex-direction:column;gap:var(--cc-search-label-gap, .5rem);width:100%;font-family:var(--cc-search-font-family, inherit)}.cc-search-label{font-size:var(--cc-search-label-font-size, .875rem);font-weight:var(--cc-search-label-font-weight, 500);color:var(--cc-search-label-color, #202124);margin:0;line-height:1.4}.cc-search-field{display:flex;align-items:center;width:100%;box-sizing:border-box;background-color:var(--cc-search-bg, #FEFEFE);border:var(--cc-search-border-width, 1px) solid var(--cc-search-border-color, #BDC1C6);border-radius:var(--cc-search-border-radius, .4375rem);padding:var(--cc-search-padding, .5rem .75rem);min-height:var(--cc-search-height, 2.5rem);transition:border-color .2s,box-shadow .2s}.cc-search-field.focused{border-color:var(--cc-search-focus-border-color, #1A73E8)}.cc-search-field.disabled{background-color:var(--cc-search-disabled-bg, #F1F3F4);cursor:not-allowed}.cc-search-field.disabled .cc-search-input{cursor:not-allowed;color:var(--cc-search-disabled-color, #80868B)}.cc-search-field.disabled .cc-search-icon,.cc-search-field.disabled .cc-clear-btn{color:var(--cc-search-disabled-color, #80868B)}.cc-search-icon{margin-right:.5rem;color:var(--cc-search-icon-color, #5F6368);display:flex;align-items:center}.cc-search-input{flex:1;border:none;background:none;outline:none;font-family:inherit;font-size:var(--cc-search-font-size, .875rem);font-weight:var(--cc-search-font-weight, 400);color:var(--cc-search-color, #202124);padding:0;margin:0;width:100%}.cc-search-input::placeholder{color:var(--cc-search-placeholder-color, #80868B)}.cc-clear-btn{background:none;border:none;cursor:pointer;padding:0;margin-left:.5rem;display:flex;align-items:center;color:var(--cc-search-icon-color, #5F6368)}.cc-clear-btn:focus{outline:none}\n"] }]
591
2520
  }], propDecorators: { config: [{
592
2521
  type: Input
593
- }], isOpen: [{
2522
+ }], labels: [{
594
2523
  type: Input
595
- }], confirm: [{
596
- type: Output
597
- }], cancel: [{
598
- type: Output
599
- }], close: [{
2524
+ }], placeholder: [{
2525
+ type: Input
2526
+ }], label: [{
2527
+ type: Input
2528
+ }], disabled: [{
2529
+ type: Input
2530
+ }], debounceMs: [{
2531
+ type: Input
2532
+ }], clearable: [{
2533
+ type: Input
2534
+ }], value: [{
2535
+ type: Input
2536
+ }], width: [{
2537
+ type: Input
2538
+ }], height: [{
2539
+ type: Input
2540
+ }], borderRadius: [{
2541
+ type: Input
2542
+ }], fontSize: [{
2543
+ type: Input
2544
+ }], gap: [{
2545
+ type: Input
2546
+ }], fontFamily: [{
2547
+ type: Input
2548
+ }], labelColor: [{
2549
+ type: Input
2550
+ }], labelFontSize: [{
2551
+ type: Input
2552
+ }], labelFontWeight: [{
2553
+ type: Input
2554
+ }], backgroundColor: [{
2555
+ type: Input
2556
+ }], borderColor: [{
2557
+ type: Input
2558
+ }], borderWidth: [{
2559
+ type: Input
2560
+ }], border: [{
2561
+ type: Input
2562
+ }], padding: [{
2563
+ type: Input
2564
+ }], fontWeight: [{
2565
+ type: Input
2566
+ }], color: [{
2567
+ type: Input
2568
+ }], textColor: [{
2569
+ type: Input
2570
+ }], iconColor: [{
2571
+ type: Input
2572
+ }], placeholderColor: [{
2573
+ type: Input
2574
+ }], focusBorderColor: [{
2575
+ type: Input
2576
+ }], disabledBackgroundColor: [{
2577
+ type: Input
2578
+ }], disabledColor: [{
2579
+ type: Input
2580
+ }], boxShadow: [{
2581
+ type: Input
2582
+ }], search: [{
600
2583
  type: Output
601
- }], showCodeSnippet: [{
2584
+ }], clear: [{
602
2585
  type: Output
603
- }], handleEscape: [{
604
- type: HostListener,
605
- args: ['document:keydown.escape', ['$event']]
606
2586
  }] } });
607
2587
 
608
- class ConfirmationModalModule {
609
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
610
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, declarations: [ConfirmationModalComponent], imports: [CommonModule,
611
- MatIconModule, // For material icons support
612
- FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
613
- ], exports: [ConfirmationModalComponent] });
614
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, imports: [CommonModule,
615
- MatIconModule, // For material icons support
616
- FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
617
- ] });
618
- }
619
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, decorators: [{
620
- type: NgModule,
621
- args: [{
622
- declarations: [
623
- ConfirmationModalComponent
624
- ],
625
- imports: [
626
- CommonModule,
627
- MatIconModule, // For material icons support
628
- FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
629
- ],
630
- exports: [
631
- ConfirmationModalComponent
632
- ]
633
- }]
634
- }] });
635
-
636
2588
  class FilterSidebarComponent {
637
2589
  router;
638
2590
  route;
@@ -641,13 +2593,16 @@ class FilterSidebarComponent {
641
2593
  filterChange = new EventEmitter();
642
2594
  filterApply = new EventEmitter();
643
2595
  filterClear = new EventEmitter();
644
- tabChange = new EventEmitter();
645
2596
  showCodeSnippet = new EventEmitter();
2597
+ close = new EventEmitter();
646
2598
  filters = {};
647
- selectedTabId = null;
648
2599
  // ControlValueAccessor callbacks
649
2600
  onChange = () => { };
650
2601
  onTouched = () => { };
2602
+ isCollapsed = false;
2603
+ toggleCollapse() {
2604
+ this.isCollapsed = !this.isCollapsed;
2605
+ }
651
2606
  constructor(router, route) {
652
2607
  this.router = router;
653
2608
  this.route = route;
@@ -656,22 +2611,22 @@ class FilterSidebarComponent {
656
2611
  if (this.initialFilters) {
657
2612
  this.filters = { ...this.initialFilters };
658
2613
  }
659
- // Initialize from URL query params
660
- this.route.queryParams.subscribe(params => {
661
- if (Object.keys(params).length > 0) {
662
- // Merge params into filters, handling potential array/string conversions if needed
663
- // For now assuming direct mapping or basic string values
664
- this.filters = { ...this.filters, ...params };
665
- }
666
- });
667
- // Initialize Tabs
668
- if (this.config?.tabs?.items?.length) {
669
- if (this.config.tabs.defaultActive) {
670
- this.selectedTabId = this.config.tabs.defaultActive;
671
- }
672
- else {
673
- this.selectedTabId = this.config.tabs.items[0].id;
674
- }
2614
+ // Initialize from URL query params if persistent
2615
+ if (this.config.settings?.persistent !== false) {
2616
+ this.route.queryParams.subscribe(params => {
2617
+ if (Object.keys(params).length > 0) {
2618
+ // Start with existing filters to preserve defaults not in URL
2619
+ const newFilters = { ...this.filters };
2620
+ Object.keys(params).forEach(key => {
2621
+ // Try to parse arrays or numbers if possible, otherwise string
2622
+ // This is a naive implementation, ideally config should dictate type
2623
+ const val = params[key];
2624
+ // If comma separated and looked like array? For now keep simple
2625
+ newFilters[key] = val;
2626
+ });
2627
+ this.filters = newFilters;
2628
+ }
2629
+ });
675
2630
  }
676
2631
  }
677
2632
  // ControlValueAccessor Implementation
@@ -690,42 +2645,18 @@ class FilterSidebarComponent {
690
2645
  this.onTouched = fn;
691
2646
  }
692
2647
  // Component Logic
693
- onTabClick(tab) {
694
- this.selectedTabId = tab.id;
695
- this.tabChange.emit(tab.id);
696
- }
697
- onFilterChange(key, value, isMulti = false) {
698
- if (isMulti) {
699
- this.toggleFilterValue(key, value);
700
- }
701
- else {
702
- this.filters[key] = value;
703
- }
704
- // Notify Generic Change
705
- this.notifyChanges(key, this.filters[key]);
706
- }
707
- toggleFilterValue(key, value) {
708
- const currentValues = this.filters[key] || [];
709
- if (Array.isArray(currentValues)) {
710
- const index = currentValues.indexOf(value);
711
- if (index > -1) {
712
- // Remove value
713
- this.filters[key] = currentValues.filter((v) => v !== value);
714
- }
715
- else {
716
- // Add value
717
- this.filters[key] = [...currentValues, value];
718
- }
719
- }
720
- else {
721
- // Initialize array if undefined
722
- this.filters[key] = [value];
723
- }
2648
+ onValueChange(key, value) {
2649
+ if (!key)
2650
+ return;
2651
+ this.filters[key] = value;
2652
+ this.notifyChanges(key, value);
724
2653
  }
725
2654
  notifyChanges(key, value) {
726
2655
  this.onChange(this.filters);
727
- // Update URL
728
- this.updateUrl();
2656
+ // Update URL if persistent
2657
+ if (this.config.settings?.persistent !== false) {
2658
+ this.updateUrl();
2659
+ }
729
2660
  this.filterChange.emit({
730
2661
  key,
731
2662
  value,
@@ -736,8 +2667,8 @@ class FilterSidebarComponent {
736
2667
  this.router.navigate([], {
737
2668
  relativeTo: this.route,
738
2669
  queryParams: this.filters,
739
- queryParamsHandling: 'merge', // Merge with existing params
740
- replaceUrl: true // Don't create new history entry for every filter change
2670
+ queryParamsHandling: 'merge',
2671
+ replaceUrl: true
741
2672
  });
742
2673
  }
743
2674
  applyFilters() {
@@ -746,41 +2677,49 @@ class FilterSidebarComponent {
746
2677
  clearFilters() {
747
2678
  this.filters = {};
748
2679
  this.onChange(this.filters);
749
- // Clear URL params (navigate with empty queryParams to clear, or reset to defaults)
750
- // Since we don't know "defaults" specifically for URL here without config,
751
- // we'll remove the keys currently in filters from the URL.
752
- // Actually, easiest way to clear specific params is passing null.
753
- // However, to clear ALL filter related params, we might need a more robust strategy
754
- // if there are other params we want to keep.
755
- // For this task, we will just navigate with empty paramsObject for the keys in `filters`
756
- // or just clear all if that's the intention.
757
- // Let's try to clear only the keys we know about from the config if possible,
758
- // but since `filters` is dynamic, let's clear the keys present in the current state before clearing.
759
- // A safer approach for "Clear All" in a filter sidebar is often to strip query params.
760
- this.router.navigate([], {
761
- relativeTo: this.route,
762
- queryParams: {}, // Clear all query params
763
- // queryParamsHandling: 'merge' // attributes to merge would need to be null to remove
764
- });
2680
+ if (this.config.settings?.persistent !== false) {
2681
+ this.router.navigate([], {
2682
+ relativeTo: this.route,
2683
+ queryParams: {},
2684
+ });
2685
+ }
765
2686
  this.filterClear.emit();
766
2687
  }
767
- trackByFn(index, item) {
768
- return item.key || index;
2688
+ onClose() {
2689
+ this.close.emit();
769
2690
  }
770
2691
  onShowCodeSnippet() {
771
2692
  this.showCodeSnippet.emit();
772
2693
  }
773
- isImgUrl(icon) {
774
- return icon.includes('/') || icon.includes('.') || icon.startsWith('http');
2694
+ get sidebarStyles() {
2695
+ const styles = {};
2696
+ if (this.config?.styles) {
2697
+ if (this.config.styles.width)
2698
+ styles['--cc-filter-sidebar-width'] = this.config.styles.width;
2699
+ if (this.config.styles.padding)
2700
+ styles['--cc-filter-sidebar-padding'] = this.config.styles.padding;
2701
+ if (this.config.styles.gap)
2702
+ styles['--cc-filter-sidebar-gap'] = this.config.styles.gap;
2703
+ if (this.config.styles.backgroundColor)
2704
+ styles['--cc-filter-sidebar-bg'] = this.config.styles.backgroundColor;
2705
+ if (this.config.styles.headerHeight)
2706
+ styles['--cc-filter-header-height'] = this.config.styles.headerHeight;
2707
+ if (this.config.styles.borderRadius)
2708
+ styles['--cc-filter-sidebar-border-radius'] = this.config.styles.borderRadius;
2709
+ }
2710
+ return styles;
2711
+ }
2712
+ trackByFn(index, item) {
2713
+ return item.key || index;
775
2714
  }
776
2715
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarComponent, deps: [{ token: i1$1.Router }, { token: i1$1.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
777
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FilterSidebarComponent, isStandalone: false, selector: "lib-filter-sidebar", inputs: { config: "config", initialFilters: "initialFilters" }, outputs: { filterChange: "filterChange", filterApply: "filterApply", filterClear: "filterClear", tabChange: "tabChange", showCodeSnippet: "showCodeSnippet" }, providers: [
2716
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FilterSidebarComponent, isStandalone: false, selector: "lib-filter-sidebar", inputs: { config: "config", initialFilters: "initialFilters" }, outputs: { filterChange: "filterChange", filterApply: "filterApply", filterClear: "filterClear", showCodeSnippet: "showCodeSnippet", close: "close" }, providers: [
778
2717
  {
779
2718
  provide: NG_VALUE_ACCESSOR,
780
2719
  useExisting: forwardRef(() => FilterSidebarComponent),
781
2720
  multi: true
782
2721
  }
783
- ], ngImport: i0, template: "<div class=\"cc-filter-sidebar\">\r\n\r\n <!-- Header with Code Snippet Button -->\r\n <div class=\"cc-filter-header\" *ngIf=\"config?.settings?.showCodeSnippet\">\r\n <button mat-icon-button class=\"cc-code-snippet-btn\" (click)=\"onShowCodeSnippet()\" title=\"Show Code Snippet\">\r\n <i class=\"fas fa-code\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Tabs Section -->\r\n <div *ngIf=\"config?.tabs?.items?.length\" class=\"cc-filter-tabs\">\r\n <div *ngFor=\"let tab of config.tabs!.items\" class=\"cc-filter-tab\" [class.active]=\"tab.id === selectedTabId\"\r\n (click)=\"onTabClick(tab)\">\r\n <i *ngIf=\"tab.icon && !isImgUrl(tab.icon)\" [class]=\"tab.icon\"></i>\r\n <img *ngIf=\"tab.icon && isImgUrl(tab.icon)\" [src]=\"tab.icon\" alt=\"icon\" class=\"cc-filter-tab-icon\">\r\n <span>{{ tab.label }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Filters Content -->\r\n <div class=\"cc-filter-content\">\r\n\r\n <ng-container *ngFor=\"let section of config.sections; trackBy: trackByFn\">\r\n\r\n <!-- Accordion Section -->\r\n <mat-accordion *ngIf=\"section.type === 'accordion'\" class=\"cc-filter-accordion\">\r\n <mat-expansion-panel [expanded]=\"section.expanded\" class=\"mat-elevation-z0\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>\r\n {{ section.title }}\r\n </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n\r\n <!-- Content of Accordion -->\r\n <ng-container *ngIf=\"section.options\">\r\n <div class=\"cc-filter-group\">\r\n <mat-checkbox *ngFor=\"let option of section.options\"\r\n [checked]=\"filters[section.key]?.includes(option.value)\"\r\n (change)=\"onFilterChange(section.key, option.value, true)\">\r\n {{ option.label }}\r\n </mat-checkbox>\r\n </div>\r\n </ng-container>\r\n </mat-expansion-panel>\r\n </mat-accordion>\r\n\r\n <!-- Select Section -->\r\n <div *ngIf=\"section.type === 'select'\" class=\"cc-filter-section\">\r\n <label *ngIf=\"section.title\" class=\"cc-filter-label\">{{ section.title }}</label>\r\n <mat-form-field appearance=\"outline\" class=\"cc-filter-full-width\">\r\n <mat-select [placeholder]=\"section.placeholder || 'Select'\" [(value)]=\"filters[section.key]\"\r\n [multiple]=\"section.multi\"\r\n (selectionChange)=\"onFilterChange(section.key, $event.value, section.multi)\">\r\n <mat-option *ngFor=\"let option of section.options\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- Radio Group Section -->\r\n <div *ngIf=\"section.type === 'radio-group'\" class=\"cc-filter-section\">\r\n <label *ngIf=\"section.title\" class=\"cc-filter-label\">{{ section.title }}</label>\r\n <mat-radio-group [(ngModel)]=\"filters[section.key]\" (change)=\"onFilterChange(section.key, $event.value)\"\r\n class=\"cc-filter-radio-group\">\r\n <mat-radio-button *ngFor=\"let option of section.options\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </mat-radio-button>\r\n </mat-radio-group>\r\n </div>\r\n\r\n <!-- Checkbox Group Section (Standalone) -->\r\n <div *ngIf=\"section.type === 'checkbox-group'\" class=\"cc-filter-section\">\r\n <label *ngIf=\"section.title\" class=\"cc-filter-label\">{{ section.title }}</label>\r\n <div class=\"cc-filter-group\">\r\n <mat-checkbox *ngFor=\"let option of section.options\"\r\n [checked]=\"filters[section.key]?.includes(option.value)\"\r\n (change)=\"onFilterChange(section.key, option.value, true)\">\r\n {{ option.label }}\r\n </mat-checkbox>\r\n </div>\r\n </div>\r\n\r\n </ng-container>\r\n\r\n </div>\r\n\r\n <!-- Actions Footer -->\r\n <div class=\"cc-filter-actions\" *ngIf=\"config.actions\">\r\n <button mat-button class=\"cc-btn-text text-danger\" *ngIf=\"config.actions?.clear?.visible !== false\"\r\n (click)=\"clearFilters()\">\r\n {{ config.actions?.clear?.label || 'Clear Filter' }}\r\n </button>\r\n <button mat-flat-button color=\"warn\" class=\"cc-btn-primary\" *ngIf=\"config.actions?.apply?.visible !== false\"\r\n [disabled]=\"config.actions?.apply?.disabled\" (click)=\"applyFilters()\">\r\n {{ config.actions?.apply?.label || 'Apply Filter' }}\r\n </button>\r\n </div>\r\n</div>", styles: [".cc-filter-sidebar{display:flex;flex-direction:column;height:100%;background-color:var(--cc-filter-bg, #ffffff);border-right:1px solid var(--cc-filter-border-color, #E5E7EB);width:var(--cc-filter-width, 320px);box-shadow:2px 0 12px #0000000a;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.cc-filter-header{display:flex;justify-content:flex-end;align-items:center;padding:.75rem 1rem;border-bottom:1px solid #f0f0f0;background-color:var(--cc-filter-header-bg, #fafafa)}.cc-filter-header .cc-code-snippet-btn{color:var(--cc-primary-color, #EF4444);transition:all .2s ease}.cc-filter-header .cc-code-snippet-btn:hover{background-color:#ef444414;transform:scale(1.05)}.cc-filter-header .cc-code-snippet-btn i{font-size:1.1rem}.cc-filter-tabs{display:flex;flex-direction:column;padding:1rem 1.25rem;gap:.625rem;border-bottom:1px solid #E5E7EB;background-color:var(--cc-filter-header-bg, #ffffff)}.cc-filter-tabs .cc-filter-tab{padding:.875rem 1.125rem;border-radius:10px;cursor:pointer;display:flex;align-items:center;gap:.75rem;color:var(--cc-filter-tab-color, #6B7280);font-weight:500;font-size:.9375rem;transition:all .25s cubic-bezier(.4,0,.2,1);border:1.5px solid transparent;position:relative}.cc-filter-tabs .cc-filter-tab:hover{background-color:var(--cc-filter-tab-hover-bg, #F9FAFB);color:var(--cc-filter-tab-hover-color, #374151);transform:translate(2px)}.cc-filter-tabs .cc-filter-tab.active{background:linear-gradient(135deg,#fef2f2,#fee2e2);color:var(--cc-filter-tab-active-color, #DC2626);border-color:var(--cc-filter-tab-active-border, #FECACA);box-shadow:0 2px 8px #ef44441f;font-weight:600}.cc-filter-tabs .cc-filter-tab.active:before{content:\"\";position:absolute;left:0;top:50%;transform:translateY(-50%);width:3px;height:60%;background-color:#ef4444;border-radius:0 2px 2px 0}.cc-filter-tabs .cc-filter-tab i{font-size:1.125rem;opacity:.9}.cc-filter-tabs .cc-filter-tab .cc-filter-tab-icon{width:1.125rem;height:1.125rem;object-fit:contain}.cc-filter-content{flex:1;overflow-y:auto;padding:1.5rem;display:flex;flex-direction:column;gap:1.5rem}.cc-filter-section{display:flex;flex-direction:column;gap:.625rem}.cc-filter-group{display:flex;flex-direction:column;gap:.75rem}::ng-deep .cc-filter-group .mat-mdc-checkbox,::ng-deep .cc-filter-group .mat-mdc-radio-button,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button{margin-bottom:.5rem}::ng-deep .cc-filter-group .mat-mdc-checkbox .mdc-checkbox,::ng-deep .cc-filter-group .mat-mdc-checkbox .mdc-radio,::ng-deep .cc-filter-group .mat-mdc-radio-button .mdc-checkbox,::ng-deep .cc-filter-group .mat-mdc-radio-button .mdc-radio,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox .mdc-checkbox,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox .mdc-radio,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button .mdc-checkbox,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button .mdc-radio{padding:8px}::ng-deep .cc-filter-group .mat-mdc-checkbox .mdc-label,::ng-deep .cc-filter-group .mat-mdc-radio-button .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button .mdc-label{font-size:.9375rem;color:#374151;padding-left:8px}::ng-deep .cc-filter-group .mat-mdc-checkbox:hover .mdc-label,::ng-deep .cc-filter-group .mat-mdc-radio-button:hover .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox:hover .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button:hover .mdc-label{color:#111827}::ng-deep .cc-filter-group .mat-mdc-checkbox-checked .mdc-label,::ng-deep .cc-filter-group .mat-mdc-radio-checked .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox-checked .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-radio-checked .mdc-label{font-weight:500;color:#dc2626}.cc-filter-label{font-size:.875rem;font-weight:500;color:var(--cc-filter-section-title-color, #374151);margin-bottom:.25rem}.cc-filter-full-width{width:100%}::ng-deep .cc-filter-accordion .mat-expansion-panel{box-shadow:none!important;background:transparent;border-radius:8px;margin-bottom:.5rem}::ng-deep .cc-filter-accordion .mat-expansion-panel:hover{background-color:#00000003}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header{padding:12px 0;height:auto;min-height:48px;border-radius:8px;transition:all .2s ease}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header.mat-expanded{height:auto;background-color:#ef444405}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header:hover{background-color:#ef44440a!important}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header .mat-content{font-weight:600;color:var(--cc-filter-accordion-title-color, #374151);text-transform:uppercase;font-size:.8125rem;letter-spacing:.05em}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:#ef4444}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-body{padding:.75rem 0 .5rem}.cc-filter-content::-webkit-scrollbar{width:6px}.cc-filter-content::-webkit-scrollbar-track{background:transparent}.cc-filter-content::-webkit-scrollbar-thumb{background-color:#0000001a;border-radius:3px}.cc-filter-content:hover::-webkit-scrollbar-thumb{background-color:#0003}::ng-deep .cc-filter-full-width.mat-mdc-form-field{width:100%}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-text-field-wrapper{background-color:#fff!important;border-radius:8px;padding:0}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .cc-filter-full-width.mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .cc-filter-full-width.mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#e2e8f0;border-width:1px;transition:border-color .2s ease}::ng-deep .cc-filter-full-width.mat-mdc-form-field:hover .mdc-notched-outline__leading,::ng-deep .cc-filter-full-width.mat-mdc-form-field:hover .mdc-notched-outline__notch,::ng-deep .cc-filter-full-width.mat-mdc-form-field:hover .mdc-notched-outline__trailing{border-color:#94a3b8}::ng-deep .cc-filter-full-width.mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .cc-filter-full-width.mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .cc-filter-full-width.mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--cc-primary-color, #EF4444);border-width:2px}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-form-field-flex{padding:0 12px;align-items:center;height:48px}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-form-field-infix{padding:8px 0!important;min-height:unset!important;display:flex;align-items:center}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-select-value{color:#1e293b;font-weight:500;font-size:.9375rem}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-select-placeholder{color:#94a3b8}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-select-arrow{color:#64748b}::ng-deep .mat-mdc-select-panel{background-color:#fff!important;border-radius:8px!important;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d!important;padding:6px 0!important;border:1px solid #E2E8F0;min-width:100%!important;margin-top:4px}::ng-deep .mat-mdc-select-panel .mat-mdc-option{padding:0 16px;height:40px;font-size:.9375rem;color:#334155;transition:background-color .15s ease}::ng-deep .mat-mdc-select-panel .mat-mdc-option:hover{background-color:#f8fafc!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option.mat-mdc-option-active,::ng-deep .mat-mdc-select-panel .mat-mdc-option.mdc-list-item--selected{background-color:#fef2f2!important;color:#ef4444!important;font-weight:500}::ng-deep .mat-mdc-select-panel .mat-mdc-option .mdc-list-item__primary-text{color:inherit}.cc-filter-actions{padding:1.25rem 1.5rem;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--cc-filter-footer-border-color, #E5E7EB);background:linear-gradient(to bottom,#fafafa,#fff);box-shadow:0 -2px 8px #00000008}.cc-filter-actions button{font-weight:500;border-radius:8px;padding:10px 20px;transition:all .25s ease;text-transform:none;font-size:.9375rem}.cc-filter-actions button.cc-btn-primary{background:linear-gradient(135deg,#ef4444,#dc2626)!important;color:#fff!important;box-shadow:0 2px 8px #ef444440}.cc-filter-actions button.cc-btn-primary:hover{box-shadow:0 4px 12px #ef444459;transform:translateY(-1px)}.cc-filter-actions button.cc-btn-primary:active{transform:translateY(0)}.cc-filter-actions button.cc-btn-text{color:#ef4444!important;font-weight:600}.cc-filter-actions button.cc-btn-text:hover{background-color:#ef444414!important}\n"], dependencies: [{ 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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i6.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i6.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: i7.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i7.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: i8.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i8.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i8.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i8.MatExpansionPanelTitle, selector: "mat-panel-title" }] });
2722
+ ], ngImport: i0, template: "<div class=\"cc-filter-sidebar\" [ngStyle]=\"sidebarStyles\" [class.collapsed]=\"isCollapsed\">\r\n\r\n <!-- Header -->\r\n <div class=\"cc-filter-header\" *ngIf=\"config.header?.visible !== false\">\r\n <div class=\"cc-header-content\">\r\n <span class=\"cc-header-title\" *ngIf=\"config.header?.title\">\r\n <span *ngIf=\"config.header?.icon\" [class]=\"config.header?.icon\" class=\"cc-header-icon material-icons\">\r\n <!-- {{config.header?.icon }} -->\r\n </span>\r\n {{ config.header?.title }}\r\n </span>\r\n <ng-content select=\"[header-actions]\"></ng-content>\r\n </div>\r\n <button type=\"button\" *ngIf=\"config.settings?.collapsible\" (click)=\"toggleCollapse()\" class=\"cc-icon-btn\"\r\n [attr.aria-label]=\"isCollapsed ? config.labels?.expandAriaLabel : config.labels?.collapseAriaLabel\">\r\n <span class=\"material-icons\">{{ isCollapsed ? 'menu_open' : 'menu' }}</span>\r\n </button>\r\n <button type=\"button\" *ngIf=\"config.header?.showClose && !isCollapsed\" (click)=\"onClose()\"\r\n class=\"cc-icon-btn cc-close-btn\" [attr.aria-label]=\"config.labels?.closeAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n <!-- Code snippet debug (optional) -->\r\n <button type=\"button\" *ngIf=\"config.settings?.showCodeSnippet\" (click)=\"onShowCodeSnippet()\" class=\"cc-icon-btn\"\r\n [attr.aria-label]=\"config.labels?.codeSnippetAriaLabel\">\r\n <span class=\"material-icons\">code</span>\r\n </button>\r\n </div>\r\n\r\n <!-- Content (Scrollable) -->\r\n <div class=\"cc-filter-content\" [class.hidden]=\"isCollapsed\">\r\n <ng-container *ngFor=\"let item of config.items; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"cc-filter-footer\" *ngIf=\"config.footer?.visible !== false && !isCollapsed\">\r\n <lib-button variant=\"outline\" color=\"warn\" class=\"cc-btn-clear\"\r\n *ngIf=\"config.footer?.clearButton?.visible !== false\" (click)=\"clearFilters()\">\r\n {{ config.footer?.clearButton?.label }}\r\n </lib-button>\r\n <lib-button variant=\"primary\" color=\"warn\" class=\"cc-btn-apply\"\r\n *ngIf=\"config.footer?.applyButton?.visible !== false\" [disabled]=\"config.footer?.applyButton?.disabled\"\r\n (click)=\"applyFilters()\">\r\n {{ config.footer?.applyButton?.label }}\r\n </lib-button>\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive Template for Items -->\r\n<ng-template #itemTemplate let-item=\"item\">\r\n <div class=\"cc-filter-item\" [ngClass]=\"['type-' + item.type]\"\r\n [style.display]=\"item.visible === false ? 'none' : 'block'\" [ngStyle]=\"item.styles\">\r\n\r\n <ng-container [ngSwitch]=\"item.type\">\r\n\r\n <!-- Input -->\r\n <lib-input *ngSwitchCase=\"'input'\" [config]=\"item.inputConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (valueChange)=\"onValueChange(item.key, $event)\">\r\n </lib-input>\r\n\r\n <!-- Dropdown -->\r\n <lib-dropdown *ngSwitchCase=\"'dropdown'\" [config]=\"item.dropdownConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (selectionChange)=\"onValueChange(item.key, $event)\">\r\n </lib-dropdown>\r\n\r\n <!-- Checkbox -->\r\n <lib-checkbox *ngSwitchCase=\"'checkbox'\" [config]=\"item.checkboxConfig\" [label]=\"item.label\"\r\n [checked]=\"!!filters[item.key]\" (checkedChange)=\"onValueChange(item.key, $event)\">\r\n </lib-checkbox>\r\n\r\n <!-- Radio -->\r\n <lib-radio *ngSwitchCase=\"'radio'\" [config]=\"item.radioConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (selectionChange)=\"onValueChange(item.key, $event)\">\r\n </lib-radio>\r\n\r\n <!-- Toggle -->\r\n <lib-toggle *ngSwitchCase=\"'toggle'\" [config]=\"item.toggleConfig\" [label]=\"item.label\"\r\n [checked]=\"filters[item.key]\" (toggleChange)=\"onValueChange(item.key, $event)\">\r\n </lib-toggle>\r\n\r\n <!-- Datepicker -->\r\n <lib-datepicker *ngSwitchCase=\"'datepicker'\" [config]=\"item.datepickerConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (dateChange)=\"onValueChange(item.key, $event)\">\r\n </lib-datepicker>\r\n\r\n <!-- Search -->\r\n <lib-search *ngSwitchCase=\"'active-search'\" [config]=\"item.searchConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (search)=\"onValueChange(item.key, $event)\">\r\n </lib-search>\r\n\r\n <!-- Group / Accordion -->\r\n <div *ngSwitchCase=\"'group'\" class=\"cc-accordion-item\" [class.expanded]=\"item.expanded\">\r\n <button type=\"button\" class=\"cc-accordion-header\" (click)=\"item.expanded = !item.expanded\">\r\n <span class=\"cc-accordion-title\">{{ item.label }}</span>\r\n <span class=\"material-icons cc-accordion-icon\">{{ item.expanded ? 'expand_less' : 'expand_more'\r\n }}</span>\r\n </button>\r\n\r\n <div class=\"cc-accordion-body\" *ngIf=\"item.expanded\">\r\n <ng-container *ngFor=\"let child of item.children; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: child }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Custom Divider -->\r\n <div *ngSwitchCase=\"'divider'\" class=\"cc-filter-divider\"></div>\r\n\r\n </ng-container>\r\n </div>\r\n</ng-template>", styles: [":host{display:block;height:100%;--cc-filter-sidebar-width: 100%;--cc-filter-sidebar-padding: 1.5rem;--cc-filter-sidebar-gap: 1.5rem;--cc-filter-sidebar-bg: #FEFEFE;--cc-filter-sidebar-border-radius: 0;--cc-filter-header-height: 3rem;--cc-filter-header-title-size: 1.125rem;--cc-filter-header-title-weight: 500;--cc-filter-header-title-color: #202124;--cc-filter-footer-padding: 1rem 0 0 0;--cc-filter-footer-gap: 1rem}.cc-filter-sidebar{display:flex;flex-direction:column;height:100%;width:var(--cc-filter-sidebar-width, 280px);background-color:var(--cc-filter-sidebar-bg, #FEFEFE);padding:var(--cc-filter-sidebar-padding, 1.5rem);box-sizing:border-box;overflow:hidden;border-radius:var(--cc-filter-sidebar-border-radius, 0);transition:width .3s ease,padding .3s ease}.cc-filter-sidebar.collapsed{width:60px!important;padding:1.5rem .5rem}.cc-filter-sidebar.collapsed .cc-filter-header{justify-content:center;margin-bottom:0}.cc-filter-sidebar.collapsed .cc-filter-header .cc-header-content,.cc-filter-sidebar.collapsed .cc-filter-header .cc-close-btn,.cc-filter-sidebar.collapsed .cc-filter-content{display:none}.cc-filter-header{display:flex;align-items:center;justify-content:space-between;min-height:var(--cc-filter-header-height, 3rem);margin-bottom:1rem;flex-shrink:0}.cc-filter-header .cc-header-content{display:flex;align-items:center;gap:.5rem;flex:1}.cc-filter-header .cc-header-title{font-size:var(--cc-filter-header-title-size, 1.125rem);font-weight:var(--cc-filter-header-title-weight, 500);color:var(--cc-filter-header-title-color, #202124);display:flex;align-items:center;gap:.5rem}.cc-filter-content{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:var(--cc-filter-sidebar-gap, 1.5rem);padding-right:.25rem}.cc-filter-content::-webkit-scrollbar{width:6px}.cc-filter-content::-webkit-scrollbar-thumb{background-color:#e0e0e0;border-radius:3px}.cc-accordion-item{border-bottom:1px solid #E0E0E0}.cc-accordion-item:last-child{border-bottom:none}.cc-accordion-item .cc-accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 0;background:none;border:none;cursor:pointer;text-align:left;outline:none}.cc-accordion-item .cc-accordion-header .cc-accordion-title{font-size:.875rem;font-weight:500;color:#202124}.cc-accordion-item .cc-accordion-header .cc-accordion-icon{color:#5f6368;transition:transform .2s}.cc-accordion-item .cc-accordion-body{padding:0 0 1rem;display:flex;flex-direction:column;gap:1rem;animation:slideDown .2s ease-out}@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-group-content{display:flex;flex-direction:column;gap:1rem}.cc-filter-divider{height:1px;background-color:#e0e0e0;margin:.5rem 0}.cc-filter-footer{display:flex;gap:var(--cc-filter-footer-gap, 1rem);padding:var(--cc-filter-footer-padding, 1rem 0 0 0);margin-top:auto;flex-shrink:0}.cc-filter-footer button{flex:1}.cc-icon-btn{background:none;border:none;cursor:pointer;color:#5f6368;padding:.5rem;border-radius:50%;display:flex;align-items:center;justify-content:center}.cc-icon-btn:hover{background-color:#0000000a}.cc-close-btn{margin-right:-.5rem}\n"], dependencies: [{ 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.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: InputComponent, selector: "lib-input", inputs: ["config", "labels", "type", "label", "placeholder", "disabled", "required", "readonly", "clearable", "maxLength", "minLength", "min", "max", "pattern", "errorMessage", "helperText", "rows", "prefixIcon", "suffixIcon", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["valueChange", "inputBlur", "inputFocus"] }, { kind: "component", type: DropdownComponent, selector: "lib-dropdown", inputs: ["config", "labels", "options", "placeholder", "label", "multiple", "searchable", "clearable", "disabled", "required", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["selectionChange"] }, { kind: "component", type: CheckboxComponent, selector: "lib-checkbox", inputs: ["config", "labels", "label", "checked", "disabled", "required", "indeterminate", "options", "labelPosition", "color", "borderRadius", "value", "errorMessage", "width", "height", "fontSize", "fontWeight", "labelColor", "labelFontSize", "labelFontWeight", "gap", "fontFamily", "backgroundColor", "borderColor", "borderWidth", "padding", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow", "size", "checkedColor", "uncheckedColor", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight"], outputs: ["checkedChange"] }, { kind: "component", type: RadioComponent, selector: "lib-radio", inputs: ["config", "label", "options", "disabled", "required", "labelPosition", "color", "layout", "labels", "gap", "labelColor", "checkedColor", "uncheckedColor", "fontSize", "fontWeight", "fontFamily", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight", "disabledColor", "errorColor", "size", "borderRadius", "labelFontSize", "labelFontWeight"], outputs: ["selectionChange"] }, { kind: "component", type: ToggleComponent, selector: "lib-toggle", inputs: ["config", "labels", "label", "checked", "disabled", "required", "labelPosition", "color", "labelColor", "uncheckedColor", "checkedColor", "thumbColor", "checkedThumbColor", "fontSize", "fontWeight", "fontFamily", "toggleWidth", "toggleHeight", "gap", "sliderColor", "labelFontSize", "labelFontWeight", "disabledColor"], outputs: ["toggleChange"] }, { kind: "component", type: DatepickerComponent, selector: "lib-datepicker", inputs: ["config", "labels", "label", "placeholder", "disabled", "required", "minDate", "maxDate", "isRange", "startView", "value", "startDate", "endDate", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["dateChange"] }, { kind: "component", type: SearchComponent, selector: "lib-search", inputs: ["config", "labels", "placeholder", "label", "disabled", "debounceMs", "clearable", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "border", "padding", "fontWeight", "color", "textColor", "iconColor", "placeholderColor", "focusBorderColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["search", "clear"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["variant", "type", "disabled", "width", "height", "borderRadius", "fontSize", "fontWeight", "backgroundColor", "color", "border", "icon", "labels"] }] });
784
2723
  }
785
2724
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarComponent, decorators: [{
786
2725
  type: Component,
@@ -790,7 +2729,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
790
2729
  useExisting: forwardRef(() => FilterSidebarComponent),
791
2730
  multi: true
792
2731
  }
793
- ], template: "<div class=\"cc-filter-sidebar\">\r\n\r\n <!-- Header with Code Snippet Button -->\r\n <div class=\"cc-filter-header\" *ngIf=\"config?.settings?.showCodeSnippet\">\r\n <button mat-icon-button class=\"cc-code-snippet-btn\" (click)=\"onShowCodeSnippet()\" title=\"Show Code Snippet\">\r\n <i class=\"fas fa-code\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Tabs Section -->\r\n <div *ngIf=\"config?.tabs?.items?.length\" class=\"cc-filter-tabs\">\r\n <div *ngFor=\"let tab of config.tabs!.items\" class=\"cc-filter-tab\" [class.active]=\"tab.id === selectedTabId\"\r\n (click)=\"onTabClick(tab)\">\r\n <i *ngIf=\"tab.icon && !isImgUrl(tab.icon)\" [class]=\"tab.icon\"></i>\r\n <img *ngIf=\"tab.icon && isImgUrl(tab.icon)\" [src]=\"tab.icon\" alt=\"icon\" class=\"cc-filter-tab-icon\">\r\n <span>{{ tab.label }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Filters Content -->\r\n <div class=\"cc-filter-content\">\r\n\r\n <ng-container *ngFor=\"let section of config.sections; trackBy: trackByFn\">\r\n\r\n <!-- Accordion Section -->\r\n <mat-accordion *ngIf=\"section.type === 'accordion'\" class=\"cc-filter-accordion\">\r\n <mat-expansion-panel [expanded]=\"section.expanded\" class=\"mat-elevation-z0\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>\r\n {{ section.title }}\r\n </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n\r\n <!-- Content of Accordion -->\r\n <ng-container *ngIf=\"section.options\">\r\n <div class=\"cc-filter-group\">\r\n <mat-checkbox *ngFor=\"let option of section.options\"\r\n [checked]=\"filters[section.key]?.includes(option.value)\"\r\n (change)=\"onFilterChange(section.key, option.value, true)\">\r\n {{ option.label }}\r\n </mat-checkbox>\r\n </div>\r\n </ng-container>\r\n </mat-expansion-panel>\r\n </mat-accordion>\r\n\r\n <!-- Select Section -->\r\n <div *ngIf=\"section.type === 'select'\" class=\"cc-filter-section\">\r\n <label *ngIf=\"section.title\" class=\"cc-filter-label\">{{ section.title }}</label>\r\n <mat-form-field appearance=\"outline\" class=\"cc-filter-full-width\">\r\n <mat-select [placeholder]=\"section.placeholder || 'Select'\" [(value)]=\"filters[section.key]\"\r\n [multiple]=\"section.multi\"\r\n (selectionChange)=\"onFilterChange(section.key, $event.value, section.multi)\">\r\n <mat-option *ngFor=\"let option of section.options\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- Radio Group Section -->\r\n <div *ngIf=\"section.type === 'radio-group'\" class=\"cc-filter-section\">\r\n <label *ngIf=\"section.title\" class=\"cc-filter-label\">{{ section.title }}</label>\r\n <mat-radio-group [(ngModel)]=\"filters[section.key]\" (change)=\"onFilterChange(section.key, $event.value)\"\r\n class=\"cc-filter-radio-group\">\r\n <mat-radio-button *ngFor=\"let option of section.options\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </mat-radio-button>\r\n </mat-radio-group>\r\n </div>\r\n\r\n <!-- Checkbox Group Section (Standalone) -->\r\n <div *ngIf=\"section.type === 'checkbox-group'\" class=\"cc-filter-section\">\r\n <label *ngIf=\"section.title\" class=\"cc-filter-label\">{{ section.title }}</label>\r\n <div class=\"cc-filter-group\">\r\n <mat-checkbox *ngFor=\"let option of section.options\"\r\n [checked]=\"filters[section.key]?.includes(option.value)\"\r\n (change)=\"onFilterChange(section.key, option.value, true)\">\r\n {{ option.label }}\r\n </mat-checkbox>\r\n </div>\r\n </div>\r\n\r\n </ng-container>\r\n\r\n </div>\r\n\r\n <!-- Actions Footer -->\r\n <div class=\"cc-filter-actions\" *ngIf=\"config.actions\">\r\n <button mat-button class=\"cc-btn-text text-danger\" *ngIf=\"config.actions?.clear?.visible !== false\"\r\n (click)=\"clearFilters()\">\r\n {{ config.actions?.clear?.label || 'Clear Filter' }}\r\n </button>\r\n <button mat-flat-button color=\"warn\" class=\"cc-btn-primary\" *ngIf=\"config.actions?.apply?.visible !== false\"\r\n [disabled]=\"config.actions?.apply?.disabled\" (click)=\"applyFilters()\">\r\n {{ config.actions?.apply?.label || 'Apply Filter' }}\r\n </button>\r\n </div>\r\n</div>", styles: [".cc-filter-sidebar{display:flex;flex-direction:column;height:100%;background-color:var(--cc-filter-bg, #ffffff);border-right:1px solid var(--cc-filter-border-color, #E5E7EB);width:var(--cc-filter-width, 320px);box-shadow:2px 0 12px #0000000a;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.cc-filter-header{display:flex;justify-content:flex-end;align-items:center;padding:.75rem 1rem;border-bottom:1px solid #f0f0f0;background-color:var(--cc-filter-header-bg, #fafafa)}.cc-filter-header .cc-code-snippet-btn{color:var(--cc-primary-color, #EF4444);transition:all .2s ease}.cc-filter-header .cc-code-snippet-btn:hover{background-color:#ef444414;transform:scale(1.05)}.cc-filter-header .cc-code-snippet-btn i{font-size:1.1rem}.cc-filter-tabs{display:flex;flex-direction:column;padding:1rem 1.25rem;gap:.625rem;border-bottom:1px solid #E5E7EB;background-color:var(--cc-filter-header-bg, #ffffff)}.cc-filter-tabs .cc-filter-tab{padding:.875rem 1.125rem;border-radius:10px;cursor:pointer;display:flex;align-items:center;gap:.75rem;color:var(--cc-filter-tab-color, #6B7280);font-weight:500;font-size:.9375rem;transition:all .25s cubic-bezier(.4,0,.2,1);border:1.5px solid transparent;position:relative}.cc-filter-tabs .cc-filter-tab:hover{background-color:var(--cc-filter-tab-hover-bg, #F9FAFB);color:var(--cc-filter-tab-hover-color, #374151);transform:translate(2px)}.cc-filter-tabs .cc-filter-tab.active{background:linear-gradient(135deg,#fef2f2,#fee2e2);color:var(--cc-filter-tab-active-color, #DC2626);border-color:var(--cc-filter-tab-active-border, #FECACA);box-shadow:0 2px 8px #ef44441f;font-weight:600}.cc-filter-tabs .cc-filter-tab.active:before{content:\"\";position:absolute;left:0;top:50%;transform:translateY(-50%);width:3px;height:60%;background-color:#ef4444;border-radius:0 2px 2px 0}.cc-filter-tabs .cc-filter-tab i{font-size:1.125rem;opacity:.9}.cc-filter-tabs .cc-filter-tab .cc-filter-tab-icon{width:1.125rem;height:1.125rem;object-fit:contain}.cc-filter-content{flex:1;overflow-y:auto;padding:1.5rem;display:flex;flex-direction:column;gap:1.5rem}.cc-filter-section{display:flex;flex-direction:column;gap:.625rem}.cc-filter-group{display:flex;flex-direction:column;gap:.75rem}::ng-deep .cc-filter-group .mat-mdc-checkbox,::ng-deep .cc-filter-group .mat-mdc-radio-button,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button{margin-bottom:.5rem}::ng-deep .cc-filter-group .mat-mdc-checkbox .mdc-checkbox,::ng-deep .cc-filter-group .mat-mdc-checkbox .mdc-radio,::ng-deep .cc-filter-group .mat-mdc-radio-button .mdc-checkbox,::ng-deep .cc-filter-group .mat-mdc-radio-button .mdc-radio,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox .mdc-checkbox,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox .mdc-radio,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button .mdc-checkbox,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button .mdc-radio{padding:8px}::ng-deep .cc-filter-group .mat-mdc-checkbox .mdc-label,::ng-deep .cc-filter-group .mat-mdc-radio-button .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button .mdc-label{font-size:.9375rem;color:#374151;padding-left:8px}::ng-deep .cc-filter-group .mat-mdc-checkbox:hover .mdc-label,::ng-deep .cc-filter-group .mat-mdc-radio-button:hover .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox:hover .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-radio-button:hover .mdc-label{color:#111827}::ng-deep .cc-filter-group .mat-mdc-checkbox-checked .mdc-label,::ng-deep .cc-filter-group .mat-mdc-radio-checked .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-checkbox-checked .mdc-label,::ng-deep .cc-filter-radio-group .mat-mdc-radio-checked .mdc-label{font-weight:500;color:#dc2626}.cc-filter-label{font-size:.875rem;font-weight:500;color:var(--cc-filter-section-title-color, #374151);margin-bottom:.25rem}.cc-filter-full-width{width:100%}::ng-deep .cc-filter-accordion .mat-expansion-panel{box-shadow:none!important;background:transparent;border-radius:8px;margin-bottom:.5rem}::ng-deep .cc-filter-accordion .mat-expansion-panel:hover{background-color:#00000003}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header{padding:12px 0;height:auto;min-height:48px;border-radius:8px;transition:all .2s ease}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header.mat-expanded{height:auto;background-color:#ef444405}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header:hover{background-color:#ef44440a!important}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header .mat-content{font-weight:600;color:var(--cc-filter-accordion-title-color, #374151);text-transform:uppercase;font-size:.8125rem;letter-spacing:.05em}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:#ef4444}::ng-deep .cc-filter-accordion .mat-expansion-panel .mat-expansion-panel-body{padding:.75rem 0 .5rem}.cc-filter-content::-webkit-scrollbar{width:6px}.cc-filter-content::-webkit-scrollbar-track{background:transparent}.cc-filter-content::-webkit-scrollbar-thumb{background-color:#0000001a;border-radius:3px}.cc-filter-content:hover::-webkit-scrollbar-thumb{background-color:#0003}::ng-deep .cc-filter-full-width.mat-mdc-form-field{width:100%}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-text-field-wrapper{background-color:#fff!important;border-radius:8px;padding:0}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .cc-filter-full-width.mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .cc-filter-full-width.mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#e2e8f0;border-width:1px;transition:border-color .2s ease}::ng-deep .cc-filter-full-width.mat-mdc-form-field:hover .mdc-notched-outline__leading,::ng-deep .cc-filter-full-width.mat-mdc-form-field:hover .mdc-notched-outline__notch,::ng-deep .cc-filter-full-width.mat-mdc-form-field:hover .mdc-notched-outline__trailing{border-color:#94a3b8}::ng-deep .cc-filter-full-width.mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .cc-filter-full-width.mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .cc-filter-full-width.mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--cc-primary-color, #EF4444);border-width:2px}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-form-field-flex{padding:0 12px;align-items:center;height:48px}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-form-field-infix{padding:8px 0!important;min-height:unset!important;display:flex;align-items:center}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-select-value{color:#1e293b;font-weight:500;font-size:.9375rem}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-select-placeholder{color:#94a3b8}::ng-deep .cc-filter-full-width.mat-mdc-form-field .mat-mdc-select-arrow{color:#64748b}::ng-deep .mat-mdc-select-panel{background-color:#fff!important;border-radius:8px!important;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d!important;padding:6px 0!important;border:1px solid #E2E8F0;min-width:100%!important;margin-top:4px}::ng-deep .mat-mdc-select-panel .mat-mdc-option{padding:0 16px;height:40px;font-size:.9375rem;color:#334155;transition:background-color .15s ease}::ng-deep .mat-mdc-select-panel .mat-mdc-option:hover{background-color:#f8fafc!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option.mat-mdc-option-active,::ng-deep .mat-mdc-select-panel .mat-mdc-option.mdc-list-item--selected{background-color:#fef2f2!important;color:#ef4444!important;font-weight:500}::ng-deep .mat-mdc-select-panel .mat-mdc-option .mdc-list-item__primary-text{color:inherit}.cc-filter-actions{padding:1.25rem 1.5rem;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--cc-filter-footer-border-color, #E5E7EB);background:linear-gradient(to bottom,#fafafa,#fff);box-shadow:0 -2px 8px #00000008}.cc-filter-actions button{font-weight:500;border-radius:8px;padding:10px 20px;transition:all .25s ease;text-transform:none;font-size:.9375rem}.cc-filter-actions button.cc-btn-primary{background:linear-gradient(135deg,#ef4444,#dc2626)!important;color:#fff!important;box-shadow:0 2px 8px #ef444440}.cc-filter-actions button.cc-btn-primary:hover{box-shadow:0 4px 12px #ef444459;transform:translateY(-1px)}.cc-filter-actions button.cc-btn-primary:active{transform:translateY(0)}.cc-filter-actions button.cc-btn-text{color:#ef4444!important;font-weight:600}.cc-filter-actions button.cc-btn-text:hover{background-color:#ef444414!important}\n"] }]
2732
+ ], template: "<div class=\"cc-filter-sidebar\" [ngStyle]=\"sidebarStyles\" [class.collapsed]=\"isCollapsed\">\r\n\r\n <!-- Header -->\r\n <div class=\"cc-filter-header\" *ngIf=\"config.header?.visible !== false\">\r\n <div class=\"cc-header-content\">\r\n <span class=\"cc-header-title\" *ngIf=\"config.header?.title\">\r\n <span *ngIf=\"config.header?.icon\" [class]=\"config.header?.icon\" class=\"cc-header-icon material-icons\">\r\n <!-- {{config.header?.icon }} -->\r\n </span>\r\n {{ config.header?.title }}\r\n </span>\r\n <ng-content select=\"[header-actions]\"></ng-content>\r\n </div>\r\n <button type=\"button\" *ngIf=\"config.settings?.collapsible\" (click)=\"toggleCollapse()\" class=\"cc-icon-btn\"\r\n [attr.aria-label]=\"isCollapsed ? config.labels?.expandAriaLabel : config.labels?.collapseAriaLabel\">\r\n <span class=\"material-icons\">{{ isCollapsed ? 'menu_open' : 'menu' }}</span>\r\n </button>\r\n <button type=\"button\" *ngIf=\"config.header?.showClose && !isCollapsed\" (click)=\"onClose()\"\r\n class=\"cc-icon-btn cc-close-btn\" [attr.aria-label]=\"config.labels?.closeAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n <!-- Code snippet debug (optional) -->\r\n <button type=\"button\" *ngIf=\"config.settings?.showCodeSnippet\" (click)=\"onShowCodeSnippet()\" class=\"cc-icon-btn\"\r\n [attr.aria-label]=\"config.labels?.codeSnippetAriaLabel\">\r\n <span class=\"material-icons\">code</span>\r\n </button>\r\n </div>\r\n\r\n <!-- Content (Scrollable) -->\r\n <div class=\"cc-filter-content\" [class.hidden]=\"isCollapsed\">\r\n <ng-container *ngFor=\"let item of config.items; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"cc-filter-footer\" *ngIf=\"config.footer?.visible !== false && !isCollapsed\">\r\n <lib-button variant=\"outline\" color=\"warn\" class=\"cc-btn-clear\"\r\n *ngIf=\"config.footer?.clearButton?.visible !== false\" (click)=\"clearFilters()\">\r\n {{ config.footer?.clearButton?.label }}\r\n </lib-button>\r\n <lib-button variant=\"primary\" color=\"warn\" class=\"cc-btn-apply\"\r\n *ngIf=\"config.footer?.applyButton?.visible !== false\" [disabled]=\"config.footer?.applyButton?.disabled\"\r\n (click)=\"applyFilters()\">\r\n {{ config.footer?.applyButton?.label }}\r\n </lib-button>\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive Template for Items -->\r\n<ng-template #itemTemplate let-item=\"item\">\r\n <div class=\"cc-filter-item\" [ngClass]=\"['type-' + item.type]\"\r\n [style.display]=\"item.visible === false ? 'none' : 'block'\" [ngStyle]=\"item.styles\">\r\n\r\n <ng-container [ngSwitch]=\"item.type\">\r\n\r\n <!-- Input -->\r\n <lib-input *ngSwitchCase=\"'input'\" [config]=\"item.inputConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (valueChange)=\"onValueChange(item.key, $event)\">\r\n </lib-input>\r\n\r\n <!-- Dropdown -->\r\n <lib-dropdown *ngSwitchCase=\"'dropdown'\" [config]=\"item.dropdownConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (selectionChange)=\"onValueChange(item.key, $event)\">\r\n </lib-dropdown>\r\n\r\n <!-- Checkbox -->\r\n <lib-checkbox *ngSwitchCase=\"'checkbox'\" [config]=\"item.checkboxConfig\" [label]=\"item.label\"\r\n [checked]=\"!!filters[item.key]\" (checkedChange)=\"onValueChange(item.key, $event)\">\r\n </lib-checkbox>\r\n\r\n <!-- Radio -->\r\n <lib-radio *ngSwitchCase=\"'radio'\" [config]=\"item.radioConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (selectionChange)=\"onValueChange(item.key, $event)\">\r\n </lib-radio>\r\n\r\n <!-- Toggle -->\r\n <lib-toggle *ngSwitchCase=\"'toggle'\" [config]=\"item.toggleConfig\" [label]=\"item.label\"\r\n [checked]=\"filters[item.key]\" (toggleChange)=\"onValueChange(item.key, $event)\">\r\n </lib-toggle>\r\n\r\n <!-- Datepicker -->\r\n <lib-datepicker *ngSwitchCase=\"'datepicker'\" [config]=\"item.datepickerConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (dateChange)=\"onValueChange(item.key, $event)\">\r\n </lib-datepicker>\r\n\r\n <!-- Search -->\r\n <lib-search *ngSwitchCase=\"'active-search'\" [config]=\"item.searchConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (search)=\"onValueChange(item.key, $event)\">\r\n </lib-search>\r\n\r\n <!-- Group / Accordion -->\r\n <div *ngSwitchCase=\"'group'\" class=\"cc-accordion-item\" [class.expanded]=\"item.expanded\">\r\n <button type=\"button\" class=\"cc-accordion-header\" (click)=\"item.expanded = !item.expanded\">\r\n <span class=\"cc-accordion-title\">{{ item.label }}</span>\r\n <span class=\"material-icons cc-accordion-icon\">{{ item.expanded ? 'expand_less' : 'expand_more'\r\n }}</span>\r\n </button>\r\n\r\n <div class=\"cc-accordion-body\" *ngIf=\"item.expanded\">\r\n <ng-container *ngFor=\"let child of item.children; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: child }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Custom Divider -->\r\n <div *ngSwitchCase=\"'divider'\" class=\"cc-filter-divider\"></div>\r\n\r\n </ng-container>\r\n </div>\r\n</ng-template>", styles: [":host{display:block;height:100%;--cc-filter-sidebar-width: 100%;--cc-filter-sidebar-padding: 1.5rem;--cc-filter-sidebar-gap: 1.5rem;--cc-filter-sidebar-bg: #FEFEFE;--cc-filter-sidebar-border-radius: 0;--cc-filter-header-height: 3rem;--cc-filter-header-title-size: 1.125rem;--cc-filter-header-title-weight: 500;--cc-filter-header-title-color: #202124;--cc-filter-footer-padding: 1rem 0 0 0;--cc-filter-footer-gap: 1rem}.cc-filter-sidebar{display:flex;flex-direction:column;height:100%;width:var(--cc-filter-sidebar-width, 280px);background-color:var(--cc-filter-sidebar-bg, #FEFEFE);padding:var(--cc-filter-sidebar-padding, 1.5rem);box-sizing:border-box;overflow:hidden;border-radius:var(--cc-filter-sidebar-border-radius, 0);transition:width .3s ease,padding .3s ease}.cc-filter-sidebar.collapsed{width:60px!important;padding:1.5rem .5rem}.cc-filter-sidebar.collapsed .cc-filter-header{justify-content:center;margin-bottom:0}.cc-filter-sidebar.collapsed .cc-filter-header .cc-header-content,.cc-filter-sidebar.collapsed .cc-filter-header .cc-close-btn,.cc-filter-sidebar.collapsed .cc-filter-content{display:none}.cc-filter-header{display:flex;align-items:center;justify-content:space-between;min-height:var(--cc-filter-header-height, 3rem);margin-bottom:1rem;flex-shrink:0}.cc-filter-header .cc-header-content{display:flex;align-items:center;gap:.5rem;flex:1}.cc-filter-header .cc-header-title{font-size:var(--cc-filter-header-title-size, 1.125rem);font-weight:var(--cc-filter-header-title-weight, 500);color:var(--cc-filter-header-title-color, #202124);display:flex;align-items:center;gap:.5rem}.cc-filter-content{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:var(--cc-filter-sidebar-gap, 1.5rem);padding-right:.25rem}.cc-filter-content::-webkit-scrollbar{width:6px}.cc-filter-content::-webkit-scrollbar-thumb{background-color:#e0e0e0;border-radius:3px}.cc-accordion-item{border-bottom:1px solid #E0E0E0}.cc-accordion-item:last-child{border-bottom:none}.cc-accordion-item .cc-accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 0;background:none;border:none;cursor:pointer;text-align:left;outline:none}.cc-accordion-item .cc-accordion-header .cc-accordion-title{font-size:.875rem;font-weight:500;color:#202124}.cc-accordion-item .cc-accordion-header .cc-accordion-icon{color:#5f6368;transition:transform .2s}.cc-accordion-item .cc-accordion-body{padding:0 0 1rem;display:flex;flex-direction:column;gap:1rem;animation:slideDown .2s ease-out}@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-group-content{display:flex;flex-direction:column;gap:1rem}.cc-filter-divider{height:1px;background-color:#e0e0e0;margin:.5rem 0}.cc-filter-footer{display:flex;gap:var(--cc-filter-footer-gap, 1rem);padding:var(--cc-filter-footer-padding, 1rem 0 0 0);margin-top:auto;flex-shrink:0}.cc-filter-footer button{flex:1}.cc-icon-btn{background:none;border:none;cursor:pointer;color:#5f6368;padding:.5rem;border-radius:50%;display:flex;align-items:center;justify-content:center}.cc-icon-btn:hover{background-color:#0000000a}.cc-close-btn{margin-right:-.5rem}\n"] }]
794
2733
  }], ctorParameters: () => [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }], propDecorators: { config: [{
795
2734
  type: Input
796
2735
  }], initialFilters: [{
@@ -801,22 +2740,79 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
801
2740
  type: Output
802
2741
  }], filterClear: [{
803
2742
  type: Output
804
- }], tabChange: [{
805
- type: Output
806
2743
  }], showCodeSnippet: [{
807
2744
  type: Output
2745
+ }], close: [{
2746
+ type: Output
808
2747
  }] } });
809
2748
 
2749
+ class FormComponentsModule {
2750
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormComponentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2751
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: FormComponentsModule, declarations: [InputComponent,
2752
+ DropdownComponent,
2753
+ CheckboxComponent,
2754
+ RadioComponent,
2755
+ ToggleComponent,
2756
+ DatepickerComponent,
2757
+ SearchComponent,
2758
+ ClickOutsideDirective], imports: [CommonModule,
2759
+ ReactiveFormsModule,
2760
+ FormsModule,
2761
+ ScrollingModule], exports: [InputComponent,
2762
+ DropdownComponent,
2763
+ CheckboxComponent,
2764
+ RadioComponent,
2765
+ ToggleComponent,
2766
+ DatepickerComponent,
2767
+ SearchComponent] });
2768
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormComponentsModule, imports: [CommonModule,
2769
+ ReactiveFormsModule,
2770
+ FormsModule,
2771
+ ScrollingModule] });
2772
+ }
2773
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormComponentsModule, decorators: [{
2774
+ type: NgModule,
2775
+ args: [{
2776
+ declarations: [
2777
+ InputComponent,
2778
+ DropdownComponent,
2779
+ CheckboxComponent,
2780
+ RadioComponent,
2781
+ ToggleComponent,
2782
+ DatepickerComponent,
2783
+ SearchComponent,
2784
+ ClickOutsideDirective
2785
+ ],
2786
+ imports: [
2787
+ CommonModule,
2788
+ ReactiveFormsModule,
2789
+ FormsModule,
2790
+ ScrollingModule
2791
+ ],
2792
+ exports: [
2793
+ InputComponent,
2794
+ DropdownComponent,
2795
+ CheckboxComponent,
2796
+ RadioComponent,
2797
+ ToggleComponent,
2798
+ DatepickerComponent,
2799
+ SearchComponent
2800
+ ]
2801
+ }]
2802
+ }] });
2803
+
810
2804
  class FilterSidebarModule {
811
2805
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
812
2806
  static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarModule, declarations: [FilterSidebarComponent], imports: [CommonModule,
813
2807
  FormsModule,
814
2808
  ReactiveFormsModule,
815
- MaterialModule], exports: [FilterSidebarComponent] });
2809
+ FormComponentsModule,
2810
+ ButtonModule], exports: [FilterSidebarComponent] });
816
2811
  static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarModule, imports: [CommonModule,
817
2812
  FormsModule,
818
2813
  ReactiveFormsModule,
819
- MaterialModule] });
2814
+ FormComponentsModule,
2815
+ ButtonModule] });
820
2816
  }
821
2817
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarModule, decorators: [{
822
2818
  type: NgModule,
@@ -828,7 +2824,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
828
2824
  CommonModule,
829
2825
  FormsModule,
830
2826
  ReactiveFormsModule,
831
- MaterialModule
2827
+ FormComponentsModule,
2828
+ ButtonModule
832
2829
  ],
833
2830
  exports: [
834
2831
  FilterSidebarComponent
@@ -942,12 +2939,11 @@ class ConfigurableFormComponent {
942
2939
  jsonConfig;
943
2940
  data = {};
944
2941
  baseApiUrl = '';
945
- formSubmit = new EventEmitter();
946
- formCancel = new EventEmitter();
947
2942
  optionsLoad = new EventEmitter();
948
2943
  form;
949
2944
  processedConfig;
950
2945
  fieldVisibilityMap = new Map();
2946
+ passwordFieldState = new Map();
951
2947
  constructor(fb, snackBar, http) {
952
2948
  this.fb = fb;
953
2949
  this.snackBar = snackBar;
@@ -1210,14 +3206,13 @@ class ConfigurableFormComponent {
1210
3206
  const formArray = this.getFormArray(sectionName);
1211
3207
  formArray.removeAt(index);
1212
3208
  }
1213
- onSubmit() {
3209
+ validate() {
1214
3210
  if (this.form.invalid) {
1215
3211
  this.form.markAllAsTouched();
1216
3212
  this.scrollToFirstInvalidControl();
1217
- this.snackBar.open('Please fill all required fields', 'Close', { duration: 3000 });
1218
- return;
3213
+ return false;
1219
3214
  }
1220
- this.formSubmit.emit(this.form.value);
3215
+ return true;
1221
3216
  }
1222
3217
  scrollToFirstInvalidControl() {
1223
3218
  const firstInvalidControl = document.querySelector('.is-invalid');
@@ -1437,9 +3432,6 @@ class ConfigurableFormComponent {
1437
3432
  toggleSection(section) {
1438
3433
  section.collapsed = !section.collapsed;
1439
3434
  }
1440
- onCancel() {
1441
- this.formCancel.emit();
1442
- }
1443
3435
  // Helper method to find field by name
1444
3436
  findFieldByName(name) {
1445
3437
  for (const section of this.processedConfig.sections) {
@@ -1454,13 +3446,19 @@ class ConfigurableFormComponent {
1454
3446
  get sections() {
1455
3447
  return this.processedConfig?.sections || [];
1456
3448
  }
1457
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigurableFormComponent, deps: [{ token: i1$2.FormBuilder }, { token: i2$1.MatSnackBar }, { token: i3.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
1458
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ConfigurableFormComponent, isStandalone: true, selector: "lib-configurable-form", inputs: { config: "config", jsonConfig: "jsonConfig", data: "data", baseApiUrl: "baseApiUrl" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", optionsLoad: "optionsLoad" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\" class=\"configurable-form-container\" *ngIf=\"form\">\r\n\r\n <ng-container *ngFor=\"let section of sections\">\r\n\r\n <!-- Repeater Section -->\r\n <div *ngIf=\"section.isRepeater; else normalSection\"\r\n [ngClass]=\"section.noCardLayout ? 'section-no-card' : 'section-card'\">\r\n <div class=\"section-header\" *ngIf=\"section.sectionTitle\">\r\n <h3 class=\"section-title\">{{ section.sectionTitle }}</h3>\r\n <button *ngIf=\"section.collapsible\" mat-icon-button type=\"button\" (click)=\"toggleSection(section)\">\r\n <mat-icon>{{ section.collapsed ? 'expand_more' : 'expand_less' }}</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div [formArrayName]=\"section.formArrayName || 'items'\" *ngIf=\"!section.collapsed\">\r\n <div *ngFor=\"let item of getFormArray(section.formArrayName!).controls; let i = index\"\r\n [formGroupName]=\"i\" class=\"repeater-item\">\r\n <div class=\"repeater-item-header\" *ngIf=\"getFormArray(section.formArrayName!).length > 1\">\r\n <span class=\"text-small\">{{ section.repeaterItemLabel || 'Item' }} {{i + 1}}</span>\r\n <button mat-icon-button color=\"warn\" type=\"button\"\r\n (click)=\"removeRepeaterItem(section.formArrayName!, i)\"\r\n [disabled]=\"section.minItems && getFormArray(section.formArrayName!).length <= section.minItems\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Fields Grid -->\r\n <div class=\"form-grid\">\r\n <div *ngFor=\"let field of section.fields\" [ngClass]=\"['form-col', field.class || 'col-12']\"\r\n [hidden]=\"!isFieldVisible(field)\">\r\n <ng-container\r\n *ngTemplateOutlet=\"fieldTemplate; context: {field: field, group: item}\"></ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"repeater-separator\" *ngIf=\"i < getFormArray(section.formArrayName!).length - 1\"></div>\r\n </div>\r\n </div>\r\n\r\n <button mat-button color=\"primary\" type=\"button\" (click)=\"addRepeaterItem(section)\" class=\"add-btn\"\r\n *ngIf=\"!section.collapsed\"\r\n [disabled]=\"section.maxItems && getFormArray(section.formArrayName!).length >= section.maxItems\">\r\n <mat-icon>add_circle_outline</mat-icon> {{ section.addLabel || 'Add More' }}\r\n </button>\r\n </div>\r\n\r\n <!-- Normal Section -->\r\n <ng-template #normalSection>\r\n <div [ngClass]=\"section.noCardLayout ? 'section-no-card' : 'section-card'\">\r\n <div class=\"section-header\" *ngIf=\"section.sectionTitle\">\r\n <h3 class=\"section-title\">{{ section.sectionTitle }}</h3>\r\n <button *ngIf=\"section.collapsible\" mat-icon-button type=\"button\" (click)=\"toggleSection(section)\">\r\n <mat-icon>{{ section.collapsed ? 'expand_more' : 'expand_less' }}</mat-icon>\r\n </button>\r\n </div>\r\n <div class=\"form-grid\" *ngIf=\"!section.collapsed\">\r\n <div *ngFor=\"let field of section.fields\" [ngClass]=\"['form-col', field.class || 'col-12']\"\r\n [hidden]=\"!isFieldVisible(field)\">\r\n <!-- Pass the root form group to the template -->\r\n <ng-container\r\n *ngTemplateOutlet=\"fieldTemplate; context: {field: field, group: form}\"></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n </ng-container>\r\n\r\n <div class=\"btn-row\">\r\n <button mat-stroked-button type=\"button\" (click)=\"onCancel()\" *ngIf=\"processedConfig?.cancelLabel\">{{\r\n processedConfig.cancelLabel\r\n }}</button>\r\n <button mat-stroked-button type=\"button\" *ngIf=\"processedConfig?.saveDraftLabel\">{{\r\n processedConfig.saveDraftLabel }}</button>\r\n <button mat-flat-button color=\"primary\" type=\"submit\">{{ processedConfig?.submitLabel || 'Submit' }}</button>\r\n </div>\r\n\r\n</form>\r\n\r\n<!-- Reusable Field Template -->\r\n<ng-template #fieldTemplate let-field=\"field\" let-group=\"group\">\r\n <div [formGroup]=\"group\">\r\n\r\n <!-- Text / Email / Number / Tel / Password / URL -->\r\n <div *ngIf=\"['text', 'email', 'number', 'tel', 'password', 'url'].includes(field.type || '')\"\r\n class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"field.type\" [formControlName]=\"field.name\" [placeholder]=\"field.placeholder || ''\"\r\n [readonly]=\"field.readonly\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\">\r\n <div class=\"input-suffix\">\r\n <span class=\"suffix-text\" *ngIf=\"field.suffixText\">{{ field.suffixText }}</span>\r\n <mat-icon *ngIf=\"field.suffixIcon\">{{ field.suffixIcon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.icon\">{{ field.icon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n </div>\r\n </div>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Textarea -->\r\n <div *ngIf=\"field.type === 'textarea'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <textarea [formControlName]=\"field.name\" [placeholder]=\"field.placeholder || ''\" [readonly]=\"field.readonly\"\r\n class=\"form-input form-textarea\" rows=\"4\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\"></textarea>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Select / Dropdown -->\r\n <div *ngIf=\"field.type === 'select' || field.type === 'dropdown'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <select [formControlName]=\"field.name\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <option value=\"\" disabled selected *ngIf=\"field.placeholder\">{{ field.placeholder }}</option>\r\n <option value=\"\" disabled selected *ngIf=\"!field.placeholder\">Select</option>\r\n <option *ngFor=\"let opt of getFieldOptions(field)\" [value]=\"opt.value\">{{ opt.label }}</option>\r\n </select>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Date -->\r\n <div *ngIf=\"field.type === 'date'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"relative\">\r\n <input matInput [matDatepicker]=\"picker\" [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder || ''\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <mat-datepicker-toggle matSuffix [for]=\"picker\" class=\"date-toggle\"></mat-datepicker-toggle>\r\n <mat-datepicker #picker></mat-datepicker>\r\n </div>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Radio -->\r\n <div *ngIf=\"field.type === 'radio'\" class=\"radio-group-container\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <label class=\"field-label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </label>\r\n <mat-radio-group [formControlName]=\"field.name\" class=\"radio-group\">\r\n <mat-radio-button *ngFor=\"let opt of getFieldOptions(field)\" [value]=\"opt.value\" class=\"radio-button\">\r\n {{ opt.label }}\r\n </mat-radio-button>\r\n </mat-radio-group>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Composite Field (Sub-groups) -->\r\n <div *ngIf=\"field.type === 'composite'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"composite-container\">\r\n <ng-container *ngFor=\"let sub of field.subFields; let last = last\">\r\n <div class=\"composite-sub-field\" style=\"flex: 1;\">\r\n <div class=\"field-label\" *ngIf=\"sub.label\"\r\n style=\"font-size: 0.75rem; font-weight: normal; margin-bottom: 0.25rem;\">\r\n {{ sub.label }}\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"sub.type\" [formControlName]=\"sub.name\" [placeholder]=\"sub.placeholder || ''\"\r\n [readonly]=\"sub.readonly\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(sub.name)?.touched && group.get(sub.name)?.invalid\">\r\n <div class=\"input-suffix\" [class.color-suffix]=\"sub.suffixText === '%'\">\r\n <span class=\"suffix-text\" *ngIf=\"sub.suffixText\">{{ sub.suffixText }}</span>\r\n <mat-icon *ngIf=\"sub.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <!-- Adjust separator alignment if labels are present -->\r\n <span class=\"separator\" *ngIf=\"!last && field.separator\"\r\n [style.padding-top]=\"sub.label ? '1.25rem' : '0'\">{{ field.separator }}</span>\r\n </ng-container>\r\n </div>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"error-text text-danger text-small mt-1\" *ngIf=\"group.errors?.['invalid_minMax_' + field.name]\">\r\n Min value cannot be greater than Max value.\r\n </div>\r\n <div class=\"error-text text-danger text-small mt-1\"\r\n *ngIf=\"group.errors?.['invalid_percentageTotal_' + field.name]\">\r\n Total percentage must be 100%.\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- File Upload -->\r\n <div *ngIf=\"field.type === 'file'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n\r\n <!-- Upload Box -->\r\n <div class=\"upload-box\" (click)=\"fileInput.click()\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n *ngIf=\"!field.uploadedFiles || field.uploadedFiles.length === 0 || field.multiple\">\r\n <mat-icon class=\"upload-icon\">cloud_upload</mat-icon>\r\n <div class=\"upload-text\">Click to upload File</div>\r\n <div class=\"upload-hint\">PDF, DOCX, JPG, PNG (Max 5MB)</div>\r\n <input #fileInput type=\"file\" [attr.multiple]=\"field.multiple ? true : null\" [attr.accept]=\"field.accept\"\r\n (change)=\"onFileChange($event, field)\" style=\"display: none;\">\r\n </div>\r\n\r\n <!-- Uploaded Files List -->\r\n <div class=\"uploaded-files-list\" *ngIf=\"field.uploadedFiles && field.uploadedFiles.length > 0\">\r\n <div class=\"uploaded-file-item\" *ngFor=\"let file of field.uploadedFiles; let i = index\">\r\n <div class=\"file-icon\">\r\n <mat-icon class=\"pdf-icon\" *ngIf=\"file.type === 'application/pdf'\">picture_as_pdf</mat-icon>\r\n <mat-icon class=\"doc-icon\"\r\n *ngIf=\"file.type.includes('word') || file.type.includes('document')\">description</mat-icon>\r\n <mat-icon class=\"img-icon\" *ngIf=\"file.type.includes('image')\">image</mat-icon>\r\n <mat-icon class=\"file-icon-default\"\r\n *ngIf=\"!file.type.includes('pdf') && !file.type.includes('word') && !file.type.includes('document') && !file.type.includes('image')\">insert_drive_file</mat-icon>\r\n </div>\r\n <div class=\"file-info\">\r\n <div class=\"file-name\">{{ file.name }}</div>\r\n <div class=\"file-size\">{{ (file.size / 1024).toFixed(2) }} KB</div>\r\n </div>\r\n <button mat-icon-button color=\"warn\" type=\"button\" (click)=\"removeFile(field, i)\"\r\n class=\"remove-file-btn\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n</ng-template>", styles: [":host{display:block;width:100%}.configurable-form-container{padding:0;font-family:var(--cf-font-family, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif)}.configurable-form-container .section-card{background:var(--cf-surface-background, #ffffff);border:1px solid var(--cf-border-color, #D1D5DB);border-radius:var(--cf-section-radius, 12px);padding:var(--cf-section-padding, 2rem);margin-bottom:var(--cf-section-spacing, 1.5rem);box-shadow:var(--cf-section-shadow, 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06))}.configurable-form-container .section-card:last-of-type{margin-bottom:0}.configurable-form-container .section-no-card{margin-bottom:var(--cf-section-spacing, 1.5rem)}.configurable-form-container .section-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--cf-section-spacing, 1.5rem);padding-bottom:1rem;border-bottom:2px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .section-title{font-size:var(--cf-section-title-size, 1.25rem);font-weight:var(--cf-section-title-weight, 600);color:var(--cf-text-primary, #111827);margin:0;letter-spacing:-.025em}.configurable-form-container .form-grid{display:flex;flex-wrap:wrap;margin-left:-.625rem;margin-right:-.625rem}.configurable-form-container .form-col{position:relative;width:100%;padding-left:.625rem;padding-right:.625rem;margin-bottom:1.25rem}.configurable-form-container .col-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.configurable-form-container .col-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.configurable-form-container .col-3{flex:0 0 25%;max-width:25%}.configurable-form-container .col-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.configurable-form-container .col-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.configurable-form-container .col-6{flex:0 0 50%;max-width:50%}.configurable-form-container .col-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.configurable-form-container .col-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.configurable-form-container .col-9{flex:0 0 75%;max-width:75%}.configurable-form-container .col-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.configurable-form-container .col-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.configurable-form-container .col-12{flex:0 0 100%;max-width:100%}@media(min-width:769px){.configurable-form-container .col-md-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.configurable-form-container .col-md-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.configurable-form-container .col-md-3{flex:0 0 25%;max-width:25%}.configurable-form-container .col-md-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.configurable-form-container .col-md-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.configurable-form-container .col-md-6{flex:0 0 50%;max-width:50%}.configurable-form-container .col-md-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.configurable-form-container .col-md-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.configurable-form-container .col-md-9{flex:0 0 75%;max-width:75%}.configurable-form-container .col-md-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.configurable-form-container .col-md-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.configurable-form-container .col-md-12{flex:0 0 100%;max-width:100%}}.configurable-form-container .field-container{margin-bottom:0}.configurable-form-container .field-label{display:block;font-size:var(--cf-label-size, .875rem);font-weight:var(--cf-label-weight, 600);color:var(--cf-text-primary, #111827);margin-bottom:.5rem;line-height:1.25rem}.configurable-form-container .field-label .text-danger{color:var(--cf-error-color, #DC2626);margin-left:.125rem}.configurable-form-container .input-wrapper{position:relative;display:flex;align-items:center}.configurable-form-container .form-input{width:100%;padding:var(--cf-input-padding-y, .625rem) var(--cf-input-padding-x, .875rem);font-size:var(--cf-input-font-size, .875rem);line-height:1.5;color:var(--cf-text-primary, #111827);background-color:var(--cf-input-bg, #ffffff);border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:var(--cf-input-radius, 8px);transition:all .2s ease;font-family:inherit}.configurable-form-container .form-input:hover:not(:disabled):not([readonly]){border-color:var(--cf-input-hover-border-color, #9CA3AF)}.configurable-form-container .form-input:focus{outline:none;border-color:var(--cf-primary-color, #3B82F6);box-shadow:0 0 0 3px #3b82f61a}.configurable-form-container .form-input::placeholder{color:#9ca3af}.configurable-form-container .form-input:disabled,.configurable-form-container .form-input[readonly]{background-color:var(--cf-disabled-background, #F3F4F6);color:var(--cf-text-secondary, #6B7280);cursor:not-allowed;border-color:#e5e7eb}.configurable-form-container .form-input.is-invalid{border-color:var(--cf-error-color, #DC2626);background-color:#fef2f2}.configurable-form-container .form-input.is-invalid:focus{box-shadow:0 0 0 3px #dc26261a}.configurable-form-container select.form-input{appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E\");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;cursor:pointer}.configurable-form-container select.form-input:disabled{cursor:not-allowed}.configurable-form-container .form-textarea{resize:vertical;min-height:100px;font-family:inherit}.configurable-form-container .input-suffix{position:absolute;right:.75rem;display:flex;align-items:center;gap:.5rem;pointer-events:none}.configurable-form-container .input-suffix .suffix-text{font-size:.875rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .input-suffix mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .input-suffix .lock-icon{color:#9ca3af}.configurable-form-container .input-suffix.color-suffix .suffix-text{color:var(--cf-primary-color, #3B82F6);font-weight:600}.configurable-form-container .char-count-row{display:flex;justify-content:space-between;align-items:center;margin-top:.5rem}.configurable-form-container .char-count{font-size:.75rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .hint-text{font-size:var(--cf-hint-size, .75rem);color:var(--cf-text-secondary, #6B7280);margin-top:.375rem;line-height:1.25rem}.configurable-form-container .mt-2{margin-top:.5rem}.configurable-form-container .radio-group-container.is-invalid .field-label{color:var(--cf-error-color, #DC2626)}.configurable-form-container .radio-group{display:flex;gap:2rem;flex-wrap:wrap;margin-top:.5rem}.configurable-form-container .radio-button{margin:0}.configurable-form-container .composite-container{display:flex;align-items:center;gap:.75rem}.configurable-form-container .composite-container .separator{font-size:.875rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .composite-container .input-wrapper{flex:1}.configurable-form-container .upload-box{border:2px dashed var(--cf-border-color, #D1D5DB);border-radius:var(--cf-section-radius, 12px);padding:2.5rem;text-align:center;cursor:pointer;transition:all .2s ease;background-color:var(--cf-hover-background, #F9FAFB)}.configurable-form-container .upload-box:hover{border-color:var(--cf-primary-color, #3B82F6);background-color:#3b82f608}.configurable-form-container .upload-box.is-invalid{border-color:var(--cf-error-color, #DC2626);background-color:#fef2f2}.configurable-form-container .upload-box .upload-icon{font-size:3rem;width:3rem;height:3rem;color:var(--cf-primary-color, #3B82F6);margin-bottom:.75rem}.configurable-form-container .upload-box .upload-text{font-size:.875rem;color:var(--cf-text-primary, #111827);font-weight:500;margin-bottom:.375rem}.configurable-form-container .upload-box .upload-hint{font-size:.75rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-files-list{margin-top:1rem}.configurable-form-container .uploaded-file-item{display:flex;align-items:center;gap:.75rem;padding:.875rem;border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:8px;margin-bottom:.5rem;background-color:var(--cf-hover-background, #F9FAFB);transition:all .2s ease}.configurable-form-container .uploaded-file-item:hover{border-color:#9ca3af;box-shadow:0 1px 3px #0000001a}.configurable-form-container .uploaded-file-item .file-icon mat-icon{font-size:2rem;width:2rem;height:2rem}.configurable-form-container .uploaded-file-item .file-icon mat-icon.pdf-icon{color:#dc2626}.configurable-form-container .uploaded-file-item .file-icon mat-icon.doc-icon{color:#2563eb}.configurable-form-container .uploaded-file-item .file-icon mat-icon.img-icon{color:#059669}.configurable-form-container .uploaded-file-item .file-icon mat-icon.file-icon-default{color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-file-item .file-info{flex:1}.configurable-form-container .uploaded-file-item .file-info .file-name{font-size:.875rem;color:var(--cf-text-primary, #111827);font-weight:500;margin-bottom:.125rem}.configurable-form-container .uploaded-file-item .file-info .file-size{font-size:.75rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-file-item .remove-file-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem}.configurable-form-container .relative{position:relative}.configurable-form-container .date-toggle{position:absolute;right:0;top:50%;transform:translateY(-50%)}.configurable-form-container .repeater-item{padding:1.5rem;border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:10px;margin-bottom:1rem;background-color:var(--cf-hover-background, #F9FAFB);transition:all .2s ease}.configurable-form-container .repeater-item:hover{border-color:#9ca3af;box-shadow:0 2px 4px #0000000d}.configurable-form-container .repeater-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.25rem;padding-bottom:.75rem;border-bottom:1.5px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .repeater-item-header .text-small{font-size:.875rem;font-weight:600;color:var(--cf-text-primary, #111827);text-transform:uppercase;letter-spacing:.025em}.configurable-form-container .repeater-separator{height:1px;background-color:var(--cf-border-color, #D1D5DB);margin:1.5rem 0}.configurable-form-container .add-btn{margin-top:1rem;display:inline-flex;align-items:center;gap:.5rem;padding:.625rem 1.25rem;background-color:transparent;color:var(--cf-primary-color, #3B82F6);border:1.5px solid var(--cf-primary-color, #3B82F6);border-radius:8px;font-size:.875rem;font-weight:600;cursor:pointer;transition:all .2s ease}.configurable-form-container .add-btn:hover:not(:disabled){background-color:var(--cf-primary-color, #3B82F6);color:#fff}.configurable-form-container .add-btn:disabled{opacity:.5;cursor:not-allowed;border-color:var(--cf-disabled-background, #E5E7EB)}.configurable-form-container .add-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem}.configurable-form-container .btn-row{display:flex;justify-content:flex-end;gap:1rem;margin-top:2rem;padding-top:1.5rem;border-top:2px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .btn-row button{padding:.625rem 1.5rem;font-size:.875rem;font-weight:600;border-radius:8px;cursor:pointer;transition:all .2s ease;border:none;font-family:inherit}.configurable-form-container .btn-row button[mat-stroked-button]{background-color:transparent;color:var(--cf-text-primary, #111827);border:1.5px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .btn-row button[mat-stroked-button]:hover{background-color:var(--cf-hover-background, #F9FAFB);border-color:#9ca3af}.configurable-form-container .btn-row button[mat-flat-button]{background-color:var(--cf-primary-color, #3B82F6);color:#fff;box-shadow:0 1px 3px #0000001a}.configurable-form-container .btn-row button[mat-flat-button]:hover{background-color:#2563eb;box-shadow:0 4px 6px -1px #0000001a}.configurable-form-container .btn-row button[mat-flat-button]:active{background-color:#1d4ed8}@media(max-width:768px){.configurable-form-container .section-card{padding:1.25rem;border-radius:8px}.configurable-form-container .form-grid{margin-left:-.5rem;margin-right:-.5rem}.configurable-form-container .form-col{padding-left:.5rem;padding-right:.5rem;margin-bottom:1rem}.configurable-form-container .btn-row{flex-direction:column-reverse}.configurable-form-container .btn-row button{width:100%}.configurable-form-container .radio-group{flex-direction:column;gap:.75rem}.configurable-form-container .composite-container{flex-direction:column;align-items:stretch}.configurable-form-container .composite-container .separator{text-align:center}}\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.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.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: i1$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: MaterialModule }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i6.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i6.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: i7$1.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i7$1.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: i7$1.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "directive", type: i8$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i7.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i7.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }] });
3449
+ togglePassword(fieldName) {
3450
+ this.passwordFieldState.set(fieldName, !this.passwordFieldState.get(fieldName));
3451
+ }
3452
+ isPasswordVisible(fieldName) {
3453
+ return this.passwordFieldState.get(fieldName) || false;
3454
+ }
3455
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigurableFormComponent, deps: [{ token: i1$2.FormBuilder }, { token: i2$2.MatSnackBar }, { token: i3.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
3456
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ConfigurableFormComponent, isStandalone: true, selector: "lib-configurable-form", inputs: { config: "config", jsonConfig: "jsonConfig", data: "data", baseApiUrl: "baseApiUrl" }, outputs: { optionsLoad: "optionsLoad" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\" class=\"configurable-form-container\" *ngIf=\"form\">\r\n\r\n <ng-container *ngFor=\"let section of sections\">\r\n\r\n <!-- Repeater Section -->\r\n <div *ngIf=\"section.isRepeater; else normalSection\"\r\n [ngClass]=\"section.noCardLayout ? 'section-no-card' : 'section-card'\">\r\n <div class=\"section-header\" *ngIf=\"section.sectionTitle\">\r\n <h3 class=\"section-title\">{{ section.sectionTitle }}</h3>\r\n <button *ngIf=\"section.collapsible\" mat-icon-button type=\"button\" (click)=\"toggleSection(section)\">\r\n <mat-icon>{{ section.collapsed ? 'expand_more' : 'expand_less' }}</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div [formArrayName]=\"section.formArrayName || 'items'\" *ngIf=\"!section.collapsed\">\r\n <div *ngFor=\"let item of getFormArray(section.formArrayName!).controls; let i = index\"\r\n [formGroupName]=\"i\" class=\"repeater-item\">\r\n <div class=\"repeater-item-header\" *ngIf=\"getFormArray(section.formArrayName!).length > 1\">\r\n <span class=\"text-small\">{{ section.repeaterItemLabel || 'Item' }} {{i + 1}}</span>\r\n <button mat-icon-button color=\"warn\" type=\"button\"\r\n (click)=\"removeRepeaterItem(section.formArrayName!, i)\"\r\n [disabled]=\"section.minItems && getFormArray(section.formArrayName!).length <= section.minItems\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Fields Grid -->\r\n <div class=\"form-grid\">\r\n <div *ngFor=\"let field of section.fields\" [ngClass]=\"['form-col', field.class || 'col-12']\"\r\n [hidden]=\"!isFieldVisible(field)\">\r\n <ng-container\r\n *ngTemplateOutlet=\"fieldTemplate; context: {field: field, group: item}\"></ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"repeater-separator\" *ngIf=\"i < getFormArray(section.formArrayName!).length - 1\"></div>\r\n </div>\r\n </div>\r\n\r\n <button mat-button color=\"primary\" type=\"button\" (click)=\"addRepeaterItem(section)\" class=\"add-btn\"\r\n *ngIf=\"!section.collapsed\"\r\n [disabled]=\"section.maxItems && getFormArray(section.formArrayName!).length >= section.maxItems\">\r\n <mat-icon>add_circle_outline</mat-icon> {{ section.addLabel || 'Add More' }}\r\n </button>\r\n </div>\r\n\r\n <!-- Normal Section -->\r\n <ng-template #normalSection>\r\n <div [ngClass]=\"section.noCardLayout ? 'section-no-card' : 'section-card'\">\r\n <div class=\"section-header\" *ngIf=\"section.sectionTitle\">\r\n <h3 class=\"section-title\">{{ section.sectionTitle }}</h3>\r\n <button *ngIf=\"section.collapsible\" mat-icon-button type=\"button\" (click)=\"toggleSection(section)\">\r\n <mat-icon>{{ section.collapsed ? 'expand_more' : 'expand_less' }}</mat-icon>\r\n </button>\r\n </div>\r\n <div class=\"form-grid\" *ngIf=\"!section.collapsed\">\r\n <div *ngFor=\"let field of section.fields\" [ngClass]=\"['form-col', field.class || 'col-12']\"\r\n [hidden]=\"!isFieldVisible(field)\">\r\n <!-- Pass the root form group to the template -->\r\n <ng-container\r\n *ngTemplateOutlet=\"fieldTemplate; context: {field: field, group: form}\"></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n </ng-container>\r\n\r\n</form>\r\n\r\n<!-- Reusable Field Template -->\r\n<ng-template #fieldTemplate let-field=\"field\" let-group=\"group\">\r\n <div [formGroup]=\"group\">\r\n\r\n <!-- Text / Email / Number / Tel / URL (Password removed) -->\r\n <div *ngIf=\"['text', 'email', 'number', 'tel', 'url'].includes(field.type || '')\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"field.type\" [formControlName]=\"field.name\" [placeholder]=\"field.placeholder || ''\"\r\n [readonly]=\"field.readonly\" class=\"form-input\" [name]=\"field.name\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\">\r\n <div class=\"input-suffix\">\r\n <span class=\"suffix-text\" *ngIf=\"field.suffixText\">{{ field.suffixText }}</span>\r\n <mat-icon *ngIf=\"field.suffixIcon\">{{ field.suffixIcon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.icon\">{{ field.icon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n </div>\r\n </div>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Password Field (Separated) -->\r\n <div *ngIf=\"field.type === 'password'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"isPasswordVisible(field.name) ? 'text' : 'password'\" [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder || ''\" [readonly]=\"field.readonly\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\">\r\n <div class=\"input-suffix\">\r\n <span class=\"suffix-text\" *ngIf=\"field.suffixText\">{{ field.suffixText }}</span>\r\n <mat-icon *ngIf=\"field.suffixIcon\">{{ field.suffixIcon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.icon\">{{ field.icon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n <mat-icon class=\"password-toggle-icon\" (click)=\"togglePassword(field.name)\">\r\n {{ isPasswordVisible(field.name) ? 'visibility' : 'visibility_off' }}\r\n </mat-icon>\r\n </div>\r\n </div>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Textarea -->\r\n <div *ngIf=\"field.type === 'textarea'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <textarea [formControlName]=\"field.name\" [placeholder]=\"field.placeholder || ''\" [readonly]=\"field.readonly\"\r\n class=\"form-input form-textarea\" rows=\"4\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\"></textarea>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Select / Dropdown -->\r\n <div *ngIf=\"field.type === 'select' || field.type === 'dropdown'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <select [formControlName]=\"field.name\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <option value=\"\" disabled selected *ngIf=\"field.placeholder\">{{ field.placeholder }}</option>\r\n <option value=\"\" disabled selected *ngIf=\"!field.placeholder\">Select</option>\r\n <option *ngFor=\"let opt of getFieldOptions(field)\" [value]=\"opt.value\">{{ opt.label }}</option>\r\n </select>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Date -->\r\n <div *ngIf=\"field.type === 'date'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"relative\">\r\n <input matInput [matDatepicker]=\"picker\" [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder || ''\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <mat-datepicker-toggle matSuffix [for]=\"picker\" class=\"date-toggle\"></mat-datepicker-toggle>\r\n <mat-datepicker #picker></mat-datepicker>\r\n </div>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Radio -->\r\n <div *ngIf=\"field.type === 'radio'\" class=\"radio-group-container\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <label class=\"field-label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </label>\r\n <mat-radio-group [formControlName]=\"field.name\" class=\"radio-group\">\r\n <mat-radio-button *ngFor=\"let opt of getFieldOptions(field)\" [value]=\"opt.value\" class=\"radio-button\">\r\n {{ opt.label }}\r\n </mat-radio-button>\r\n </mat-radio-group>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Composite Field (Sub-groups) -->\r\n <div *ngIf=\"field.type === 'composite'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"composite-container\">\r\n <ng-container *ngFor=\"let sub of field.subFields; let last = last\">\r\n <div class=\"composite-sub-field\" style=\"flex: 1;\">\r\n <div class=\"field-label\" *ngIf=\"sub.label\"\r\n style=\"font-size: 0.75rem; font-weight: normal; margin-bottom: 0.25rem;\">\r\n {{ sub.label }}\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"sub.type\" [formControlName]=\"sub.name\" [placeholder]=\"sub.placeholder || ''\"\r\n [readonly]=\"sub.readonly\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(sub.name)?.touched && group.get(sub.name)?.invalid\">\r\n <div class=\"input-suffix\" [class.color-suffix]=\"sub.suffixText === '%'\">\r\n <span class=\"suffix-text\" *ngIf=\"sub.suffixText\">{{ sub.suffixText }}</span>\r\n <mat-icon *ngIf=\"sub.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <!-- Adjust separator alignment if labels are present -->\r\n <span class=\"separator\" *ngIf=\"!last && field.separator\"\r\n [style.padding-top]=\"sub.label ? '1.25rem' : '0'\">{{ field.separator }}</span>\r\n </ng-container>\r\n </div>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"error-text text-danger text-small mt-1\" *ngIf=\"group.errors?.['invalid_minMax_' + field.name]\">\r\n Min value cannot be greater than Max value.\r\n </div>\r\n <div class=\"error-text text-danger text-small mt-1\"\r\n *ngIf=\"group.errors?.['invalid_percentageTotal_' + field.name]\">\r\n Total percentage must be 100%.\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- File Upload -->\r\n <div *ngIf=\"field.type === 'file'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n\r\n <!-- Upload Box -->\r\n <div class=\"upload-box\" (click)=\"fileInput.click()\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n *ngIf=\"!field.uploadedFiles || field.uploadedFiles.length === 0 || field.multiple\">\r\n <mat-icon class=\"upload-icon\">cloud_upload</mat-icon>\r\n <div class=\"upload-text\">Click to upload File</div>\r\n <div class=\"upload-hint\">PDF, DOCX, JPG, PNG (Max 5MB)</div>\r\n <input #fileInput type=\"file\" [attr.multiple]=\"field.multiple ? true : null\" [attr.accept]=\"field.accept\"\r\n (change)=\"onFileChange($event, field)\" style=\"display: none;\">\r\n </div>\r\n\r\n <!-- Uploaded Files List -->\r\n <div class=\"uploaded-files-list\" *ngIf=\"field.uploadedFiles && field.uploadedFiles.length > 0\">\r\n <div class=\"uploaded-file-item\" *ngFor=\"let file of field.uploadedFiles; let i = index\">\r\n <div class=\"file-icon\">\r\n <mat-icon class=\"pdf-icon\" *ngIf=\"file.type === 'application/pdf'\">picture_as_pdf</mat-icon>\r\n <mat-icon class=\"doc-icon\"\r\n *ngIf=\"file.type.includes('word') || file.type.includes('document')\">description</mat-icon>\r\n <mat-icon class=\"img-icon\" *ngIf=\"file.type.includes('image')\">image</mat-icon>\r\n <mat-icon class=\"file-icon-default\"\r\n *ngIf=\"!file.type.includes('pdf') && !file.type.includes('word') && !file.type.includes('document') && !file.type.includes('image')\">insert_drive_file</mat-icon>\r\n </div>\r\n <div class=\"file-info\">\r\n <div class=\"file-name\">{{ file.name }}</div>\r\n <div class=\"file-size\">{{ (file.size / 1024).toFixed(2) }} KB</div>\r\n </div>\r\n <button mat-icon-button color=\"warn\" type=\"button\" (click)=\"removeFile(field, i)\"\r\n class=\"remove-file-btn\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n</ng-template>", styles: [":host{display:block;width:100%}.configurable-form-container{padding:0;font-family:var(--cf-font-family, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif)}.configurable-form-container .section-card{background:var(--cf-surface-background, #ffffff);border:1px solid var(--cf-border-color, #D1D5DB);border-radius:var(--cf-section-radius, 12px);padding:var(--cf-section-padding, 2rem);margin-bottom:var(--cf-section-spacing, 1.5rem);box-shadow:var(--cf-section-shadow, 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06))}.configurable-form-container .section-card:last-of-type{margin-bottom:0}.configurable-form-container .section-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--cf-section-spacing, 1.5rem);padding-bottom:1rem;border-bottom:2px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .section-title{font-size:var(--cf-section-title-size, 1.25rem);font-weight:var(--cf-section-title-weight, 600);color:var(--cf-text-primary, #111827);margin:0;letter-spacing:-.025em}.configurable-form-container .form-grid{display:flex;flex-wrap:wrap;margin-left:-.625rem;margin-right:-.625rem}.configurable-form-container .form-col{position:relative;width:100%;padding-left:.625rem;padding-right:.625rem;margin-bottom:1.25rem}.configurable-form-container .col-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.configurable-form-container .col-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.configurable-form-container .col-3{flex:0 0 25%;max-width:25%}.configurable-form-container .col-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.configurable-form-container .col-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.configurable-form-container .col-6{flex:0 0 50%;max-width:50%}.configurable-form-container .col-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.configurable-form-container .col-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.configurable-form-container .col-9{flex:0 0 75%;max-width:75%}.configurable-form-container .col-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.configurable-form-container .col-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.configurable-form-container .col-12{flex:0 0 100%;max-width:100%}@media(min-width:769px){.configurable-form-container .col-md-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.configurable-form-container .col-md-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.configurable-form-container .col-md-3{flex:0 0 25%;max-width:25%}.configurable-form-container .col-md-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.configurable-form-container .col-md-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.configurable-form-container .col-md-6{flex:0 0 50%;max-width:50%}.configurable-form-container .col-md-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.configurable-form-container .col-md-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.configurable-form-container .col-md-9{flex:0 0 75%;max-width:75%}.configurable-form-container .col-md-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.configurable-form-container .col-md-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.configurable-form-container .col-md-12{flex:0 0 100%;max-width:100%}}.configurable-form-container .field-container{margin-bottom:0}.configurable-form-container .field-label{display:block;font-size:var(--cf-label-size, .875rem);font-weight:var(--cf-label-weight, 600);color:var(--cf-text-primary, #111827);margin-bottom:.5rem;line-height:1.25rem}.configurable-form-container .field-label .text-danger{color:var(--cf-error-color, #DC2626);margin-left:.125rem}.configurable-form-container .input-wrapper{position:relative;display:flex;align-items:center}.configurable-form-container .form-input{width:100%;padding:var(--cf-input-padding-y, .625rem) var(--cf-input-padding-x, .875rem);font-size:var(--cf-input-font-size, .875rem);line-height:1.5;color:var(--cf-text-primary, #111827);background-color:var(--cf-input-bg, #ffffff);border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:var(--cf-input-radius, 8px);transition:all .2s ease;font-family:inherit}.configurable-form-container .form-input:hover:not(:disabled):not([readonly]){border-color:var(--cf-input-hover-border-color, #9CA3AF)}.configurable-form-container .form-input:focus{outline:none;border-color:var(--cf-primary-color, #3B82F6);box-shadow:0 0 0 3px #3b82f61a}.configurable-form-container .form-input::placeholder{color:#9ca3af}.configurable-form-container .form-input:disabled,.configurable-form-container .form-input[readonly]{background-color:var(--cf-disabled-background, #F3F4F6);color:var(--cf-text-secondary, #6B7280);cursor:not-allowed;border-color:#e5e7eb}.configurable-form-container .form-input.is-invalid{border-color:var(--cf-error-color, #DC2626);background-color:#fef2f2}.configurable-form-container .form-input.is-invalid:focus{box-shadow:0 0 0 3px #dc26261a}.configurable-form-container select.form-input{appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E\");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;cursor:pointer}.configurable-form-container select.form-input:disabled{cursor:not-allowed}.configurable-form-container .form-textarea{resize:vertical;min-height:100px;font-family:inherit}.configurable-form-container .input-suffix{position:absolute;right:.75rem;display:flex;align-items:center;gap:.5rem;pointer-events:none}.configurable-form-container .input-suffix .password-toggle-icon{pointer-events:auto;cursor:pointer}.configurable-form-container .input-suffix .password-toggle-icon:hover{color:var(--cf-text-primary, #111827)}.configurable-form-container .input-suffix .suffix-text{font-size:.875rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .input-suffix mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .input-suffix .lock-icon{color:#9ca3af}.configurable-form-container .input-suffix.color-suffix .suffix-text{color:var(--cf-primary-color, #3B82F6);font-weight:600}.configurable-form-container .char-count-row{display:flex;justify-content:space-between;align-items:center;margin-top:.5rem}.configurable-form-container .char-count{font-size:.75rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .hint-text{font-size:var(--cf-hint-size, .75rem);color:var(--cf-text-secondary, #6B7280);margin-top:.375rem;line-height:1.25rem}.configurable-form-container .mt-2{margin-top:.5rem}.configurable-form-container .radio-group-container.is-invalid .field-label{color:var(--cf-error-color, #DC2626)}.configurable-form-container .radio-group{display:flex;gap:2rem;flex-wrap:wrap;margin-top:.5rem}.configurable-form-container .radio-button{margin:0}.configurable-form-container .composite-container{display:flex;align-items:center;gap:.75rem}.configurable-form-container .composite-container .separator{font-size:.875rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .composite-container .input-wrapper{flex:1}.configurable-form-container .upload-box{border:2px dashed var(--cf-border-color, #D1D5DB);border-radius:var(--cf-section-radius, 12px);padding:2.5rem;text-align:center;cursor:pointer;transition:all .2s ease;background-color:var(--cf-hover-background, #F9FAFB)}.configurable-form-container .upload-box:hover{border-color:var(--cf-primary-color, #3B82F6);background-color:#3b82f608}.configurable-form-container .upload-box.is-invalid{border-color:var(--cf-error-color, #DC2626);background-color:#fef2f2}.configurable-form-container .upload-box .upload-icon{font-size:3rem;width:3rem;height:3rem;color:var(--cf-primary-color, #3B82F6);margin-bottom:.75rem}.configurable-form-container .upload-box .upload-text{font-size:.875rem;color:var(--cf-text-primary, #111827);font-weight:500;margin-bottom:.375rem}.configurable-form-container .upload-box .upload-hint{font-size:.75rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-files-list{margin-top:1rem}.configurable-form-container .uploaded-file-item{display:flex;align-items:center;gap:.75rem;padding:.875rem;border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:8px;margin-bottom:.5rem;background-color:var(--cf-hover-background, #F9FAFB);transition:all .2s ease}.configurable-form-container .uploaded-file-item:hover{border-color:#9ca3af;box-shadow:0 1px 3px #0000001a}.configurable-form-container .uploaded-file-item .file-icon mat-icon{font-size:2rem;width:2rem;height:2rem}.configurable-form-container .uploaded-file-item .file-icon mat-icon.pdf-icon{color:#dc2626}.configurable-form-container .uploaded-file-item .file-icon mat-icon.doc-icon{color:#2563eb}.configurable-form-container .uploaded-file-item .file-icon mat-icon.img-icon{color:#059669}.configurable-form-container .uploaded-file-item .file-icon mat-icon.file-icon-default{color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-file-item .file-info{flex:1}.configurable-form-container .uploaded-file-item .file-info .file-name{font-size:.875rem;color:var(--cf-text-primary, #111827);font-weight:500;margin-bottom:.125rem}.configurable-form-container .uploaded-file-item .file-info .file-size{font-size:.75rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-file-item .remove-file-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem}.configurable-form-container .relative{position:relative}.configurable-form-container .date-toggle{position:absolute;right:0;top:50%;transform:translateY(-50%)}.configurable-form-container .repeater-item{padding:1.5rem;border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:10px;margin-bottom:1rem;background-color:var(--cf-hover-background, #F9FAFB);transition:all .2s ease}.configurable-form-container .repeater-item:hover{border-color:#9ca3af;box-shadow:0 2px 4px #0000000d}.configurable-form-container .repeater-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.25rem;padding-bottom:.75rem;border-bottom:1.5px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .repeater-item-header .text-small{font-size:.875rem;font-weight:600;color:var(--cf-text-primary, #111827);text-transform:uppercase;letter-spacing:.025em}.configurable-form-container .repeater-separator{height:1px;background-color:var(--cf-border-color, #D1D5DB);margin:1.5rem 0}.configurable-form-container .add-btn{margin-top:1rem;display:inline-flex;align-items:center;gap:.5rem;padding:.625rem 1.25rem;background-color:transparent;color:var(--cf-primary-color, #3B82F6);border:1.5px solid var(--cf-primary-color, #3B82F6);border-radius:8px;font-size:.875rem;font-weight:600;cursor:pointer;transition:all .2s ease}.configurable-form-container .add-btn:hover:not(:disabled){background-color:var(--cf-primary-color, #3B82F6);color:#fff}.configurable-form-container .add-btn:disabled{opacity:.5;cursor:not-allowed;border-color:var(--cf-disabled-background, #E5E7EB)}.configurable-form-container .add-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem}@media(max-width:768px){.configurable-form-container .section-card{padding:1.25rem;border-radius:8px}.configurable-form-container .form-grid{margin-left:-.5rem;margin-right:-.5rem}.configurable-form-container .form-col{padding-left:.5rem;padding-right:.5rem;margin-bottom:1rem}.configurable-form-container .radio-group{flex-direction:column;gap:.75rem}.configurable-form-container .composite-container{flex-direction:column;align-items:stretch}.configurable-form-container .composite-container .separator{text-align:center}}\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.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.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: i1$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: MaterialModule }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i6.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i6.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: i7.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i7.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: i7.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "directive", type: i8.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i10.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i10.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }] });
1459
3457
  }
1460
3458
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigurableFormComponent, decorators: [{
1461
3459
  type: Component,
1462
- args: [{ selector: 'lib-configurable-form', standalone: true, imports: [CommonModule, ReactiveFormsModule, MaterialModule], template: "<form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\" class=\"configurable-form-container\" *ngIf=\"form\">\r\n\r\n <ng-container *ngFor=\"let section of sections\">\r\n\r\n <!-- Repeater Section -->\r\n <div *ngIf=\"section.isRepeater; else normalSection\"\r\n [ngClass]=\"section.noCardLayout ? 'section-no-card' : 'section-card'\">\r\n <div class=\"section-header\" *ngIf=\"section.sectionTitle\">\r\n <h3 class=\"section-title\">{{ section.sectionTitle }}</h3>\r\n <button *ngIf=\"section.collapsible\" mat-icon-button type=\"button\" (click)=\"toggleSection(section)\">\r\n <mat-icon>{{ section.collapsed ? 'expand_more' : 'expand_less' }}</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div [formArrayName]=\"section.formArrayName || 'items'\" *ngIf=\"!section.collapsed\">\r\n <div *ngFor=\"let item of getFormArray(section.formArrayName!).controls; let i = index\"\r\n [formGroupName]=\"i\" class=\"repeater-item\">\r\n <div class=\"repeater-item-header\" *ngIf=\"getFormArray(section.formArrayName!).length > 1\">\r\n <span class=\"text-small\">{{ section.repeaterItemLabel || 'Item' }} {{i + 1}}</span>\r\n <button mat-icon-button color=\"warn\" type=\"button\"\r\n (click)=\"removeRepeaterItem(section.formArrayName!, i)\"\r\n [disabled]=\"section.minItems && getFormArray(section.formArrayName!).length <= section.minItems\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Fields Grid -->\r\n <div class=\"form-grid\">\r\n <div *ngFor=\"let field of section.fields\" [ngClass]=\"['form-col', field.class || 'col-12']\"\r\n [hidden]=\"!isFieldVisible(field)\">\r\n <ng-container\r\n *ngTemplateOutlet=\"fieldTemplate; context: {field: field, group: item}\"></ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"repeater-separator\" *ngIf=\"i < getFormArray(section.formArrayName!).length - 1\"></div>\r\n </div>\r\n </div>\r\n\r\n <button mat-button color=\"primary\" type=\"button\" (click)=\"addRepeaterItem(section)\" class=\"add-btn\"\r\n *ngIf=\"!section.collapsed\"\r\n [disabled]=\"section.maxItems && getFormArray(section.formArrayName!).length >= section.maxItems\">\r\n <mat-icon>add_circle_outline</mat-icon> {{ section.addLabel || 'Add More' }}\r\n </button>\r\n </div>\r\n\r\n <!-- Normal Section -->\r\n <ng-template #normalSection>\r\n <div [ngClass]=\"section.noCardLayout ? 'section-no-card' : 'section-card'\">\r\n <div class=\"section-header\" *ngIf=\"section.sectionTitle\">\r\n <h3 class=\"section-title\">{{ section.sectionTitle }}</h3>\r\n <button *ngIf=\"section.collapsible\" mat-icon-button type=\"button\" (click)=\"toggleSection(section)\">\r\n <mat-icon>{{ section.collapsed ? 'expand_more' : 'expand_less' }}</mat-icon>\r\n </button>\r\n </div>\r\n <div class=\"form-grid\" *ngIf=\"!section.collapsed\">\r\n <div *ngFor=\"let field of section.fields\" [ngClass]=\"['form-col', field.class || 'col-12']\"\r\n [hidden]=\"!isFieldVisible(field)\">\r\n <!-- Pass the root form group to the template -->\r\n <ng-container\r\n *ngTemplateOutlet=\"fieldTemplate; context: {field: field, group: form}\"></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n </ng-container>\r\n\r\n <div class=\"btn-row\">\r\n <button mat-stroked-button type=\"button\" (click)=\"onCancel()\" *ngIf=\"processedConfig?.cancelLabel\">{{\r\n processedConfig.cancelLabel\r\n }}</button>\r\n <button mat-stroked-button type=\"button\" *ngIf=\"processedConfig?.saveDraftLabel\">{{\r\n processedConfig.saveDraftLabel }}</button>\r\n <button mat-flat-button color=\"primary\" type=\"submit\">{{ processedConfig?.submitLabel || 'Submit' }}</button>\r\n </div>\r\n\r\n</form>\r\n\r\n<!-- Reusable Field Template -->\r\n<ng-template #fieldTemplate let-field=\"field\" let-group=\"group\">\r\n <div [formGroup]=\"group\">\r\n\r\n <!-- Text / Email / Number / Tel / Password / URL -->\r\n <div *ngIf=\"['text', 'email', 'number', 'tel', 'password', 'url'].includes(field.type || '')\"\r\n class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"field.type\" [formControlName]=\"field.name\" [placeholder]=\"field.placeholder || ''\"\r\n [readonly]=\"field.readonly\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\">\r\n <div class=\"input-suffix\">\r\n <span class=\"suffix-text\" *ngIf=\"field.suffixText\">{{ field.suffixText }}</span>\r\n <mat-icon *ngIf=\"field.suffixIcon\">{{ field.suffixIcon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.icon\">{{ field.icon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n </div>\r\n </div>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Textarea -->\r\n <div *ngIf=\"field.type === 'textarea'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <textarea [formControlName]=\"field.name\" [placeholder]=\"field.placeholder || ''\" [readonly]=\"field.readonly\"\r\n class=\"form-input form-textarea\" rows=\"4\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\"></textarea>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Select / Dropdown -->\r\n <div *ngIf=\"field.type === 'select' || field.type === 'dropdown'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <select [formControlName]=\"field.name\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <option value=\"\" disabled selected *ngIf=\"field.placeholder\">{{ field.placeholder }}</option>\r\n <option value=\"\" disabled selected *ngIf=\"!field.placeholder\">Select</option>\r\n <option *ngFor=\"let opt of getFieldOptions(field)\" [value]=\"opt.value\">{{ opt.label }}</option>\r\n </select>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Date -->\r\n <div *ngIf=\"field.type === 'date'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"relative\">\r\n <input matInput [matDatepicker]=\"picker\" [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder || ''\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <mat-datepicker-toggle matSuffix [for]=\"picker\" class=\"date-toggle\"></mat-datepicker-toggle>\r\n <mat-datepicker #picker></mat-datepicker>\r\n </div>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Radio -->\r\n <div *ngIf=\"field.type === 'radio'\" class=\"radio-group-container\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <label class=\"field-label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </label>\r\n <mat-radio-group [formControlName]=\"field.name\" class=\"radio-group\">\r\n <mat-radio-button *ngFor=\"let opt of getFieldOptions(field)\" [value]=\"opt.value\" class=\"radio-button\">\r\n {{ opt.label }}\r\n </mat-radio-button>\r\n </mat-radio-group>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Composite Field (Sub-groups) -->\r\n <div *ngIf=\"field.type === 'composite'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"composite-container\">\r\n <ng-container *ngFor=\"let sub of field.subFields; let last = last\">\r\n <div class=\"composite-sub-field\" style=\"flex: 1;\">\r\n <div class=\"field-label\" *ngIf=\"sub.label\"\r\n style=\"font-size: 0.75rem; font-weight: normal; margin-bottom: 0.25rem;\">\r\n {{ sub.label }}\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"sub.type\" [formControlName]=\"sub.name\" [placeholder]=\"sub.placeholder || ''\"\r\n [readonly]=\"sub.readonly\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(sub.name)?.touched && group.get(sub.name)?.invalid\">\r\n <div class=\"input-suffix\" [class.color-suffix]=\"sub.suffixText === '%'\">\r\n <span class=\"suffix-text\" *ngIf=\"sub.suffixText\">{{ sub.suffixText }}</span>\r\n <mat-icon *ngIf=\"sub.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <!-- Adjust separator alignment if labels are present -->\r\n <span class=\"separator\" *ngIf=\"!last && field.separator\"\r\n [style.padding-top]=\"sub.label ? '1.25rem' : '0'\">{{ field.separator }}</span>\r\n </ng-container>\r\n </div>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"error-text text-danger text-small mt-1\" *ngIf=\"group.errors?.['invalid_minMax_' + field.name]\">\r\n Min value cannot be greater than Max value.\r\n </div>\r\n <div class=\"error-text text-danger text-small mt-1\"\r\n *ngIf=\"group.errors?.['invalid_percentageTotal_' + field.name]\">\r\n Total percentage must be 100%.\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- File Upload -->\r\n <div *ngIf=\"field.type === 'file'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n\r\n <!-- Upload Box -->\r\n <div class=\"upload-box\" (click)=\"fileInput.click()\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n *ngIf=\"!field.uploadedFiles || field.uploadedFiles.length === 0 || field.multiple\">\r\n <mat-icon class=\"upload-icon\">cloud_upload</mat-icon>\r\n <div class=\"upload-text\">Click to upload File</div>\r\n <div class=\"upload-hint\">PDF, DOCX, JPG, PNG (Max 5MB)</div>\r\n <input #fileInput type=\"file\" [attr.multiple]=\"field.multiple ? true : null\" [attr.accept]=\"field.accept\"\r\n (change)=\"onFileChange($event, field)\" style=\"display: none;\">\r\n </div>\r\n\r\n <!-- Uploaded Files List -->\r\n <div class=\"uploaded-files-list\" *ngIf=\"field.uploadedFiles && field.uploadedFiles.length > 0\">\r\n <div class=\"uploaded-file-item\" *ngFor=\"let file of field.uploadedFiles; let i = index\">\r\n <div class=\"file-icon\">\r\n <mat-icon class=\"pdf-icon\" *ngIf=\"file.type === 'application/pdf'\">picture_as_pdf</mat-icon>\r\n <mat-icon class=\"doc-icon\"\r\n *ngIf=\"file.type.includes('word') || file.type.includes('document')\">description</mat-icon>\r\n <mat-icon class=\"img-icon\" *ngIf=\"file.type.includes('image')\">image</mat-icon>\r\n <mat-icon class=\"file-icon-default\"\r\n *ngIf=\"!file.type.includes('pdf') && !file.type.includes('word') && !file.type.includes('document') && !file.type.includes('image')\">insert_drive_file</mat-icon>\r\n </div>\r\n <div class=\"file-info\">\r\n <div class=\"file-name\">{{ file.name }}</div>\r\n <div class=\"file-size\">{{ (file.size / 1024).toFixed(2) }} KB</div>\r\n </div>\r\n <button mat-icon-button color=\"warn\" type=\"button\" (click)=\"removeFile(field, i)\"\r\n class=\"remove-file-btn\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n</ng-template>", styles: [":host{display:block;width:100%}.configurable-form-container{padding:0;font-family:var(--cf-font-family, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif)}.configurable-form-container .section-card{background:var(--cf-surface-background, #ffffff);border:1px solid var(--cf-border-color, #D1D5DB);border-radius:var(--cf-section-radius, 12px);padding:var(--cf-section-padding, 2rem);margin-bottom:var(--cf-section-spacing, 1.5rem);box-shadow:var(--cf-section-shadow, 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06))}.configurable-form-container .section-card:last-of-type{margin-bottom:0}.configurable-form-container .section-no-card{margin-bottom:var(--cf-section-spacing, 1.5rem)}.configurable-form-container .section-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--cf-section-spacing, 1.5rem);padding-bottom:1rem;border-bottom:2px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .section-title{font-size:var(--cf-section-title-size, 1.25rem);font-weight:var(--cf-section-title-weight, 600);color:var(--cf-text-primary, #111827);margin:0;letter-spacing:-.025em}.configurable-form-container .form-grid{display:flex;flex-wrap:wrap;margin-left:-.625rem;margin-right:-.625rem}.configurable-form-container .form-col{position:relative;width:100%;padding-left:.625rem;padding-right:.625rem;margin-bottom:1.25rem}.configurable-form-container .col-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.configurable-form-container .col-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.configurable-form-container .col-3{flex:0 0 25%;max-width:25%}.configurable-form-container .col-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.configurable-form-container .col-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.configurable-form-container .col-6{flex:0 0 50%;max-width:50%}.configurable-form-container .col-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.configurable-form-container .col-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.configurable-form-container .col-9{flex:0 0 75%;max-width:75%}.configurable-form-container .col-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.configurable-form-container .col-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.configurable-form-container .col-12{flex:0 0 100%;max-width:100%}@media(min-width:769px){.configurable-form-container .col-md-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.configurable-form-container .col-md-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.configurable-form-container .col-md-3{flex:0 0 25%;max-width:25%}.configurable-form-container .col-md-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.configurable-form-container .col-md-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.configurable-form-container .col-md-6{flex:0 0 50%;max-width:50%}.configurable-form-container .col-md-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.configurable-form-container .col-md-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.configurable-form-container .col-md-9{flex:0 0 75%;max-width:75%}.configurable-form-container .col-md-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.configurable-form-container .col-md-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.configurable-form-container .col-md-12{flex:0 0 100%;max-width:100%}}.configurable-form-container .field-container{margin-bottom:0}.configurable-form-container .field-label{display:block;font-size:var(--cf-label-size, .875rem);font-weight:var(--cf-label-weight, 600);color:var(--cf-text-primary, #111827);margin-bottom:.5rem;line-height:1.25rem}.configurable-form-container .field-label .text-danger{color:var(--cf-error-color, #DC2626);margin-left:.125rem}.configurable-form-container .input-wrapper{position:relative;display:flex;align-items:center}.configurable-form-container .form-input{width:100%;padding:var(--cf-input-padding-y, .625rem) var(--cf-input-padding-x, .875rem);font-size:var(--cf-input-font-size, .875rem);line-height:1.5;color:var(--cf-text-primary, #111827);background-color:var(--cf-input-bg, #ffffff);border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:var(--cf-input-radius, 8px);transition:all .2s ease;font-family:inherit}.configurable-form-container .form-input:hover:not(:disabled):not([readonly]){border-color:var(--cf-input-hover-border-color, #9CA3AF)}.configurable-form-container .form-input:focus{outline:none;border-color:var(--cf-primary-color, #3B82F6);box-shadow:0 0 0 3px #3b82f61a}.configurable-form-container .form-input::placeholder{color:#9ca3af}.configurable-form-container .form-input:disabled,.configurable-form-container .form-input[readonly]{background-color:var(--cf-disabled-background, #F3F4F6);color:var(--cf-text-secondary, #6B7280);cursor:not-allowed;border-color:#e5e7eb}.configurable-form-container .form-input.is-invalid{border-color:var(--cf-error-color, #DC2626);background-color:#fef2f2}.configurable-form-container .form-input.is-invalid:focus{box-shadow:0 0 0 3px #dc26261a}.configurable-form-container select.form-input{appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E\");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;cursor:pointer}.configurable-form-container select.form-input:disabled{cursor:not-allowed}.configurable-form-container .form-textarea{resize:vertical;min-height:100px;font-family:inherit}.configurable-form-container .input-suffix{position:absolute;right:.75rem;display:flex;align-items:center;gap:.5rem;pointer-events:none}.configurable-form-container .input-suffix .suffix-text{font-size:.875rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .input-suffix mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .input-suffix .lock-icon{color:#9ca3af}.configurable-form-container .input-suffix.color-suffix .suffix-text{color:var(--cf-primary-color, #3B82F6);font-weight:600}.configurable-form-container .char-count-row{display:flex;justify-content:space-between;align-items:center;margin-top:.5rem}.configurable-form-container .char-count{font-size:.75rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .hint-text{font-size:var(--cf-hint-size, .75rem);color:var(--cf-text-secondary, #6B7280);margin-top:.375rem;line-height:1.25rem}.configurable-form-container .mt-2{margin-top:.5rem}.configurable-form-container .radio-group-container.is-invalid .field-label{color:var(--cf-error-color, #DC2626)}.configurable-form-container .radio-group{display:flex;gap:2rem;flex-wrap:wrap;margin-top:.5rem}.configurable-form-container .radio-button{margin:0}.configurable-form-container .composite-container{display:flex;align-items:center;gap:.75rem}.configurable-form-container .composite-container .separator{font-size:.875rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .composite-container .input-wrapper{flex:1}.configurable-form-container .upload-box{border:2px dashed var(--cf-border-color, #D1D5DB);border-radius:var(--cf-section-radius, 12px);padding:2.5rem;text-align:center;cursor:pointer;transition:all .2s ease;background-color:var(--cf-hover-background, #F9FAFB)}.configurable-form-container .upload-box:hover{border-color:var(--cf-primary-color, #3B82F6);background-color:#3b82f608}.configurable-form-container .upload-box.is-invalid{border-color:var(--cf-error-color, #DC2626);background-color:#fef2f2}.configurable-form-container .upload-box .upload-icon{font-size:3rem;width:3rem;height:3rem;color:var(--cf-primary-color, #3B82F6);margin-bottom:.75rem}.configurable-form-container .upload-box .upload-text{font-size:.875rem;color:var(--cf-text-primary, #111827);font-weight:500;margin-bottom:.375rem}.configurable-form-container .upload-box .upload-hint{font-size:.75rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-files-list{margin-top:1rem}.configurable-form-container .uploaded-file-item{display:flex;align-items:center;gap:.75rem;padding:.875rem;border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:8px;margin-bottom:.5rem;background-color:var(--cf-hover-background, #F9FAFB);transition:all .2s ease}.configurable-form-container .uploaded-file-item:hover{border-color:#9ca3af;box-shadow:0 1px 3px #0000001a}.configurable-form-container .uploaded-file-item .file-icon mat-icon{font-size:2rem;width:2rem;height:2rem}.configurable-form-container .uploaded-file-item .file-icon mat-icon.pdf-icon{color:#dc2626}.configurable-form-container .uploaded-file-item .file-icon mat-icon.doc-icon{color:#2563eb}.configurable-form-container .uploaded-file-item .file-icon mat-icon.img-icon{color:#059669}.configurable-form-container .uploaded-file-item .file-icon mat-icon.file-icon-default{color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-file-item .file-info{flex:1}.configurable-form-container .uploaded-file-item .file-info .file-name{font-size:.875rem;color:var(--cf-text-primary, #111827);font-weight:500;margin-bottom:.125rem}.configurable-form-container .uploaded-file-item .file-info .file-size{font-size:.75rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-file-item .remove-file-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem}.configurable-form-container .relative{position:relative}.configurable-form-container .date-toggle{position:absolute;right:0;top:50%;transform:translateY(-50%)}.configurable-form-container .repeater-item{padding:1.5rem;border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:10px;margin-bottom:1rem;background-color:var(--cf-hover-background, #F9FAFB);transition:all .2s ease}.configurable-form-container .repeater-item:hover{border-color:#9ca3af;box-shadow:0 2px 4px #0000000d}.configurable-form-container .repeater-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.25rem;padding-bottom:.75rem;border-bottom:1.5px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .repeater-item-header .text-small{font-size:.875rem;font-weight:600;color:var(--cf-text-primary, #111827);text-transform:uppercase;letter-spacing:.025em}.configurable-form-container .repeater-separator{height:1px;background-color:var(--cf-border-color, #D1D5DB);margin:1.5rem 0}.configurable-form-container .add-btn{margin-top:1rem;display:inline-flex;align-items:center;gap:.5rem;padding:.625rem 1.25rem;background-color:transparent;color:var(--cf-primary-color, #3B82F6);border:1.5px solid var(--cf-primary-color, #3B82F6);border-radius:8px;font-size:.875rem;font-weight:600;cursor:pointer;transition:all .2s ease}.configurable-form-container .add-btn:hover:not(:disabled){background-color:var(--cf-primary-color, #3B82F6);color:#fff}.configurable-form-container .add-btn:disabled{opacity:.5;cursor:not-allowed;border-color:var(--cf-disabled-background, #E5E7EB)}.configurable-form-container .add-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem}.configurable-form-container .btn-row{display:flex;justify-content:flex-end;gap:1rem;margin-top:2rem;padding-top:1.5rem;border-top:2px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .btn-row button{padding:.625rem 1.5rem;font-size:.875rem;font-weight:600;border-radius:8px;cursor:pointer;transition:all .2s ease;border:none;font-family:inherit}.configurable-form-container .btn-row button[mat-stroked-button]{background-color:transparent;color:var(--cf-text-primary, #111827);border:1.5px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .btn-row button[mat-stroked-button]:hover{background-color:var(--cf-hover-background, #F9FAFB);border-color:#9ca3af}.configurable-form-container .btn-row button[mat-flat-button]{background-color:var(--cf-primary-color, #3B82F6);color:#fff;box-shadow:0 1px 3px #0000001a}.configurable-form-container .btn-row button[mat-flat-button]:hover{background-color:#2563eb;box-shadow:0 4px 6px -1px #0000001a}.configurable-form-container .btn-row button[mat-flat-button]:active{background-color:#1d4ed8}@media(max-width:768px){.configurable-form-container .section-card{padding:1.25rem;border-radius:8px}.configurable-form-container .form-grid{margin-left:-.5rem;margin-right:-.5rem}.configurable-form-container .form-col{padding-left:.5rem;padding-right:.5rem;margin-bottom:1rem}.configurable-form-container .btn-row{flex-direction:column-reverse}.configurable-form-container .btn-row button{width:100%}.configurable-form-container .radio-group{flex-direction:column;gap:.75rem}.configurable-form-container .composite-container{flex-direction:column;align-items:stretch}.configurable-form-container .composite-container .separator{text-align:center}}\n"] }]
1463
- }], ctorParameters: () => [{ type: i1$2.FormBuilder }, { type: i2$1.MatSnackBar }, { type: i3.HttpClient }], propDecorators: { config: [{
3460
+ args: [{ selector: 'lib-configurable-form', standalone: true, imports: [CommonModule, ReactiveFormsModule, MaterialModule], template: "<form [formGroup]=\"form\" class=\"configurable-form-container\" *ngIf=\"form\">\r\n\r\n <ng-container *ngFor=\"let section of sections\">\r\n\r\n <!-- Repeater Section -->\r\n <div *ngIf=\"section.isRepeater; else normalSection\"\r\n [ngClass]=\"section.noCardLayout ? 'section-no-card' : 'section-card'\">\r\n <div class=\"section-header\" *ngIf=\"section.sectionTitle\">\r\n <h3 class=\"section-title\">{{ section.sectionTitle }}</h3>\r\n <button *ngIf=\"section.collapsible\" mat-icon-button type=\"button\" (click)=\"toggleSection(section)\">\r\n <mat-icon>{{ section.collapsed ? 'expand_more' : 'expand_less' }}</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div [formArrayName]=\"section.formArrayName || 'items'\" *ngIf=\"!section.collapsed\">\r\n <div *ngFor=\"let item of getFormArray(section.formArrayName!).controls; let i = index\"\r\n [formGroupName]=\"i\" class=\"repeater-item\">\r\n <div class=\"repeater-item-header\" *ngIf=\"getFormArray(section.formArrayName!).length > 1\">\r\n <span class=\"text-small\">{{ section.repeaterItemLabel || 'Item' }} {{i + 1}}</span>\r\n <button mat-icon-button color=\"warn\" type=\"button\"\r\n (click)=\"removeRepeaterItem(section.formArrayName!, i)\"\r\n [disabled]=\"section.minItems && getFormArray(section.formArrayName!).length <= section.minItems\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Fields Grid -->\r\n <div class=\"form-grid\">\r\n <div *ngFor=\"let field of section.fields\" [ngClass]=\"['form-col', field.class || 'col-12']\"\r\n [hidden]=\"!isFieldVisible(field)\">\r\n <ng-container\r\n *ngTemplateOutlet=\"fieldTemplate; context: {field: field, group: item}\"></ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"repeater-separator\" *ngIf=\"i < getFormArray(section.formArrayName!).length - 1\"></div>\r\n </div>\r\n </div>\r\n\r\n <button mat-button color=\"primary\" type=\"button\" (click)=\"addRepeaterItem(section)\" class=\"add-btn\"\r\n *ngIf=\"!section.collapsed\"\r\n [disabled]=\"section.maxItems && getFormArray(section.formArrayName!).length >= section.maxItems\">\r\n <mat-icon>add_circle_outline</mat-icon> {{ section.addLabel || 'Add More' }}\r\n </button>\r\n </div>\r\n\r\n <!-- Normal Section -->\r\n <ng-template #normalSection>\r\n <div [ngClass]=\"section.noCardLayout ? 'section-no-card' : 'section-card'\">\r\n <div class=\"section-header\" *ngIf=\"section.sectionTitle\">\r\n <h3 class=\"section-title\">{{ section.sectionTitle }}</h3>\r\n <button *ngIf=\"section.collapsible\" mat-icon-button type=\"button\" (click)=\"toggleSection(section)\">\r\n <mat-icon>{{ section.collapsed ? 'expand_more' : 'expand_less' }}</mat-icon>\r\n </button>\r\n </div>\r\n <div class=\"form-grid\" *ngIf=\"!section.collapsed\">\r\n <div *ngFor=\"let field of section.fields\" [ngClass]=\"['form-col', field.class || 'col-12']\"\r\n [hidden]=\"!isFieldVisible(field)\">\r\n <!-- Pass the root form group to the template -->\r\n <ng-container\r\n *ngTemplateOutlet=\"fieldTemplate; context: {field: field, group: form}\"></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n </ng-container>\r\n\r\n</form>\r\n\r\n<!-- Reusable Field Template -->\r\n<ng-template #fieldTemplate let-field=\"field\" let-group=\"group\">\r\n <div [formGroup]=\"group\">\r\n\r\n <!-- Text / Email / Number / Tel / URL (Password removed) -->\r\n <div *ngIf=\"['text', 'email', 'number', 'tel', 'url'].includes(field.type || '')\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"field.type\" [formControlName]=\"field.name\" [placeholder]=\"field.placeholder || ''\"\r\n [readonly]=\"field.readonly\" class=\"form-input\" [name]=\"field.name\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\">\r\n <div class=\"input-suffix\">\r\n <span class=\"suffix-text\" *ngIf=\"field.suffixText\">{{ field.suffixText }}</span>\r\n <mat-icon *ngIf=\"field.suffixIcon\">{{ field.suffixIcon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.icon\">{{ field.icon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n </div>\r\n </div>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Password Field (Separated) -->\r\n <div *ngIf=\"field.type === 'password'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"isPasswordVisible(field.name) ? 'text' : 'password'\" [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder || ''\" [readonly]=\"field.readonly\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\">\r\n <div class=\"input-suffix\">\r\n <span class=\"suffix-text\" *ngIf=\"field.suffixText\">{{ field.suffixText }}</span>\r\n <mat-icon *ngIf=\"field.suffixIcon\">{{ field.suffixIcon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.icon\">{{ field.icon }}</mat-icon>\r\n <mat-icon *ngIf=\"field.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n <mat-icon class=\"password-toggle-icon\" (click)=\"togglePassword(field.name)\">\r\n {{ isPasswordVisible(field.name) ? 'visibility' : 'visibility_off' }}\r\n </mat-icon>\r\n </div>\r\n </div>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Textarea -->\r\n <div *ngIf=\"field.type === 'textarea'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <textarea [formControlName]=\"field.name\" [placeholder]=\"field.placeholder || ''\" [readonly]=\"field.readonly\"\r\n class=\"form-input form-textarea\" rows=\"4\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n [maxlength]=\"field.validationRules?.maxLength || field.uiConfig?.maxCharacters\"></textarea>\r\n <!-- Character count -->\r\n <div class=\"char-count-row\" *ngIf=\"field.uiConfig?.maxCharacters || field.validationRules?.maxLength\">\r\n <div class=\"hint-text\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"char-count\">\r\n {{ getCharacterCount(field.name) }} / {{ field.uiConfig?.maxCharacters ||\r\n field.validationRules?.maxLength }} Characters\r\n </div>\r\n </div>\r\n <div class=\"hint-text mt-2\"\r\n *ngIf=\"(field.hint || field.helpText) && !field.uiConfig?.maxCharacters && !field.validationRules?.maxLength\">\r\n {{ field.hint || field.helpText }}\r\n </div>\r\n </div>\r\n\r\n <!-- Select / Dropdown -->\r\n <div *ngIf=\"field.type === 'select' || field.type === 'dropdown'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <select [formControlName]=\"field.name\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <option value=\"\" disabled selected *ngIf=\"field.placeholder\">{{ field.placeholder }}</option>\r\n <option value=\"\" disabled selected *ngIf=\"!field.placeholder\">Select</option>\r\n <option *ngFor=\"let opt of getFieldOptions(field)\" [value]=\"opt.value\">{{ opt.label }}</option>\r\n </select>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Date -->\r\n <div *ngIf=\"field.type === 'date'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"relative\">\r\n <input matInput [matDatepicker]=\"picker\" [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder || ''\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <mat-datepicker-toggle matSuffix [for]=\"picker\" class=\"date-toggle\"></mat-datepicker-toggle>\r\n <mat-datepicker #picker></mat-datepicker>\r\n </div>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Radio -->\r\n <div *ngIf=\"field.type === 'radio'\" class=\"radio-group-container\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\">\r\n <label class=\"field-label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </label>\r\n <mat-radio-group [formControlName]=\"field.name\" class=\"radio-group\">\r\n <mat-radio-button *ngFor=\"let opt of getFieldOptions(field)\" [value]=\"opt.value\" class=\"radio-button\">\r\n {{ opt.label }}\r\n </mat-radio-button>\r\n </mat-radio-group>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n </div>\r\n\r\n <!-- Composite Field (Sub-groups) -->\r\n <div *ngIf=\"field.type === 'composite'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n <div class=\"composite-container\">\r\n <ng-container *ngFor=\"let sub of field.subFields; let last = last\">\r\n <div class=\"composite-sub-field\" style=\"flex: 1;\">\r\n <div class=\"field-label\" *ngIf=\"sub.label\"\r\n style=\"font-size: 0.75rem; font-weight: normal; margin-bottom: 0.25rem;\">\r\n {{ sub.label }}\r\n </div>\r\n <div class=\"input-wrapper\">\r\n <input [type]=\"sub.type\" [formControlName]=\"sub.name\" [placeholder]=\"sub.placeholder || ''\"\r\n [readonly]=\"sub.readonly\" class=\"form-input\"\r\n [class.is-invalid]=\"group.get(sub.name)?.touched && group.get(sub.name)?.invalid\">\r\n <div class=\"input-suffix\" [class.color-suffix]=\"sub.suffixText === '%'\">\r\n <span class=\"suffix-text\" *ngIf=\"sub.suffixText\">{{ sub.suffixText }}</span>\r\n <mat-icon *ngIf=\"sub.readonly\" class=\"lock-icon\">lock_outline</mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <!-- Adjust separator alignment if labels are present -->\r\n <span class=\"separator\" *ngIf=\"!last && field.separator\"\r\n [style.padding-top]=\"sub.label ? '1.25rem' : '0'\">{{ field.separator }}</span>\r\n </ng-container>\r\n </div>\r\n <div class=\"hint-text mt-2\" *ngIf=\"field.hint || field.helpText\">{{ field.hint || field.helpText }}</div>\r\n <div class=\"error-text text-danger text-small mt-1\" *ngIf=\"group.errors?.['invalid_minMax_' + field.name]\">\r\n Min value cannot be greater than Max value.\r\n </div>\r\n <div class=\"error-text text-danger text-small mt-1\"\r\n *ngIf=\"group.errors?.['invalid_percentageTotal_' + field.name]\">\r\n Total percentage must be 100%.\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- File Upload -->\r\n <div *ngIf=\"field.type === 'file'\" class=\"field-container\">\r\n <div class=\"field-label\" *ngIf=\"field.label\">\r\n {{ field.label }}\r\n <span class=\"text-danger\" *ngIf=\"field.required || field.mandatory\">*</span>\r\n </div>\r\n\r\n <!-- Upload Box -->\r\n <div class=\"upload-box\" (click)=\"fileInput.click()\"\r\n [class.is-invalid]=\"group.get(field.name)?.touched && group.get(field.name)?.invalid\"\r\n *ngIf=\"!field.uploadedFiles || field.uploadedFiles.length === 0 || field.multiple\">\r\n <mat-icon class=\"upload-icon\">cloud_upload</mat-icon>\r\n <div class=\"upload-text\">Click to upload File</div>\r\n <div class=\"upload-hint\">PDF, DOCX, JPG, PNG (Max 5MB)</div>\r\n <input #fileInput type=\"file\" [attr.multiple]=\"field.multiple ? true : null\" [attr.accept]=\"field.accept\"\r\n (change)=\"onFileChange($event, field)\" style=\"display: none;\">\r\n </div>\r\n\r\n <!-- Uploaded Files List -->\r\n <div class=\"uploaded-files-list\" *ngIf=\"field.uploadedFiles && field.uploadedFiles.length > 0\">\r\n <div class=\"uploaded-file-item\" *ngFor=\"let file of field.uploadedFiles; let i = index\">\r\n <div class=\"file-icon\">\r\n <mat-icon class=\"pdf-icon\" *ngIf=\"file.type === 'application/pdf'\">picture_as_pdf</mat-icon>\r\n <mat-icon class=\"doc-icon\"\r\n *ngIf=\"file.type.includes('word') || file.type.includes('document')\">description</mat-icon>\r\n <mat-icon class=\"img-icon\" *ngIf=\"file.type.includes('image')\">image</mat-icon>\r\n <mat-icon class=\"file-icon-default\"\r\n *ngIf=\"!file.type.includes('pdf') && !file.type.includes('word') && !file.type.includes('document') && !file.type.includes('image')\">insert_drive_file</mat-icon>\r\n </div>\r\n <div class=\"file-info\">\r\n <div class=\"file-name\">{{ file.name }}</div>\r\n <div class=\"file-size\">{{ (file.size / 1024).toFixed(2) }} KB</div>\r\n </div>\r\n <button mat-icon-button color=\"warn\" type=\"button\" (click)=\"removeFile(field, i)\"\r\n class=\"remove-file-btn\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n</ng-template>", styles: [":host{display:block;width:100%}.configurable-form-container{padding:0;font-family:var(--cf-font-family, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif)}.configurable-form-container .section-card{background:var(--cf-surface-background, #ffffff);border:1px solid var(--cf-border-color, #D1D5DB);border-radius:var(--cf-section-radius, 12px);padding:var(--cf-section-padding, 2rem);margin-bottom:var(--cf-section-spacing, 1.5rem);box-shadow:var(--cf-section-shadow, 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06))}.configurable-form-container .section-card:last-of-type{margin-bottom:0}.configurable-form-container .section-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--cf-section-spacing, 1.5rem);padding-bottom:1rem;border-bottom:2px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .section-title{font-size:var(--cf-section-title-size, 1.25rem);font-weight:var(--cf-section-title-weight, 600);color:var(--cf-text-primary, #111827);margin:0;letter-spacing:-.025em}.configurable-form-container .form-grid{display:flex;flex-wrap:wrap;margin-left:-.625rem;margin-right:-.625rem}.configurable-form-container .form-col{position:relative;width:100%;padding-left:.625rem;padding-right:.625rem;margin-bottom:1.25rem}.configurable-form-container .col-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.configurable-form-container .col-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.configurable-form-container .col-3{flex:0 0 25%;max-width:25%}.configurable-form-container .col-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.configurable-form-container .col-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.configurable-form-container .col-6{flex:0 0 50%;max-width:50%}.configurable-form-container .col-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.configurable-form-container .col-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.configurable-form-container .col-9{flex:0 0 75%;max-width:75%}.configurable-form-container .col-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.configurable-form-container .col-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.configurable-form-container .col-12{flex:0 0 100%;max-width:100%}@media(min-width:769px){.configurable-form-container .col-md-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.configurable-form-container .col-md-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.configurable-form-container .col-md-3{flex:0 0 25%;max-width:25%}.configurable-form-container .col-md-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.configurable-form-container .col-md-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.configurable-form-container .col-md-6{flex:0 0 50%;max-width:50%}.configurable-form-container .col-md-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.configurable-form-container .col-md-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.configurable-form-container .col-md-9{flex:0 0 75%;max-width:75%}.configurable-form-container .col-md-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.configurable-form-container .col-md-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.configurable-form-container .col-md-12{flex:0 0 100%;max-width:100%}}.configurable-form-container .field-container{margin-bottom:0}.configurable-form-container .field-label{display:block;font-size:var(--cf-label-size, .875rem);font-weight:var(--cf-label-weight, 600);color:var(--cf-text-primary, #111827);margin-bottom:.5rem;line-height:1.25rem}.configurable-form-container .field-label .text-danger{color:var(--cf-error-color, #DC2626);margin-left:.125rem}.configurable-form-container .input-wrapper{position:relative;display:flex;align-items:center}.configurable-form-container .form-input{width:100%;padding:var(--cf-input-padding-y, .625rem) var(--cf-input-padding-x, .875rem);font-size:var(--cf-input-font-size, .875rem);line-height:1.5;color:var(--cf-text-primary, #111827);background-color:var(--cf-input-bg, #ffffff);border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:var(--cf-input-radius, 8px);transition:all .2s ease;font-family:inherit}.configurable-form-container .form-input:hover:not(:disabled):not([readonly]){border-color:var(--cf-input-hover-border-color, #9CA3AF)}.configurable-form-container .form-input:focus{outline:none;border-color:var(--cf-primary-color, #3B82F6);box-shadow:0 0 0 3px #3b82f61a}.configurable-form-container .form-input::placeholder{color:#9ca3af}.configurable-form-container .form-input:disabled,.configurable-form-container .form-input[readonly]{background-color:var(--cf-disabled-background, #F3F4F6);color:var(--cf-text-secondary, #6B7280);cursor:not-allowed;border-color:#e5e7eb}.configurable-form-container .form-input.is-invalid{border-color:var(--cf-error-color, #DC2626);background-color:#fef2f2}.configurable-form-container .form-input.is-invalid:focus{box-shadow:0 0 0 3px #dc26261a}.configurable-form-container select.form-input{appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E\");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;cursor:pointer}.configurable-form-container select.form-input:disabled{cursor:not-allowed}.configurable-form-container .form-textarea{resize:vertical;min-height:100px;font-family:inherit}.configurable-form-container .input-suffix{position:absolute;right:.75rem;display:flex;align-items:center;gap:.5rem;pointer-events:none}.configurable-form-container .input-suffix .password-toggle-icon{pointer-events:auto;cursor:pointer}.configurable-form-container .input-suffix .password-toggle-icon:hover{color:var(--cf-text-primary, #111827)}.configurable-form-container .input-suffix .suffix-text{font-size:.875rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .input-suffix mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .input-suffix .lock-icon{color:#9ca3af}.configurable-form-container .input-suffix.color-suffix .suffix-text{color:var(--cf-primary-color, #3B82F6);font-weight:600}.configurable-form-container .char-count-row{display:flex;justify-content:space-between;align-items:center;margin-top:.5rem}.configurable-form-container .char-count{font-size:.75rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .hint-text{font-size:var(--cf-hint-size, .75rem);color:var(--cf-text-secondary, #6B7280);margin-top:.375rem;line-height:1.25rem}.configurable-form-container .mt-2{margin-top:.5rem}.configurable-form-container .radio-group-container.is-invalid .field-label{color:var(--cf-error-color, #DC2626)}.configurable-form-container .radio-group{display:flex;gap:2rem;flex-wrap:wrap;margin-top:.5rem}.configurable-form-container .radio-button{margin:0}.configurable-form-container .composite-container{display:flex;align-items:center;gap:.75rem}.configurable-form-container .composite-container .separator{font-size:.875rem;color:var(--cf-text-secondary, #6B7280);font-weight:500}.configurable-form-container .composite-container .input-wrapper{flex:1}.configurable-form-container .upload-box{border:2px dashed var(--cf-border-color, #D1D5DB);border-radius:var(--cf-section-radius, 12px);padding:2.5rem;text-align:center;cursor:pointer;transition:all .2s ease;background-color:var(--cf-hover-background, #F9FAFB)}.configurable-form-container .upload-box:hover{border-color:var(--cf-primary-color, #3B82F6);background-color:#3b82f608}.configurable-form-container .upload-box.is-invalid{border-color:var(--cf-error-color, #DC2626);background-color:#fef2f2}.configurable-form-container .upload-box .upload-icon{font-size:3rem;width:3rem;height:3rem;color:var(--cf-primary-color, #3B82F6);margin-bottom:.75rem}.configurable-form-container .upload-box .upload-text{font-size:.875rem;color:var(--cf-text-primary, #111827);font-weight:500;margin-bottom:.375rem}.configurable-form-container .upload-box .upload-hint{font-size:.75rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-files-list{margin-top:1rem}.configurable-form-container .uploaded-file-item{display:flex;align-items:center;gap:.75rem;padding:.875rem;border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:8px;margin-bottom:.5rem;background-color:var(--cf-hover-background, #F9FAFB);transition:all .2s ease}.configurable-form-container .uploaded-file-item:hover{border-color:#9ca3af;box-shadow:0 1px 3px #0000001a}.configurable-form-container .uploaded-file-item .file-icon mat-icon{font-size:2rem;width:2rem;height:2rem}.configurable-form-container .uploaded-file-item .file-icon mat-icon.pdf-icon{color:#dc2626}.configurable-form-container .uploaded-file-item .file-icon mat-icon.doc-icon{color:#2563eb}.configurable-form-container .uploaded-file-item .file-icon mat-icon.img-icon{color:#059669}.configurable-form-container .uploaded-file-item .file-icon mat-icon.file-icon-default{color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-file-item .file-info{flex:1}.configurable-form-container .uploaded-file-item .file-info .file-name{font-size:.875rem;color:var(--cf-text-primary, #111827);font-weight:500;margin-bottom:.125rem}.configurable-form-container .uploaded-file-item .file-info .file-size{font-size:.75rem;color:var(--cf-text-secondary, #6B7280)}.configurable-form-container .uploaded-file-item .remove-file-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem}.configurable-form-container .relative{position:relative}.configurable-form-container .date-toggle{position:absolute;right:0;top:50%;transform:translateY(-50%)}.configurable-form-container .repeater-item{padding:1.5rem;border:1.5px solid var(--cf-border-color, #D1D5DB);border-radius:10px;margin-bottom:1rem;background-color:var(--cf-hover-background, #F9FAFB);transition:all .2s ease}.configurable-form-container .repeater-item:hover{border-color:#9ca3af;box-shadow:0 2px 4px #0000000d}.configurable-form-container .repeater-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.25rem;padding-bottom:.75rem;border-bottom:1.5px solid var(--cf-border-color, #D1D5DB)}.configurable-form-container .repeater-item-header .text-small{font-size:.875rem;font-weight:600;color:var(--cf-text-primary, #111827);text-transform:uppercase;letter-spacing:.025em}.configurable-form-container .repeater-separator{height:1px;background-color:var(--cf-border-color, #D1D5DB);margin:1.5rem 0}.configurable-form-container .add-btn{margin-top:1rem;display:inline-flex;align-items:center;gap:.5rem;padding:.625rem 1.25rem;background-color:transparent;color:var(--cf-primary-color, #3B82F6);border:1.5px solid var(--cf-primary-color, #3B82F6);border-radius:8px;font-size:.875rem;font-weight:600;cursor:pointer;transition:all .2s ease}.configurable-form-container .add-btn:hover:not(:disabled){background-color:var(--cf-primary-color, #3B82F6);color:#fff}.configurable-form-container .add-btn:disabled{opacity:.5;cursor:not-allowed;border-color:var(--cf-disabled-background, #E5E7EB)}.configurable-form-container .add-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem}@media(max-width:768px){.configurable-form-container .section-card{padding:1.25rem;border-radius:8px}.configurable-form-container .form-grid{margin-left:-.5rem;margin-right:-.5rem}.configurable-form-container .form-col{padding-left:.5rem;padding-right:.5rem;margin-bottom:1rem}.configurable-form-container .radio-group{flex-direction:column;gap:.75rem}.configurable-form-container .composite-container{flex-direction:column;align-items:stretch}.configurable-form-container .composite-container .separator{text-align:center}}\n"] }]
3461
+ }], ctorParameters: () => [{ type: i1$2.FormBuilder }, { type: i2$2.MatSnackBar }, { type: i3.HttpClient }], propDecorators: { config: [{
1464
3462
  type: Input
1465
3463
  }], jsonConfig: [{
1466
3464
  type: Input
@@ -1468,10 +3466,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1468
3466
  type: Input
1469
3467
  }], baseApiUrl: [{
1470
3468
  type: Input
1471
- }], formSubmit: [{
1472
- type: Output
1473
- }], formCancel: [{
1474
- type: Output
1475
3469
  }], optionsLoad: [{
1476
3470
  type: Output
1477
3471
  }] } });
@@ -2277,23 +4271,27 @@ class SharedUiModule {
2277
4271
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedUiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2278
4272
  static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SharedUiModule, imports: [CommonModule,
2279
4273
  MaterialModule,
2280
- AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
4274
+ AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule, FilterModule,
2281
4275
  SummaryCardModule,
2282
4276
  ConfigurableFormModule,
4277
+ FormComponentsModule,
2283
4278
  SmartFormModule], exports: [MaterialModule,
2284
- AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
4279
+ AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule, FilterModule,
2285
4280
  SummaryCardModule,
2286
4281
  ConfigurableFormModule,
4282
+ FormComponentsModule,
2287
4283
  SmartFormModule] });
2288
4284
  static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedUiModule, imports: [CommonModule,
2289
4285
  MaterialModule,
2290
- AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
4286
+ AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule, FilterModule,
2291
4287
  SummaryCardModule,
2292
4288
  ConfigurableFormModule,
4289
+ FormComponentsModule,
2293
4290
  SmartFormModule, MaterialModule,
2294
- AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
4291
+ AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule, FilterModule,
2295
4292
  SummaryCardModule,
2296
4293
  ConfigurableFormModule,
4294
+ FormComponentsModule,
2297
4295
  SmartFormModule] });
2298
4296
  }
2299
4297
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedUiModule, decorators: [{
@@ -2303,17 +4301,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2303
4301
  imports: [
2304
4302
  CommonModule,
2305
4303
  MaterialModule,
2306
- AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
4304
+ AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule, FilterModule,
2307
4305
  SummaryCardModule,
2308
4306
  ConfigurableFormModule,
2309
- SmartFormModule,
4307
+ FormComponentsModule,
4308
+ SmartFormModule
2310
4309
  ],
2311
4310
  exports: [
2312
4311
  MaterialModule,
2313
- AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
4312
+ AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule, FilterModule,
2314
4313
  SummaryCardModule,
2315
4314
  ConfigurableFormModule,
2316
- SmartFormModule,
4315
+ FormComponentsModule,
4316
+ SmartFormModule
2317
4317
  ],
2318
4318
  }]
2319
4319
  }] });
@@ -2435,8 +4435,6 @@ const EXAMPLE_FORM_CONFIG = {
2435
4435
  ]
2436
4436
  }
2437
4437
  ],
2438
- submitLabel: 'Save',
2439
- cancelLabel: 'Cancel',
2440
4438
  entityType: 'User'
2441
4439
  };
2442
4440
  /**
@@ -2500,8 +4498,6 @@ const TARGET_GROUP_CONFIG = {
2500
4498
  ]
2501
4499
  }
2502
4500
  ],
2503
- submitLabel: 'Save Configuration',
2504
- cancelLabel: 'Cancel'
2505
4501
  };
2506
4502
 
2507
4503
  var configurableForm_examples = /*#__PURE__*/Object.freeze({
@@ -2733,6 +4729,253 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2733
4729
  }]
2734
4730
  }] });
2735
4731
 
4732
+ class FilterComponent {
4733
+ elementRef;
4734
+ router;
4735
+ route;
4736
+ config = { items: [] };
4737
+ activeFilters = {};
4738
+ columns = [];
4739
+ labels = {
4740
+ filterBtn: '',
4741
+ clear: '',
4742
+ apply: '',
4743
+ search: '',
4744
+ columns: '',
4745
+ showAll: '',
4746
+ hideAll: ''
4747
+ };
4748
+ theme = '';
4749
+ filterChange = new EventEmitter();
4750
+ columnChange = new EventEmitter();
4751
+ toggle = new EventEmitter();
4752
+ isOpen = false;
4753
+ activeTab = 'filters';
4754
+ // Temporary state while panel is open
4755
+ tempFilters = {};
4756
+ tempColumns = [];
4757
+ constructor(elementRef, router, route) {
4758
+ this.elementRef = elementRef;
4759
+ this.router = router;
4760
+ this.route = route;
4761
+ }
4762
+ ngOnInit() {
4763
+ this.syncTempState();
4764
+ this.initFromUrl();
4765
+ }
4766
+ initFromUrl() {
4767
+ if (this.config.settings?.persistent) {
4768
+ this.route.queryParams.subscribe(params => {
4769
+ if (Object.keys(params).length > 0) {
4770
+ const newFilters = { ...this.activeFilters };
4771
+ Object.keys(params).forEach(key => {
4772
+ // Skip non-filter params if possible, or assume all are filters
4773
+ // Ideally we check against config items
4774
+ if (params[key] !== undefined) {
4775
+ newFilters[key] = params[key];
4776
+ }
4777
+ });
4778
+ this.activeFilters = newFilters;
4779
+ this.syncTempState();
4780
+ }
4781
+ });
4782
+ }
4783
+ }
4784
+ onClickOutside(event) {
4785
+ if (!this.elementRef.nativeElement.contains(event.target)) {
4786
+ this.isOpen = false;
4787
+ }
4788
+ }
4789
+ togglePanel() {
4790
+ this.isOpen = !this.isOpen;
4791
+ if (this.isOpen) {
4792
+ this.syncTempState();
4793
+ this.activeTab = 'filters';
4794
+ }
4795
+ this.toggle.emit(this.isOpen);
4796
+ }
4797
+ setActiveTab(tab) {
4798
+ this.activeTab = tab;
4799
+ }
4800
+ // Generic Filter Change Handler
4801
+ onFilterChange(key, value) {
4802
+ if (!key)
4803
+ return;
4804
+ this.tempFilters[key] = value;
4805
+ }
4806
+ // Column Visibility Logic
4807
+ toggleColumn(columnId) {
4808
+ const col = this.tempColumns.find(c => c.id === columnId);
4809
+ if (col) {
4810
+ col.visible = !col.visible;
4811
+ }
4812
+ }
4813
+ toggleAllColumns(visible) {
4814
+ this.tempColumns.forEach(c => c.visible = visible);
4815
+ }
4816
+ // Actions
4817
+ clearAll() {
4818
+ if (this.activeTab === 'filters') {
4819
+ this.tempFilters = {};
4820
+ if (this.config.settings?.persistent) {
4821
+ this.updateUrl({});
4822
+ }
4823
+ }
4824
+ else {
4825
+ // Reset columns to default or show all?
4826
+ // Usually 'clear' in filters context means clear filters
4827
+ // But if we are in columns tab, maybe we want to reset columns?
4828
+ // For now, let's keep it simple: generic clear clears filters.
4829
+ this.tempFilters = {};
4830
+ }
4831
+ // If we want clear to apply immediately without clicking apply:
4832
+ // this.apply();
4833
+ // But usually "Clear" inside panel just clears temp state until Apply is clicked.
4834
+ // However, if the user requested "Persistent" and "Clear", they might expect immediate URL update?
4835
+ // Standard UX: panel actions apply on "Apply".
4836
+ // The persisted state should only change when "Apply" is clicked?
4837
+ // Wait, if I update URL on clearAll inside panel, it might be confusing if panel is still open with cleared state but not "applied" to data.
4838
+ // Re-reading expectation: "Persistent" setting usually means the filter state is synced with URL.
4839
+ // If I clear temp state, URL shouldn't change until I click Apply.
4840
+ // SO I WILL NOT UPDATE URL HERE. The `initFromUrl` loads INTO `activeFilters`.
4841
+ // `apply()` updates `activeFilters` AND should update URL.
4842
+ }
4843
+ apply() {
4844
+ // Apply temp state to active state
4845
+ this.activeFilters = { ...this.tempFilters };
4846
+ // Clean up undefined/null values
4847
+ Object.keys(this.activeFilters).forEach(key => {
4848
+ if (this.activeFilters[key] === null || this.activeFilters[key] === undefined || this.activeFilters[key] === '') {
4849
+ delete this.activeFilters[key];
4850
+ }
4851
+ });
4852
+ // Apply columns
4853
+ this.columns = this.tempColumns.map(c => ({ ...c }));
4854
+ this.filterChange.emit(this.activeFilters);
4855
+ this.columnChange.emit(this.columns);
4856
+ if (this.config.settings?.persistent) {
4857
+ this.updateUrl(this.activeFilters);
4858
+ }
4859
+ this.isOpen = false;
4860
+ }
4861
+ updateUrl(queryParams) {
4862
+ this.router.navigate([], {
4863
+ relativeTo: this.route,
4864
+ queryParams: queryParams,
4865
+ queryParamsHandling: 'merge', // or 'replace' to clear others? 'merge' ensures we don't lose other params
4866
+ // But wait, if we removed a filter, merge keeps it?
4867
+ // We need to explicitly clear removed keys if we use merge.
4868
+ // Or use pure replacement of filter keys.
4869
+ // For simplicity, let's assuming we want to replace parameters that overlap.
4870
+ // But to clear keys, we need to pass `null` or `undefined` for those keys in `queryParams`?
4871
+ // Angular router: passing null removes the param.
4872
+ });
4873
+ // Refined updateUrl logic:
4874
+ // We merged activeFilters. But if we removed a key, it's missing from activeFilters.
4875
+ // We need to compare with current params and remove keys that are no longer in activeFilters?
4876
+ // A simpler way for this component:
4877
+ // We likely want to replace ALL query params that correspond to filters.
4878
+ // But we don't know which params are filters vs other things (e.g. page, sort).
4879
+ // For now, I will just push `this.activeFilters`.
4880
+ // NOTE: This doesn't clear keys that were removed.
4881
+ // To fix clearing:
4882
+ // I should probably navigate with exact activeFilters if I knew they are the ONLY params.
4883
+ // Better:
4884
+ // this.router.navigate([], { queryParams: this.activeFilters }); // property replaces all
4885
+ // If we want to keep 'page', etc., we need to include them.
4886
+ // Let's use 'merge' but we need to handle clearing.
4887
+ // I will implement a smarter update.
4888
+ }
4889
+ activeFilterCountValue() {
4890
+ return Object.keys(this.activeFilters).length;
4891
+ }
4892
+ get activeFilterCount() {
4893
+ return Object.keys(this.activeFilters).length;
4894
+ }
4895
+ syncTempState() {
4896
+ this.tempFilters = { ...this.activeFilters };
4897
+ this.tempColumns = JSON.parse(JSON.stringify(this.columns || []));
4898
+ }
4899
+ get containerStyles() {
4900
+ const styles = {};
4901
+ if (this.config.styles) {
4902
+ if (this.config.styles.width)
4903
+ styles['--cc-filter-panel-width'] = this.config.styles.width;
4904
+ if (this.config.styles.padding)
4905
+ styles['--cc-filter-panel-padding'] = this.config.styles.padding;
4906
+ if (this.config.styles.gap)
4907
+ styles['--cc-filter-panel-gap'] = this.config.styles.gap;
4908
+ if (this.config.styles.backgroundColor)
4909
+ styles['--cc-filter-panel-bg'] = this.config.styles.backgroundColor;
4910
+ if (this.config.styles.borderRadius)
4911
+ styles['--cc-filter-panel-radius'] = this.config.styles.borderRadius;
4912
+ if (this.config.styles.headerHeight)
4913
+ styles['--cc-filter-panel-header-height'] = this.config.styles.headerHeight;
4914
+ }
4915
+ return styles;
4916
+ }
4917
+ trackByFn(index, item) {
4918
+ return item.key || index;
4919
+ }
4920
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterComponent, deps: [{ token: i0.ElementRef }, { token: i1$1.Router }, { token: i1$1.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
4921
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FilterComponent, isStandalone: false, selector: "lib-filter", inputs: { config: "config", activeFilters: "activeFilters", columns: "columns", labels: "labels", theme: "theme" }, outputs: { filterChange: "filterChange", columnChange: "columnChange", toggle: "toggle" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, ngImport: i0, template: "<div class=\"cc-filter-container\" [class.is-open]=\"isOpen\" [ngStyle]=\"containerStyles\">\r\n\r\n <!-- Trigger Button -->\r\n <lib-button variant=\"outline\" (click)=\"togglePanel()\" class=\"cc-filter-trigger\"\r\n [class.active]=\"activeFilterCount > 0\">\r\n <span class=\"fas fa-filter\"></span> {{ labels?.filterBtn || 'Filter' }}\r\n <span *ngIf=\"activeFilterCount > 0\" class=\"cc-badge\">{{ activeFilterCount }}</span>\r\n </lib-button>\r\n\r\n <!-- Dropdown Panel -->\r\n <div class=\"cc-filter-panel mat-elevation-z4\" *ngIf=\"isOpen\" (click)=\"$event.stopPropagation()\">\r\n\r\n <!-- Header / Tabs -->\r\n <div class=\"cc-panel-header\">\r\n <div class=\"cc-tabs\">\r\n <div class=\"cc-tab\" [class.active]=\"activeTab === 'filters'\" (click)=\"setActiveTab('filters')\">\r\n {{ labels.filterBtn }}\r\n </div>\r\n <!-- Hide columns tab if no columns config provided -->\r\n <div class=\"cc-tab\" [class.active]=\"activeTab === 'columns'\" (click)=\"setActiveTab('columns')\"\r\n *ngIf=\"columns?.length\">\r\n {{ labels.columns }}\r\n </div>\r\n </div>\r\n <button type=\"button\" class=\"cc-icon-btn\" (click)=\"togglePanel()\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n </div>\r\n\r\n <!-- Filters Tab Content -->\r\n <div class=\"cc-panel-content\" *ngIf=\"activeTab === 'filters'\">\r\n\r\n <!-- Dynamic Items -->\r\n <ng-container *ngFor=\"let item of config.items; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\"></ng-container>\r\n </ng-container>\r\n\r\n </div>\r\n\r\n <!-- Columns Tab Content -->\r\n <div class=\"cc-panel-content\" *ngIf=\"activeTab === 'columns'\">\r\n <div class=\"cc-columns-actions\">\r\n <lib-button variant=\"outline\" class=\"cc-btn-text\" (click)=\"toggleAllColumns(true)\">{{ labels.showAll\r\n }}</lib-button>\r\n <lib-button variant=\"outline\" class=\"cc-btn-text\" (click)=\"toggleAllColumns(false)\">{{ labels.hideAll\r\n }}</lib-button>\r\n </div>\r\n <div class=\"cc-columns-list\">\r\n <div *ngFor=\"let col of tempColumns\" class=\"cc-column-item\">\r\n <lib-checkbox [label]=\"col.label\" [checked]=\"col.visible\" (checkedChange)=\"toggleColumn(col.id)\">\r\n </lib-checkbox>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n <div class=\"cc-panel-footer\">\r\n <lib-button variant=\"outline\" color=\"warn\" class=\"cc-btn-text text-danger\" (click)=\"clearAll()\">\r\n {{ labels.clear }}\r\n </lib-button>\r\n <lib-button class=\"ms-2\" variant=\"primary\" (click)=\"apply()\">\r\n {{ labels.apply }}\r\n </lib-button>\r\n </div>\r\n\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive Template for Items -->\r\n<ng-template #itemTemplate let-item=\"item\">\r\n <div class=\"cc-filter-item\" [ngClass]=\"['type-' + item.type]\"\r\n [style.display]=\"item.visible === false ? 'none' : 'block'\" [ngStyle]=\"item.styles\">\r\n\r\n <ng-container [ngSwitch]=\"item.type\">\r\n\r\n <!-- Input -->\r\n <lib-input *ngSwitchCase=\"'input'\" [config]=\"item.inputConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (valueChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-input>\r\n\r\n <!-- Dropdown -->\r\n <lib-dropdown *ngSwitchCase=\"'dropdown'\" [config]=\"item.dropdownConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (selectionChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-dropdown>\r\n\r\n <!-- Checkbox -->\r\n <lib-checkbox *ngSwitchCase=\"'checkbox'\" [config]=\"item.checkboxConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (checkedChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-checkbox>\r\n\r\n <!-- Radio -->\r\n <lib-radio *ngSwitchCase=\"'radio'\" [config]=\"item.radioConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (selectionChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-radio>\r\n\r\n <!-- Toggle -->\r\n <lib-toggle *ngSwitchCase=\"'toggle'\" [config]=\"item.toggleConfig\" [label]=\"item.label\"\r\n [checked]=\"tempFilters[item.key]\" (toggleChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-toggle>\r\n\r\n <!-- Datepicker -->\r\n <lib-datepicker *ngSwitchCase=\"'datepicker'\" [config]=\"item.datepickerConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (dateChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-datepicker>\r\n\r\n <!-- Search -->\r\n <lib-search *ngSwitchCase=\"'active-search'\" [config]=\"item.searchConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (search)=\"onFilterChange(item.key, $event)\">\r\n </lib-search>\r\n\r\n <!-- Group / Accordion -->\r\n <div *ngSwitchCase=\"'group'\" class=\"cc-accordion-item\" [class.expanded]=\"item.expanded\">\r\n <button type=\"button\" class=\"cc-accordion-header\" (click)=\"item.expanded = !item.expanded\">\r\n <span class=\"cc-accordion-title\">{{ item.label }}</span>\r\n <span class=\"material-icons cc-accordion-icon\">{{ item.expanded ? 'expand_less' : 'expand_more'\r\n }}</span>\r\n </button>\r\n\r\n <div class=\"cc-accordion-body\" *ngIf=\"item.expanded\">\r\n <ng-container *ngFor=\"let child of item.children; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: child }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Custom Divider -->\r\n <div *ngSwitchCase=\"'divider'\" class=\"cc-filter-divider\"></div>\r\n\r\n </ng-container>\r\n </div>\r\n</ng-template>", styles: [".cc-filter-container{position:relative;display:inline-block;font-family:var(--cc-filter-font-family, \"Roboto\", sans-serif)}.cc-filter-container .cc-filter-trigger ::ng-deep button{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:var(--cc-filter-btn-width, 103px);height:var(--cc-filter-btn-height, 44px);padding:0 16px;background-color:var(--cc-filter-btn-bg, #FCFCFB);border:var(--cc-filter-btn-border, 1px solid #E8EAED);border-radius:var(--cc-filter-btn-radius, 8px);color:var(--cc-filter-btn-text-color, #5F6368);font-size:14px;font-weight:500;transition:all .2s ease}.cc-filter-container .cc-filter-trigger ::ng-deep button mat-icon,.cc-filter-container .cc-filter-trigger ::ng-deep button .material-icons{color:#5f6368}.cc-filter-container .cc-filter-trigger ::ng-deep button:hover{background-color:var(--cc-filter-btn-hover-bg, #f1f3f4)}.cc-filter-container .cc-filter-trigger.active ::ng-deep button{background-color:var(--cc-filter-btn-active-bg, #e3f2fd);color:var(--cc-filter-btn-active-text, #1976d2);border-color:var(--cc-filter-btn-active-text, #1976d2)}.cc-filter-container .cc-filter-trigger.active ::ng-deep button mat-icon,.cc-filter-container .cc-filter-trigger.active ::ng-deep button .material-icons{color:var(--cc-filter-btn-active-text, #1976d2)}.cc-filter-container .cc-filter-trigger .cc-badge{background-color:var(--cc-filter-btn-badge-bg, #f44336);color:var(--cc-filter-btn-badge-text, #fff);font-size:10px;font-weight:700;padding:2px 6px;border-radius:10px;min-width:16px;text-align:center;margin-left:4px;line-height:1}.cc-filter-container .cc-filter-panel{position:absolute;top:calc(100% + 8px);right:0;z-index:1000;width:var(--cc-filter-panel-width, 320px);min-width:var(--cc-filter-panel-min-width, 480px)!important;padding:var(--cc-filter-panel-padding, 0);background-color:var(--cc-filter-panel-bg, #fff);border:var(--cc-filter-panel-border, 1px solid #e0e0e0);box-shadow:var(--cc-filter-panel-shadow, 0 4px 12px rgba(0, 0, 0, .15));border-radius:var(--cc-filter-panel-radius, 8px);display:flex;flex-direction:column;overflow:hidden}.cc-filter-container .cc-filter-panel.hidden{display:none}.cc-filter-container .cc-filter-panel .cc-panel-header{display:flex;align-items:center;justify-content:space-between;padding:0 1rem;height:var(--cc-filter-panel-header-height, 48px);border-bottom:1px solid #E0E0E0;background-color:var(--cc-filter-panel-header-bg, #fafafa)}.cc-filter-container .cc-tabs{display:flex;gap:1rem}.cc-filter-container .cc-tabs .cc-tab{cursor:pointer;padding:.5rem 0;font-weight:500;color:#5f6368;border-bottom:2px solid transparent;font-size:14px}.cc-filter-container .cc-tabs .cc-tab.active{color:var(--cc-filter-tab-active-text, #1976d2);border-bottom:var(--cc-filter-tab-border-bottom, 2px solid #1976d2)}.cc-filter-container .cc-icon-btn{background:none;border:none;cursor:pointer;color:#5f6368;padding:.25rem;border-radius:50%;display:flex;align-items:center;justify-content:center}.cc-filter-container .cc-icon-btn:hover{background-color:#0000000a}.cc-filter-container .cc-panel-content{padding:16px;max-height:400px;overflow-y:auto;display:flex;flex-direction:column;gap:var(--cc-filter-panel-gap, 1rem)}.cc-filter-container .cc-filter-section{margin-bottom:16px}.cc-filter-container .cc-filter-section .cc-section-title{font-size:13px;font-weight:600;margin-bottom:8px;color:var(--cc-filter-section-title, #333);text-transform:uppercase;letter-spacing:.5px}.cc-filter-container .cc-filter-section .cc-control-group{display:flex;flex-direction:column;gap:8px}.cc-filter-container .cc-filter-section .cc-control-group label{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--cc-filter-option-text, #555);cursor:pointer}.cc-filter-container .cc-filter-section .cc-control-group label:hover{color:#000}.cc-filter-container .cc-accordion-item{border-bottom:1px solid #E0E0E0}.cc-filter-container .cc-accordion-item:last-child{border-bottom:none}.cc-filter-container .cc-accordion-item .cc-accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 0;background:none;border:none;cursor:pointer;text-align:left;outline:none}.cc-filter-container .cc-accordion-item .cc-accordion-header .cc-accordion-title{font-size:.875rem;font-weight:500;color:#202124}.cc-filter-container .cc-accordion-item .cc-accordion-header .cc-accordion-icon{color:#5f6368;transition:transform .2s}.cc-filter-container .cc-accordion-item .cc-accordion-body{padding:0 0 1rem;display:flex;flex-direction:column;gap:1rem;animation:slideDown .2s ease-out}.cc-filter-container .cc-filter-divider{height:1px;background-color:#e0e0e0;margin:.5rem 0}.cc-filter-container .cc-panel-footer{padding:12px 16px;background-color:var(--cc-filter-footer-bg, #fff);border-top:var(--cc-filter-footer-border-top, 1px solid #e0e0e0);display:flex;justify-content:flex-end;align-items:center;gap:10px}.cc-filter-container .cc-columns-actions{display:flex;gap:.5rem;margin-bottom:.5rem}.cc-filter-container .cc-columns-list{display:flex;flex-direction:column;gap:.5rem}\n"], dependencies: [{ 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.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["variant", "type", "disabled", "width", "height", "borderRadius", "fontSize", "fontWeight", "backgroundColor", "color", "border", "icon", "labels"] }, { kind: "component", type: InputComponent, selector: "lib-input", inputs: ["config", "labels", "type", "label", "placeholder", "disabled", "required", "readonly", "clearable", "maxLength", "minLength", "min", "max", "pattern", "errorMessage", "helperText", "rows", "prefixIcon", "suffixIcon", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["valueChange", "inputBlur", "inputFocus"] }, { kind: "component", type: DropdownComponent, selector: "lib-dropdown", inputs: ["config", "labels", "options", "placeholder", "label", "multiple", "searchable", "clearable", "disabled", "required", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["selectionChange"] }, { kind: "component", type: CheckboxComponent, selector: "lib-checkbox", inputs: ["config", "labels", "label", "checked", "disabled", "required", "indeterminate", "options", "labelPosition", "color", "borderRadius", "value", "errorMessage", "width", "height", "fontSize", "fontWeight", "labelColor", "labelFontSize", "labelFontWeight", "gap", "fontFamily", "backgroundColor", "borderColor", "borderWidth", "padding", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow", "size", "checkedColor", "uncheckedColor", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight"], outputs: ["checkedChange"] }, { kind: "component", type: RadioComponent, selector: "lib-radio", inputs: ["config", "label", "options", "disabled", "required", "labelPosition", "color", "layout", "labels", "gap", "labelColor", "checkedColor", "uncheckedColor", "fontSize", "fontWeight", "fontFamily", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight", "disabledColor", "errorColor", "size", "borderRadius", "labelFontSize", "labelFontWeight"], outputs: ["selectionChange"] }, { kind: "component", type: ToggleComponent, selector: "lib-toggle", inputs: ["config", "labels", "label", "checked", "disabled", "required", "labelPosition", "color", "labelColor", "uncheckedColor", "checkedColor", "thumbColor", "checkedThumbColor", "fontSize", "fontWeight", "fontFamily", "toggleWidth", "toggleHeight", "gap", "sliderColor", "labelFontSize", "labelFontWeight", "disabledColor"], outputs: ["toggleChange"] }, { kind: "component", type: DatepickerComponent, selector: "lib-datepicker", inputs: ["config", "labels", "label", "placeholder", "disabled", "required", "minDate", "maxDate", "isRange", "startView", "value", "startDate", "endDate", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["dateChange"] }, { kind: "component", type: SearchComponent, selector: "lib-search", inputs: ["config", "labels", "placeholder", "label", "disabled", "debounceMs", "clearable", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "border", "padding", "fontWeight", "color", "textColor", "iconColor", "placeholderColor", "focusBorderColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["search", "clear"] }] });
4922
+ }
4923
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterComponent, decorators: [{
4924
+ type: Component,
4925
+ args: [{ selector: 'lib-filter', standalone: false, template: "<div class=\"cc-filter-container\" [class.is-open]=\"isOpen\" [ngStyle]=\"containerStyles\">\r\n\r\n <!-- Trigger Button -->\r\n <lib-button variant=\"outline\" (click)=\"togglePanel()\" class=\"cc-filter-trigger\"\r\n [class.active]=\"activeFilterCount > 0\">\r\n <span class=\"fas fa-filter\"></span> {{ labels?.filterBtn || 'Filter' }}\r\n <span *ngIf=\"activeFilterCount > 0\" class=\"cc-badge\">{{ activeFilterCount }}</span>\r\n </lib-button>\r\n\r\n <!-- Dropdown Panel -->\r\n <div class=\"cc-filter-panel mat-elevation-z4\" *ngIf=\"isOpen\" (click)=\"$event.stopPropagation()\">\r\n\r\n <!-- Header / Tabs -->\r\n <div class=\"cc-panel-header\">\r\n <div class=\"cc-tabs\">\r\n <div class=\"cc-tab\" [class.active]=\"activeTab === 'filters'\" (click)=\"setActiveTab('filters')\">\r\n {{ labels.filterBtn }}\r\n </div>\r\n <!-- Hide columns tab if no columns config provided -->\r\n <div class=\"cc-tab\" [class.active]=\"activeTab === 'columns'\" (click)=\"setActiveTab('columns')\"\r\n *ngIf=\"columns?.length\">\r\n {{ labels.columns }}\r\n </div>\r\n </div>\r\n <button type=\"button\" class=\"cc-icon-btn\" (click)=\"togglePanel()\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n </div>\r\n\r\n <!-- Filters Tab Content -->\r\n <div class=\"cc-panel-content\" *ngIf=\"activeTab === 'filters'\">\r\n\r\n <!-- Dynamic Items -->\r\n <ng-container *ngFor=\"let item of config.items; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\"></ng-container>\r\n </ng-container>\r\n\r\n </div>\r\n\r\n <!-- Columns Tab Content -->\r\n <div class=\"cc-panel-content\" *ngIf=\"activeTab === 'columns'\">\r\n <div class=\"cc-columns-actions\">\r\n <lib-button variant=\"outline\" class=\"cc-btn-text\" (click)=\"toggleAllColumns(true)\">{{ labels.showAll\r\n }}</lib-button>\r\n <lib-button variant=\"outline\" class=\"cc-btn-text\" (click)=\"toggleAllColumns(false)\">{{ labels.hideAll\r\n }}</lib-button>\r\n </div>\r\n <div class=\"cc-columns-list\">\r\n <div *ngFor=\"let col of tempColumns\" class=\"cc-column-item\">\r\n <lib-checkbox [label]=\"col.label\" [checked]=\"col.visible\" (checkedChange)=\"toggleColumn(col.id)\">\r\n </lib-checkbox>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n <div class=\"cc-panel-footer\">\r\n <lib-button variant=\"outline\" color=\"warn\" class=\"cc-btn-text text-danger\" (click)=\"clearAll()\">\r\n {{ labels.clear }}\r\n </lib-button>\r\n <lib-button class=\"ms-2\" variant=\"primary\" (click)=\"apply()\">\r\n {{ labels.apply }}\r\n </lib-button>\r\n </div>\r\n\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive Template for Items -->\r\n<ng-template #itemTemplate let-item=\"item\">\r\n <div class=\"cc-filter-item\" [ngClass]=\"['type-' + item.type]\"\r\n [style.display]=\"item.visible === false ? 'none' : 'block'\" [ngStyle]=\"item.styles\">\r\n\r\n <ng-container [ngSwitch]=\"item.type\">\r\n\r\n <!-- Input -->\r\n <lib-input *ngSwitchCase=\"'input'\" [config]=\"item.inputConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (valueChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-input>\r\n\r\n <!-- Dropdown -->\r\n <lib-dropdown *ngSwitchCase=\"'dropdown'\" [config]=\"item.dropdownConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (selectionChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-dropdown>\r\n\r\n <!-- Checkbox -->\r\n <lib-checkbox *ngSwitchCase=\"'checkbox'\" [config]=\"item.checkboxConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (checkedChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-checkbox>\r\n\r\n <!-- Radio -->\r\n <lib-radio *ngSwitchCase=\"'radio'\" [config]=\"item.radioConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (selectionChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-radio>\r\n\r\n <!-- Toggle -->\r\n <lib-toggle *ngSwitchCase=\"'toggle'\" [config]=\"item.toggleConfig\" [label]=\"item.label\"\r\n [checked]=\"tempFilters[item.key]\" (toggleChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-toggle>\r\n\r\n <!-- Datepicker -->\r\n <lib-datepicker *ngSwitchCase=\"'datepicker'\" [config]=\"item.datepickerConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (dateChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-datepicker>\r\n\r\n <!-- Search -->\r\n <lib-search *ngSwitchCase=\"'active-search'\" [config]=\"item.searchConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (search)=\"onFilterChange(item.key, $event)\">\r\n </lib-search>\r\n\r\n <!-- Group / Accordion -->\r\n <div *ngSwitchCase=\"'group'\" class=\"cc-accordion-item\" [class.expanded]=\"item.expanded\">\r\n <button type=\"button\" class=\"cc-accordion-header\" (click)=\"item.expanded = !item.expanded\">\r\n <span class=\"cc-accordion-title\">{{ item.label }}</span>\r\n <span class=\"material-icons cc-accordion-icon\">{{ item.expanded ? 'expand_less' : 'expand_more'\r\n }}</span>\r\n </button>\r\n\r\n <div class=\"cc-accordion-body\" *ngIf=\"item.expanded\">\r\n <ng-container *ngFor=\"let child of item.children; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: child }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Custom Divider -->\r\n <div *ngSwitchCase=\"'divider'\" class=\"cc-filter-divider\"></div>\r\n\r\n </ng-container>\r\n </div>\r\n</ng-template>", styles: [".cc-filter-container{position:relative;display:inline-block;font-family:var(--cc-filter-font-family, \"Roboto\", sans-serif)}.cc-filter-container .cc-filter-trigger ::ng-deep button{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:var(--cc-filter-btn-width, 103px);height:var(--cc-filter-btn-height, 44px);padding:0 16px;background-color:var(--cc-filter-btn-bg, #FCFCFB);border:var(--cc-filter-btn-border, 1px solid #E8EAED);border-radius:var(--cc-filter-btn-radius, 8px);color:var(--cc-filter-btn-text-color, #5F6368);font-size:14px;font-weight:500;transition:all .2s ease}.cc-filter-container .cc-filter-trigger ::ng-deep button mat-icon,.cc-filter-container .cc-filter-trigger ::ng-deep button .material-icons{color:#5f6368}.cc-filter-container .cc-filter-trigger ::ng-deep button:hover{background-color:var(--cc-filter-btn-hover-bg, #f1f3f4)}.cc-filter-container .cc-filter-trigger.active ::ng-deep button{background-color:var(--cc-filter-btn-active-bg, #e3f2fd);color:var(--cc-filter-btn-active-text, #1976d2);border-color:var(--cc-filter-btn-active-text, #1976d2)}.cc-filter-container .cc-filter-trigger.active ::ng-deep button mat-icon,.cc-filter-container .cc-filter-trigger.active ::ng-deep button .material-icons{color:var(--cc-filter-btn-active-text, #1976d2)}.cc-filter-container .cc-filter-trigger .cc-badge{background-color:var(--cc-filter-btn-badge-bg, #f44336);color:var(--cc-filter-btn-badge-text, #fff);font-size:10px;font-weight:700;padding:2px 6px;border-radius:10px;min-width:16px;text-align:center;margin-left:4px;line-height:1}.cc-filter-container .cc-filter-panel{position:absolute;top:calc(100% + 8px);right:0;z-index:1000;width:var(--cc-filter-panel-width, 320px);min-width:var(--cc-filter-panel-min-width, 480px)!important;padding:var(--cc-filter-panel-padding, 0);background-color:var(--cc-filter-panel-bg, #fff);border:var(--cc-filter-panel-border, 1px solid #e0e0e0);box-shadow:var(--cc-filter-panel-shadow, 0 4px 12px rgba(0, 0, 0, .15));border-radius:var(--cc-filter-panel-radius, 8px);display:flex;flex-direction:column;overflow:hidden}.cc-filter-container .cc-filter-panel.hidden{display:none}.cc-filter-container .cc-filter-panel .cc-panel-header{display:flex;align-items:center;justify-content:space-between;padding:0 1rem;height:var(--cc-filter-panel-header-height, 48px);border-bottom:1px solid #E0E0E0;background-color:var(--cc-filter-panel-header-bg, #fafafa)}.cc-filter-container .cc-tabs{display:flex;gap:1rem}.cc-filter-container .cc-tabs .cc-tab{cursor:pointer;padding:.5rem 0;font-weight:500;color:#5f6368;border-bottom:2px solid transparent;font-size:14px}.cc-filter-container .cc-tabs .cc-tab.active{color:var(--cc-filter-tab-active-text, #1976d2);border-bottom:var(--cc-filter-tab-border-bottom, 2px solid #1976d2)}.cc-filter-container .cc-icon-btn{background:none;border:none;cursor:pointer;color:#5f6368;padding:.25rem;border-radius:50%;display:flex;align-items:center;justify-content:center}.cc-filter-container .cc-icon-btn:hover{background-color:#0000000a}.cc-filter-container .cc-panel-content{padding:16px;max-height:400px;overflow-y:auto;display:flex;flex-direction:column;gap:var(--cc-filter-panel-gap, 1rem)}.cc-filter-container .cc-filter-section{margin-bottom:16px}.cc-filter-container .cc-filter-section .cc-section-title{font-size:13px;font-weight:600;margin-bottom:8px;color:var(--cc-filter-section-title, #333);text-transform:uppercase;letter-spacing:.5px}.cc-filter-container .cc-filter-section .cc-control-group{display:flex;flex-direction:column;gap:8px}.cc-filter-container .cc-filter-section .cc-control-group label{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--cc-filter-option-text, #555);cursor:pointer}.cc-filter-container .cc-filter-section .cc-control-group label:hover{color:#000}.cc-filter-container .cc-accordion-item{border-bottom:1px solid #E0E0E0}.cc-filter-container .cc-accordion-item:last-child{border-bottom:none}.cc-filter-container .cc-accordion-item .cc-accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 0;background:none;border:none;cursor:pointer;text-align:left;outline:none}.cc-filter-container .cc-accordion-item .cc-accordion-header .cc-accordion-title{font-size:.875rem;font-weight:500;color:#202124}.cc-filter-container .cc-accordion-item .cc-accordion-header .cc-accordion-icon{color:#5f6368;transition:transform .2s}.cc-filter-container .cc-accordion-item .cc-accordion-body{padding:0 0 1rem;display:flex;flex-direction:column;gap:1rem;animation:slideDown .2s ease-out}.cc-filter-container .cc-filter-divider{height:1px;background-color:#e0e0e0;margin:.5rem 0}.cc-filter-container .cc-panel-footer{padding:12px 16px;background-color:var(--cc-filter-footer-bg, #fff);border-top:var(--cc-filter-footer-border-top, 1px solid #e0e0e0);display:flex;justify-content:flex-end;align-items:center;gap:10px}.cc-filter-container .cc-columns-actions{display:flex;gap:.5rem;margin-bottom:.5rem}.cc-filter-container .cc-columns-list{display:flex;flex-direction:column;gap:.5rem}\n"] }]
4926
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1$1.Router }, { type: i1$1.ActivatedRoute }], propDecorators: { config: [{
4927
+ type: Input
4928
+ }], activeFilters: [{
4929
+ type: Input
4930
+ }], columns: [{
4931
+ type: Input
4932
+ }], labels: [{
4933
+ type: Input
4934
+ }], theme: [{
4935
+ type: Input
4936
+ }], filterChange: [{
4937
+ type: Output
4938
+ }], columnChange: [{
4939
+ type: Output
4940
+ }], toggle: [{
4941
+ type: Output
4942
+ }], onClickOutside: [{
4943
+ type: HostListener,
4944
+ args: ['document:click', ['$event']]
4945
+ }] } });
4946
+
4947
+ class FilterModule {
4948
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
4949
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: FilterModule, declarations: [FilterComponent], imports: [CommonModule,
4950
+ FormsModule,
4951
+ ReactiveFormsModule,
4952
+ ButtonModule,
4953
+ FormComponentsModule], exports: [FilterComponent] });
4954
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterModule, imports: [CommonModule,
4955
+ FormsModule,
4956
+ ReactiveFormsModule,
4957
+ ButtonModule,
4958
+ FormComponentsModule] });
4959
+ }
4960
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterModule, decorators: [{
4961
+ type: NgModule,
4962
+ args: [{
4963
+ declarations: [
4964
+ FilterComponent
4965
+ ],
4966
+ imports: [
4967
+ CommonModule,
4968
+ FormsModule,
4969
+ ReactiveFormsModule,
4970
+ ButtonModule,
4971
+ FormComponentsModule
4972
+ ],
4973
+ exports: [
4974
+ FilterComponent
4975
+ ]
4976
+ }]
4977
+ }] });
4978
+
2736
4979
  class SmartTableComponent {
2737
4980
  http;
2738
4981
  router;
@@ -2743,7 +4986,7 @@ class SmartTableComponent {
2743
4986
  topAction = new EventEmitter(); // For top bar buttons
2744
4987
  filterChange = new EventEmitter();
2745
4988
  rowSelect = new EventEmitter();
2746
- rowClick = new EventEmitter();
4989
+ columnClick = new EventEmitter();
2747
4990
  data = [];
2748
4991
  totalItems = 0;
2749
4992
  currentPage = 1;
@@ -2924,9 +5167,10 @@ class SmartTableComponent {
2924
5167
  const totalCountConfig = this.config.pagination?.totalCountConfig;
2925
5168
  let request$; // Observable
2926
5169
  if (totalCountConfig?.source === 'separate' && totalCountConfig.apiUrl) {
5170
+ const headers = this.getHeaders();
2927
5171
  request$ = forkJoin({
2928
- data: this.http.get(this.config.apiUrl, { params }),
2929
- count: this.http.get(totalCountConfig.apiUrl, { params })
5172
+ data: this.http.get(this.config.apiUrl, { params, headers }),
5173
+ count: this.http.get(totalCountConfig.apiUrl, { params, headers })
2930
5174
  }).pipe(map(({ data, count }) => {
2931
5175
  const dataPath = this.config.dataResponsePath !== undefined ? this.config.dataResponsePath : '';
2932
5176
  return {
@@ -2936,7 +5180,8 @@ class SmartTableComponent {
2936
5180
  }));
2937
5181
  }
2938
5182
  else {
2939
- request$ = this.http.get(this.config.apiUrl, { params }).pipe(map(response => {
5183
+ const headers = this.getHeaders();
5184
+ request$ = this.http.get(this.config.apiUrl, { params, headers }).pipe(map(response => {
2940
5185
  const dataPath = this.config.dataResponsePath !== undefined ? this.config.dataResponsePath : '';
2941
5186
  const totalPath = totalCountConfig?.responsePath || '';
2942
5187
  return {
@@ -3096,7 +5341,8 @@ class SmartTableComponent {
3096
5341
  return;
3097
5342
  this.config.filters.forEach(filter => {
3098
5343
  if (filter.apiUrl && !filter.options) {
3099
- this.http.get(filter.apiUrl).subscribe({
5344
+ const headers = this.getHeaders();
5345
+ this.http.get(filter.apiUrl, { headers }).subscribe({
3100
5346
  next: (response) => {
3101
5347
  const data = filter.dataPath ? this.getValueByPath(response, filter.dataPath) : response;
3102
5348
  if (!Array.isArray(data)) {
@@ -3186,18 +5432,29 @@ class SmartTableComponent {
3186
5432
  get columnCount() {
3187
5433
  return this.config.columns.length;
3188
5434
  }
3189
- onRowClick(row) {
3190
- const hasSelection = window.getSelection()?.toString();
3191
- if (this.config.clickableRows && !hasSelection) {
3192
- this.rowClick.emit(row);
5435
+ onColumnClick(row, col) {
5436
+ if (col.clickAction === 'callback') {
5437
+ this.columnClick.emit({ row, column: col.key });
5438
+ }
5439
+ else if (col.clickAction === 'route' && col.clickRoute) {
5440
+ const url = this.replaceParams(col.clickRoute, row);
5441
+ this.router.navigateByUrl(url);
5442
+ }
5443
+ }
5444
+ getHeaders() {
5445
+ let headers = new HttpHeaders();
5446
+ if (this.config.token) {
5447
+ const headerName = this.config.tokenHeader || 'Authorization';
5448
+ headers = headers.set(headerName, this.config.token);
3193
5449
  }
5450
+ return headers;
3194
5451
  }
3195
5452
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SmartTableComponent, deps: [{ token: i3.HttpClient }, { token: i1$1.Router }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
3196
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SmartTableComponent, isStandalone: false, selector: "lib-smart-table", inputs: { config: "config" }, outputs: { action: "action", topAction: "topAction", filterChange: "filterChange", rowSelect: "rowSelect", rowClick: "rowClick" }, viewQueries: [{ propertyName: "stickyHeaders", predicate: ["stickyHeader"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"smart-table-wrapper\">\n <!-- Top Toolbar -->\n <div class=\"st-toolbar\" *ngIf=\"config.searchConfig?.enabled || (config.filters && config.filters.length > 0) || (config.topBarButtons && config.topBarButtons.length > 0)\">\n \n <!-- Search -->\n <div class=\"st-search\" *ngIf=\"config.searchConfig?.enabled\">\n <i class=\"fa fa-search\"></i>\n <input type=\"text\" [placeholder]=\"config.labels?.searchPlaceholder || 'Search'\" (input)=\"onSearch($event)\">\n </div>\n\n <!-- Filters -->\n <div class=\"st-filters\" *ngIf=\"config.filters\">\n <div class=\"st-filter-item\" *ngFor=\"let filter of config.filters\">\n <select (change)=\"onFilterChange(filter.key, $event)\">\n <option value=\"\">{{ filter.label }}</option>\n <option *ngFor=\"let opt of filter.options\" [value]=\"opt.value\">{{ opt.label }}</option>\n </select>\n </div>\n </div>\n\n <!-- Top Bar Buttons -->\n <div class=\"st-actions\" *ngIf=\"config.topBarButtons\">\n <lib-button *ngFor=\"let btn of config.topBarButtons\" \n [variant]=\"btn.btnVariant || 'primary'\"\n [icon]=\"btn.icon || ''\"\n (click)=\"onTopAction(btn)\">\n {{ btn.label }}\n </lib-button>\n </div>\n </div>\n\n <!-- Table Container -->\n <div class=\"st-table-container\">\n <div class=\"st-check-loader\" *ngIf=\"loading\">\n <div class=\"spinner\"></div>\n </div>\n <table class=\"st-table\" [class.loading-data]=\"loading\">\n <thead>\n <tr>\n <th *ngIf=\"config.selectable\" class=\"st-checkbox-col\">\n <input type=\"checkbox\" (change)=\"onSelectAll($event)\">\n </th>\n <th *ngFor=\"let col of config.columns\" \n #stickyHeader\n [class.sortable]=\"col.sortable\"\n [class.sticky-col]=\"col.sticky\"\n [ngStyle]=\"stickyColumnStyles[col.key]\"\n (click)=\"onSort(col)\">\n {{ col.label }}\n <span *ngIf=\"col.sortable\" class=\"sort-icon\">\n <i class=\"fa\" [ngClass]=\"getSortIcon(col.key)\"></i>\n </span>\n </th>\n <th *ngIf=\"config.actions && config.actions.length > 0\">{{ config.labels?.actionColumnHeader || 'Actions' }}</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of data\" \n [class.clickable-row]=\"config.clickableRows\" \n (click)=\"onRowClick(row)\">\n <td *ngIf=\"config.selectable\" class=\"st-checkbox-col\">\n <input type=\"checkbox\" [(ngModel)]=\"row.selected\" (change)=\"onRowSelect(row)\">\n </td>\n <td *ngFor=\"let col of config.columns\" [class.sticky-col]=\"col.sticky\" [ngStyle]=\"stickyColumnStyles[col.key]\">\n <!-- Text/Number/Date -->\n <span *ngIf=\"col.type !== 'custom' && col.type !== 'html' && col.type !== 'badge'\">\n {{ getCellValue(row, col) }}\n </span>\n <!-- HTML -->\n <div *ngIf=\"col.type === 'html'\" [innerHTML]=\"getCellValue(row, col)\"></div>\n <!-- Badge -->\n <span *ngIf=\"col.type === 'badge'\" class=\"st-badge\" [ngClass]=\"getBadgeClass(row, col)\">\n {{ getCellValue(row, col) }}\n </span>\n </td>\n \n <!-- Row Actions -->\n <td *ngIf=\"config.actions && config.actions.length > 0\" class=\"st-row-actions\">\n <div class=\"action-buttons\">\n <ng-container *ngFor=\"let action of config.actions\">\n <lib-button \n [variant]=\"action.btnVariant || 'secondary'\"\n [icon]=\"action.icon || ''\"\n (click)=\"onAction(action, row)\">\n {{ action.label }}\n </lib-button>\n </ng-container>\n </div>\n <!-- Alternatively use specific icons if needed, but button component is requested -->\n </td>\n </tr>\n <tr *ngIf=\"data.length === 0 && !loading\">\n <td [attr.colspan]=\"columnCount + (config.selectable ? 1 : 0) + (config.actions ? 1 : 0)\" class=\"no-data\">\n {{ config.labels?.noDataMessage || 'No data available' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Pagination -->\n <div class=\"st-pagination\" *ngIf=\"config.pagination && config.pagination.enabled\">\n <lib-pagination\n [totalItems]=\"totalItems\"\n [itemsPerPage]=\"config.pagination.pageSize\"\n [currentPage]=\"currentPage\"\n [pageSizeOptions]=\"config.pagination.pageSizeOptions\"\n (pageChange)=\"onPageChange($event)\"\n (itemsPerPageChange)=\"onPageSizeChange($event)\">\n </lib-pagination>\n </div>\n</div>\n", styles: [".smart-table-wrapper{font-family:var(--st-font-family, \"Roboto\", sans-serif);background:var(--st-table-bg, #fff);border-radius:var(--st-border-radius, 8px);box-shadow:var(--st-box-shadow, 0 2px 4px rgba(0, 0, 0, .05));display:flex;flex-direction:column;gap:0;padding:0;border:var(--st-table-border, 1px solid #e0e0e0);overflow:hidden}.st-toolbar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;padding:var(--st-toolbar-padding, 1rem);background:var(--st-toolbar-bg, #fff);border-bottom:var(--st-toolbar-border-bottom, 1px solid #eee);gap:var(--st-toolbar-gap, 1rem)}.st-toolbar .st-search{position:relative;width:var(--st-search-width, auto)}.st-toolbar .st-search input{padding:var(--st-search-padding, .5rem .5rem .5rem 2rem);border:var(--st-search-border, 1px solid #ccc);border-radius:var(--st-search-radius, 4px);background:var(--st-search-bg, #fff);font-size:var(--st-font-size, 14px);width:100%;color:var(--st-text-color, #333)}.st-toolbar .st-search i{position:absolute;left:.75rem;top:50%;transform:translateY(-50%);color:var(--st-search-icon-color, #999)}.st-toolbar .st-filters{display:flex;gap:1rem}.st-toolbar .st-filters select{padding:var(--st-filter-padding, .5rem);border:var(--st-filter-border, 1px solid #ccc);border-radius:var(--st-filter-radius, 4px);font-size:var(--st-filter-font-size, 14px);background:var(--st-filter-bg, #fff);color:var(--st-filter-color, #333)}.st-toolbar .st-actions{display:flex;gap:.5rem}.st-table-container{overflow-x:auto;overflow-y:auto;padding:var(--st-table-padding, 1rem)}.st-table-container::-webkit-scrollbar{width:var(--st-scrollbar-width, 8px);height:var(--st-scrollbar-height, 8px)}.st-table-container::-webkit-scrollbar-track{background:var(--st-scrollbar-track-bg, #f1f1f1);border-radius:var(--st-scrollbar-track-radius, 4px)}.st-table-container::-webkit-scrollbar-thumb{background:var(--st-scrollbar-thumb-bg, #c1c1c1);border-radius:var(--st-scrollbar-thumb-radius, 4px)}.st-table-container::-webkit-scrollbar-thumb:hover{background:var(--st-scrollbar-thumb-hover-bg, #a8a8a8)}.st-table-container.has-sticky-header .st-table thead th{position:sticky;top:0;z-index:10;background:var(--st-header-bg, #f9f9f9);box-shadow:0 1px 2px -1px #0000001a}.st-table-container table{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--st-font-size, 14px)}.st-table-container table thead{background:var(--st-header-bg, #f9f9f9)}.st-table-container table thead th{padding:.75rem 1rem;text-align:left;color:var(--st-header-color, #333);font-weight:var(--st-header-weight, 500);font-size:var(--st-header-size, 14px);text-transform:var(--st-header-transform, none);border-bottom:var(--st-header-border, 1px solid #eee);white-space:nowrap}.st-table-container table thead th.sortable{cursor:pointer}.st-table-container table thead th.sortable:hover{opacity:.8}.st-table-container table thead th .sort-icon{margin-left:.5rem}.st-table-container table thead th .sort-icon .sort-icon{margin-left:.5rem;font-size:var(--st-sort-icon-size, .8em)}.st-table-container table thead th.st-checkbox-col{width:40px}.st-table-container table thead th.sticky-col{position:sticky;z-index:3;background:var(--st-header-bg, #f9f9f9);box-shadow:var(--st-sticky-shadow, 2px 0 5px -2px rgba(0, 0, 0, .1));border-right:var(--st-sticky-border-right, 1px solid rgba(0, 0, 0, .05))}.st-table-container table thead th.sticky-col:first-child{left:0}.st-table-container table tbody tr{background:var(--st-row-bg, #fff)}.st-table-container table tbody tr td{padding:var(--st-cell-padding, 1rem);color:var(--st-text-color, #333);vertical-align:middle;border-bottom:var(--st-row-border, 1px solid #eee)}.st-table-container table tbody tr td.sticky-col{position:sticky;z-index:2;background:var(--st-row-bg, #fff);box-shadow:var(--st-sticky-shadow, 2px 0 5px -2px rgba(0, 0, 0, .1));border-right:var(--st-sticky-border-right, 1px solid rgba(0, 0, 0, .05))}.st-table-container table tbody tr td.sticky-col:first-child{left:0}.st-table-container table tbody tr:hover td,.st-table-container table tbody tr:hover td.sticky-col{background:var(--st-row-hover-bg, #f9f9f9)}.st-table-container table tbody tr.selected td,.st-table-container table tbody tr.selected td.sticky-col{background:var(--st-row-selected-bg, #f3e5f5)}.st-table-container table tbody tr.clickable-row,.st-table-container table tbody tr.clickable-row td{cursor:pointer}.st-table-container table tbody tr.clickable-row:hover td,.st-table-container table tbody tr.clickable-row:hover td.sticky-col{background:var(--st-row-hover-bg, #f5f5f5)}input[type=checkbox]{accent-color:var(--st-checkbox-color, #6200EE);width:var(--st-checkbox-size, 16px);height:var(--st-checkbox-size, 16px);cursor:pointer}.st-badge{display:inline-block;padding:var(--st-badge-padding, 4px 12px);border-radius:var(--st-badge-radius, 12px);font-size:var(--st-badge-font-size, 12px);font-weight:var(--st-badge-font-weight, 500);text-align:center;white-space:nowrap}.st-badge.badge-success{background:var(--st-badge-success-bg, #e8f5e9);color:var(--st-badge-success-color, #2e7d32)}.st-badge.badge-warning{background:var(--st-badge-warning-bg, #fff3e0);color:var(--st-badge-warning-color, #ef6c00)}.st-badge.badge-danger{background:var(--st-badge-danger-bg, #ffebee);color:var(--st-badge-danger-color, #c62828)}.st-badge.badge-info{background:var(--st-badge-info-bg, #e3f2fd);color:var(--st-badge-info-color, #1565c0)}.st-badge.badge-neutral{background:var(--st-badge-neutral-bg, #f5f5f5);color:var(--st-badge-neutral-color, #616161)}.st-row-actions .action-buttons{display:flex;gap:.5rem;align-items:center}.no-data{text-align:center;padding:2rem;color:var(--st-no-data-color, #888)}.st-pagination{padding:var(--st-pagination-padding, 1rem);border-top:var(--st-pagination-border-top, none)}@media(max-width:768px){.st-toolbar{flex-direction:column;align-items:stretch}.st-toolbar .st-search,.st-toolbar .st-filters,.st-toolbar .st-actions,.st-toolbar .st-search input{width:100%}}.st-table-container{position:relative;min-height:200px}.st-table-container .st-table.loading-data{opacity:.5;pointer-events:none}.st-table-container .st-check-loader{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;justify-content:center;align-items:center;z-index:10}.st-table-container .st-check-loader .spinner{width:40px;height:40px;border:4px solid var(--st-spinner-border-color, rgba(0, 0, 0, .1));border-left-color:var(--st-loader-color);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ 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: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: PaginationComponent, selector: "lib-pagination", inputs: ["totalItems", "itemsPerPage", "currentPage", "pageSizeOptions", "theme", "labels"], outputs: ["pageChange", "itemsPerPageChange"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["variant", "type", "disabled", "width", "height", "borderRadius", "fontSize", "fontWeight", "backgroundColor", "color", "border", "icon"] }] });
5453
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SmartTableComponent, isStandalone: false, selector: "lib-smart-table", inputs: { config: "config" }, outputs: { action: "action", topAction: "topAction", filterChange: "filterChange", rowSelect: "rowSelect", columnClick: "columnClick" }, viewQueries: [{ propertyName: "stickyHeaders", predicate: ["stickyHeader"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"smart-table-wrapper\">\n <!-- Top Toolbar -->\n <div class=\"st-toolbar\" *ngIf=\"config.searchConfig?.enabled || (config.filters && config.filters.length > 0) || (config.topBarButtons && config.topBarButtons.length > 0)\">\n \n <!-- Search -->\n <div class=\"st-search\" *ngIf=\"config.searchConfig?.enabled\">\n <i class=\"fa fa-search\"></i>\n <input type=\"text\" [placeholder]=\"config.labels?.searchPlaceholder || 'Search'\" (input)=\"onSearch($event)\">\n </div>\n\n <!-- Filters -->\n <div class=\"st-filters\" *ngIf=\"config.filters\">\n <div class=\"st-filter-item\" *ngFor=\"let filter of config.filters\">\n <select (change)=\"onFilterChange(filter.key, $event)\">\n <option value=\"\">{{ filter.label }}</option>\n <option *ngFor=\"let opt of filter.options\" [value]=\"opt.value\">{{ opt.label }}</option>\n </select>\n </div>\n </div>\n\n <!-- Top Bar Buttons -->\n <div class=\"st-actions\" *ngIf=\"config.topBarButtons\">\n <lib-button *ngFor=\"let btn of config.topBarButtons\" \n [variant]=\"btn.btnVariant || 'primary'\"\n [icon]=\"btn.icon || ''\"\n (click)=\"onTopAction(btn)\">\n {{ btn.label }}\n </lib-button>\n </div>\n </div>\n\n <!-- Table Container -->\n <div class=\"st-table-container\">\n <div class=\"st-check-loader\" *ngIf=\"loading\">\n <div class=\"spinner\"></div>\n </div>\n <table class=\"st-table\" [class.loading-data]=\"loading\">\n <thead>\n <tr>\n <th *ngIf=\"config.selectable\" class=\"st-checkbox-col\">\n <input type=\"checkbox\" (change)=\"onSelectAll($event)\">\n </th>\n <th *ngFor=\"let col of config.columns\" \n #stickyHeader\n [class.sortable]=\"col.sortable\"\n [class.sticky-col]=\"col.sticky\"\n [ngStyle]=\"stickyColumnStyles[col.key]\"\n (click)=\"onSort(col)\">\n {{ col.label }}\n <span *ngIf=\"col.sortable\" class=\"sort-icon\">\n <i class=\"fa\" [ngClass]=\"getSortIcon(col.key)\"></i>\n </span>\n </th>\n <th *ngIf=\"config.actions && config.actions.length > 0\">{{ config.labels?.actionColumnHeader || 'Actions' }}</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of data\">\n <td *ngIf=\"config.selectable\" class=\"st-checkbox-col\">\n <input type=\"checkbox\" [(ngModel)]=\"row.selected\" (change)=\"onRowSelect(row)\">\n </td>\n <td *ngFor=\"let col of config.columns\" \n [class.sticky-col]=\"col.sticky\" \n [ngStyle]=\"stickyColumnStyles[col.key]\"\n [class.clickable-cell]=\"col.clickAction\"\n (click)=\"onColumnClick(row, col)\">\n <!-- Text/Number/Date -->\n <span *ngIf=\"col.type !== 'custom' && col.type !== 'html' && col.type !== 'badge'\">\n {{ getCellValue(row, col) }}\n </span>\n <!-- HTML -->\n <div *ngIf=\"col.type === 'html'\" [innerHTML]=\"getCellValue(row, col)\"></div>\n <!-- Badge -->\n <span *ngIf=\"col.type === 'badge'\" class=\"st-badge\" [ngClass]=\"getBadgeClass(row, col)\">\n {{ getCellValue(row, col) }}\n </span>\n </td>\n \n <!-- Row Actions -->\n <td *ngIf=\"config.actions && config.actions.length > 0\" class=\"st-row-actions\">\n <div class=\"action-buttons\">\n <ng-container *ngFor=\"let action of config.actions\">\n <lib-button \n [variant]=\"action.btnVariant || 'secondary'\"\n [icon]=\"action.icon || ''\"\n (click)=\"onAction(action, row)\">\n {{ action.label }}\n </lib-button>\n </ng-container>\n </div>\n <!-- Alternatively use specific icons if needed, but button component is requested -->\n </td>\n </tr>\n <tr *ngIf=\"data.length === 0 && !loading\">\n <td [attr.colspan]=\"columnCount + (config.selectable ? 1 : 0) + (config.actions ? 1 : 0)\" class=\"no-data\">\n {{ config.labels?.noDataMessage || 'No data available' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Pagination -->\n <div class=\"st-pagination\" *ngIf=\"config.pagination && config.pagination.enabled\">\n <lib-pagination\n [totalItems]=\"totalItems\"\n [itemsPerPage]=\"config.pagination.pageSize\"\n [currentPage]=\"currentPage\"\n [pageSizeOptions]=\"config.pagination.pageSizeOptions\"\n (pageChange)=\"onPageChange($event)\"\n (itemsPerPageChange)=\"onPageSizeChange($event)\">\n </lib-pagination>\n </div>\n</div>\n", styles: [".smart-table-wrapper{font-family:var(--st-font-family, \"Roboto\", sans-serif);background:var(--st-table-bg, #fff);border-radius:var(--st-border-radius, 8px);box-shadow:var(--st-box-shadow, 0 2px 4px rgba(0, 0, 0, .05));display:flex;flex-direction:column;gap:0;padding:0;border:var(--st-table-border, 1px solid #e0e0e0);overflow:hidden}.st-toolbar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;padding:var(--st-toolbar-padding, 1rem);background:var(--st-toolbar-bg, #fff);border-bottom:var(--st-toolbar-border-bottom, 1px solid #eee);gap:var(--st-toolbar-gap, 1rem)}.st-toolbar .st-search{position:relative;width:var(--st-search-width, auto)}.st-toolbar .st-search input{padding:var(--st-search-padding, .5rem .5rem .5rem 2rem);border:var(--st-search-border, 1px solid #ccc);border-radius:var(--st-search-radius, 4px);background:var(--st-search-bg, #fff);font-size:var(--st-font-size, 14px);width:100%;color:var(--st-text-color, #333)}.st-toolbar .st-search i{position:absolute;left:.75rem;top:50%;transform:translateY(-50%);color:var(--st-search-icon-color, #999)}.st-toolbar .st-filters{display:flex;gap:1rem}.st-toolbar .st-filters select{padding:var(--st-filter-padding, .5rem);border:var(--st-filter-border, 1px solid #ccc);border-radius:var(--st-filter-radius, 4px);font-size:var(--st-filter-font-size, 14px);background:var(--st-filter-bg, #fff);color:var(--st-filter-color, #333)}.st-toolbar .st-actions{display:flex;gap:.5rem}.st-table-container{overflow-x:auto;overflow-y:auto;padding:var(--st-table-padding, 1rem)}.st-table-container::-webkit-scrollbar{width:var(--st-scrollbar-width, 8px);height:var(--st-scrollbar-height, 8px)}.st-table-container::-webkit-scrollbar-track{background:var(--st-scrollbar-track-bg, #f1f1f1);border-radius:var(--st-scrollbar-track-radius, 4px)}.st-table-container::-webkit-scrollbar-thumb{background:var(--st-scrollbar-thumb-bg, #c1c1c1);border-radius:var(--st-scrollbar-thumb-radius, 4px)}.st-table-container::-webkit-scrollbar-thumb:hover{background:var(--st-scrollbar-thumb-hover-bg, #a8a8a8)}.st-table-container.has-sticky-header .st-table thead th{position:sticky;top:0;z-index:10;background:var(--st-header-bg, #f9f9f9);box-shadow:0 1px 2px -1px #0000001a}.st-table-container table{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--st-font-size, 14px)}.st-table-container table thead{background:var(--st-header-bg, #f9f9f9)}.st-table-container table thead th{padding:.75rem 1rem;text-align:left;color:var(--st-header-color, #333);font-weight:var(--st-header-weight, 500);font-size:var(--st-header-size, 14px);text-transform:var(--st-header-transform, none);border-bottom:var(--st-header-border, 1px solid #eee);white-space:nowrap}.st-table-container table thead th.sortable{cursor:pointer}.st-table-container table thead th.sortable:hover{opacity:.8}.st-table-container table thead th .sort-icon{margin-left:.5rem}.st-table-container table thead th .sort-icon .sort-icon{margin-left:.5rem;font-size:var(--st-sort-icon-size, .8em)}.st-table-container table thead th.st-checkbox-col{width:40px}.st-table-container table thead th.sticky-col{position:sticky;z-index:3;background:var(--st-header-bg, #f9f9f9);box-shadow:var(--st-sticky-shadow, 2px 0 5px -2px rgba(0, 0, 0, .1));border-right:var(--st-sticky-border-right, 1px solid rgba(0, 0, 0, .05))}.st-table-container table thead th.sticky-col:first-child{left:0}.st-table-container table tbody tr{background:var(--st-row-bg, #fff)}.st-table-container table tbody tr td{padding:var(--st-cell-padding, 1rem);color:var(--st-text-color, #333);vertical-align:middle;border-bottom:var(--st-row-border, 1px solid #eee)}.st-table-container table tbody tr td.sticky-col{position:sticky;z-index:2;background:var(--st-row-bg, #fff);box-shadow:var(--st-sticky-shadow, 2px 0 5px -2px rgba(0, 0, 0, .1));border-right:var(--st-sticky-border-right, 1px solid rgba(0, 0, 0, .05))}.st-table-container table tbody tr td.sticky-col:first-child{left:0}.st-table-container table tbody tr:hover td,.st-table-container table tbody tr:hover td.sticky-col{background:var(--st-row-hover-bg, #f9f9f9)}.st-table-container table tbody tr.selected td,.st-table-container table tbody tr.selected td.sticky-col{background:var(--st-row-selected-bg, #f3e5f5)}.st-table-container table tbody tr .clickable-cell{cursor:pointer;transition:background .2s}.st-table-container table tbody tr .clickable-cell:hover{background:var(--st-cell-hover-bg, #f0f0f0)!important}input[type=checkbox]{accent-color:var(--st-checkbox-color, #6200EE);width:var(--st-checkbox-size, 16px);height:var(--st-checkbox-size, 16px);cursor:pointer}.st-badge{display:inline-block;padding:var(--st-badge-padding, 4px 12px);border-radius:var(--st-badge-radius, 12px);font-size:var(--st-badge-font-size, 12px);font-weight:var(--st-badge-font-weight, 500);text-align:center;white-space:nowrap}.st-badge.badge-success{background:var(--st-badge-success-bg, #e8f5e9);color:var(--st-badge-success-color, #2e7d32)}.st-badge.badge-warning{background:var(--st-badge-warning-bg, #fff3e0);color:var(--st-badge-warning-color, #ef6c00)}.st-badge.badge-danger{background:var(--st-badge-danger-bg, #ffebee);color:var(--st-badge-danger-color, #c62828)}.st-badge.badge-info{background:var(--st-badge-info-bg, #e3f2fd);color:var(--st-badge-info-color, #1565c0)}.st-badge.badge-neutral{background:var(--st-badge-neutral-bg, #f5f5f5);color:var(--st-badge-neutral-color, #616161)}.st-row-actions .action-buttons{display:flex;gap:.5rem;align-items:center}.no-data{text-align:center;padding:2rem;color:var(--st-no-data-color, #888)}.st-pagination{padding:var(--st-pagination-padding, 1rem);border-top:var(--st-pagination-border-top, none)}@media(max-width:768px){.st-toolbar{flex-direction:column;align-items:stretch}.st-toolbar .st-search,.st-toolbar .st-filters,.st-toolbar .st-actions,.st-toolbar .st-search input{width:100%}}.st-table-container{position:relative;min-height:200px}.st-table-container .st-table.loading-data{opacity:.5;pointer-events:none}.st-table-container .st-check-loader{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;justify-content:center;align-items:center;z-index:10}.st-table-container .st-check-loader .spinner{width:40px;height:40px;border:4px solid var(--st-spinner-border-color, rgba(0, 0, 0, .1));border-left-color:var(--st-loader-color);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ 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: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: PaginationComponent, selector: "lib-pagination", inputs: ["totalItems", "itemsPerPage", "currentPage", "pageSizeOptions", "theme", "labels"], outputs: ["pageChange", "itemsPerPageChange"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["variant", "type", "disabled", "width", "height", "borderRadius", "fontSize", "fontWeight", "backgroundColor", "color", "border", "icon", "labels"] }] });
3197
5454
  }
3198
5455
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SmartTableComponent, decorators: [{
3199
5456
  type: Component,
3200
- args: [{ selector: 'lib-smart-table', standalone: false, template: "<div class=\"smart-table-wrapper\">\n <!-- Top Toolbar -->\n <div class=\"st-toolbar\" *ngIf=\"config.searchConfig?.enabled || (config.filters && config.filters.length > 0) || (config.topBarButtons && config.topBarButtons.length > 0)\">\n \n <!-- Search -->\n <div class=\"st-search\" *ngIf=\"config.searchConfig?.enabled\">\n <i class=\"fa fa-search\"></i>\n <input type=\"text\" [placeholder]=\"config.labels?.searchPlaceholder || 'Search'\" (input)=\"onSearch($event)\">\n </div>\n\n <!-- Filters -->\n <div class=\"st-filters\" *ngIf=\"config.filters\">\n <div class=\"st-filter-item\" *ngFor=\"let filter of config.filters\">\n <select (change)=\"onFilterChange(filter.key, $event)\">\n <option value=\"\">{{ filter.label }}</option>\n <option *ngFor=\"let opt of filter.options\" [value]=\"opt.value\">{{ opt.label }}</option>\n </select>\n </div>\n </div>\n\n <!-- Top Bar Buttons -->\n <div class=\"st-actions\" *ngIf=\"config.topBarButtons\">\n <lib-button *ngFor=\"let btn of config.topBarButtons\" \n [variant]=\"btn.btnVariant || 'primary'\"\n [icon]=\"btn.icon || ''\"\n (click)=\"onTopAction(btn)\">\n {{ btn.label }}\n </lib-button>\n </div>\n </div>\n\n <!-- Table Container -->\n <div class=\"st-table-container\">\n <div class=\"st-check-loader\" *ngIf=\"loading\">\n <div class=\"spinner\"></div>\n </div>\n <table class=\"st-table\" [class.loading-data]=\"loading\">\n <thead>\n <tr>\n <th *ngIf=\"config.selectable\" class=\"st-checkbox-col\">\n <input type=\"checkbox\" (change)=\"onSelectAll($event)\">\n </th>\n <th *ngFor=\"let col of config.columns\" \n #stickyHeader\n [class.sortable]=\"col.sortable\"\n [class.sticky-col]=\"col.sticky\"\n [ngStyle]=\"stickyColumnStyles[col.key]\"\n (click)=\"onSort(col)\">\n {{ col.label }}\n <span *ngIf=\"col.sortable\" class=\"sort-icon\">\n <i class=\"fa\" [ngClass]=\"getSortIcon(col.key)\"></i>\n </span>\n </th>\n <th *ngIf=\"config.actions && config.actions.length > 0\">{{ config.labels?.actionColumnHeader || 'Actions' }}</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of data\" \n [class.clickable-row]=\"config.clickableRows\" \n (click)=\"onRowClick(row)\">\n <td *ngIf=\"config.selectable\" class=\"st-checkbox-col\">\n <input type=\"checkbox\" [(ngModel)]=\"row.selected\" (change)=\"onRowSelect(row)\">\n </td>\n <td *ngFor=\"let col of config.columns\" [class.sticky-col]=\"col.sticky\" [ngStyle]=\"stickyColumnStyles[col.key]\">\n <!-- Text/Number/Date -->\n <span *ngIf=\"col.type !== 'custom' && col.type !== 'html' && col.type !== 'badge'\">\n {{ getCellValue(row, col) }}\n </span>\n <!-- HTML -->\n <div *ngIf=\"col.type === 'html'\" [innerHTML]=\"getCellValue(row, col)\"></div>\n <!-- Badge -->\n <span *ngIf=\"col.type === 'badge'\" class=\"st-badge\" [ngClass]=\"getBadgeClass(row, col)\">\n {{ getCellValue(row, col) }}\n </span>\n </td>\n \n <!-- Row Actions -->\n <td *ngIf=\"config.actions && config.actions.length > 0\" class=\"st-row-actions\">\n <div class=\"action-buttons\">\n <ng-container *ngFor=\"let action of config.actions\">\n <lib-button \n [variant]=\"action.btnVariant || 'secondary'\"\n [icon]=\"action.icon || ''\"\n (click)=\"onAction(action, row)\">\n {{ action.label }}\n </lib-button>\n </ng-container>\n </div>\n <!-- Alternatively use specific icons if needed, but button component is requested -->\n </td>\n </tr>\n <tr *ngIf=\"data.length === 0 && !loading\">\n <td [attr.colspan]=\"columnCount + (config.selectable ? 1 : 0) + (config.actions ? 1 : 0)\" class=\"no-data\">\n {{ config.labels?.noDataMessage || 'No data available' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Pagination -->\n <div class=\"st-pagination\" *ngIf=\"config.pagination && config.pagination.enabled\">\n <lib-pagination\n [totalItems]=\"totalItems\"\n [itemsPerPage]=\"config.pagination.pageSize\"\n [currentPage]=\"currentPage\"\n [pageSizeOptions]=\"config.pagination.pageSizeOptions\"\n (pageChange)=\"onPageChange($event)\"\n (itemsPerPageChange)=\"onPageSizeChange($event)\">\n </lib-pagination>\n </div>\n</div>\n", styles: [".smart-table-wrapper{font-family:var(--st-font-family, \"Roboto\", sans-serif);background:var(--st-table-bg, #fff);border-radius:var(--st-border-radius, 8px);box-shadow:var(--st-box-shadow, 0 2px 4px rgba(0, 0, 0, .05));display:flex;flex-direction:column;gap:0;padding:0;border:var(--st-table-border, 1px solid #e0e0e0);overflow:hidden}.st-toolbar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;padding:var(--st-toolbar-padding, 1rem);background:var(--st-toolbar-bg, #fff);border-bottom:var(--st-toolbar-border-bottom, 1px solid #eee);gap:var(--st-toolbar-gap, 1rem)}.st-toolbar .st-search{position:relative;width:var(--st-search-width, auto)}.st-toolbar .st-search input{padding:var(--st-search-padding, .5rem .5rem .5rem 2rem);border:var(--st-search-border, 1px solid #ccc);border-radius:var(--st-search-radius, 4px);background:var(--st-search-bg, #fff);font-size:var(--st-font-size, 14px);width:100%;color:var(--st-text-color, #333)}.st-toolbar .st-search i{position:absolute;left:.75rem;top:50%;transform:translateY(-50%);color:var(--st-search-icon-color, #999)}.st-toolbar .st-filters{display:flex;gap:1rem}.st-toolbar .st-filters select{padding:var(--st-filter-padding, .5rem);border:var(--st-filter-border, 1px solid #ccc);border-radius:var(--st-filter-radius, 4px);font-size:var(--st-filter-font-size, 14px);background:var(--st-filter-bg, #fff);color:var(--st-filter-color, #333)}.st-toolbar .st-actions{display:flex;gap:.5rem}.st-table-container{overflow-x:auto;overflow-y:auto;padding:var(--st-table-padding, 1rem)}.st-table-container::-webkit-scrollbar{width:var(--st-scrollbar-width, 8px);height:var(--st-scrollbar-height, 8px)}.st-table-container::-webkit-scrollbar-track{background:var(--st-scrollbar-track-bg, #f1f1f1);border-radius:var(--st-scrollbar-track-radius, 4px)}.st-table-container::-webkit-scrollbar-thumb{background:var(--st-scrollbar-thumb-bg, #c1c1c1);border-radius:var(--st-scrollbar-thumb-radius, 4px)}.st-table-container::-webkit-scrollbar-thumb:hover{background:var(--st-scrollbar-thumb-hover-bg, #a8a8a8)}.st-table-container.has-sticky-header .st-table thead th{position:sticky;top:0;z-index:10;background:var(--st-header-bg, #f9f9f9);box-shadow:0 1px 2px -1px #0000001a}.st-table-container table{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--st-font-size, 14px)}.st-table-container table thead{background:var(--st-header-bg, #f9f9f9)}.st-table-container table thead th{padding:.75rem 1rem;text-align:left;color:var(--st-header-color, #333);font-weight:var(--st-header-weight, 500);font-size:var(--st-header-size, 14px);text-transform:var(--st-header-transform, none);border-bottom:var(--st-header-border, 1px solid #eee);white-space:nowrap}.st-table-container table thead th.sortable{cursor:pointer}.st-table-container table thead th.sortable:hover{opacity:.8}.st-table-container table thead th .sort-icon{margin-left:.5rem}.st-table-container table thead th .sort-icon .sort-icon{margin-left:.5rem;font-size:var(--st-sort-icon-size, .8em)}.st-table-container table thead th.st-checkbox-col{width:40px}.st-table-container table thead th.sticky-col{position:sticky;z-index:3;background:var(--st-header-bg, #f9f9f9);box-shadow:var(--st-sticky-shadow, 2px 0 5px -2px rgba(0, 0, 0, .1));border-right:var(--st-sticky-border-right, 1px solid rgba(0, 0, 0, .05))}.st-table-container table thead th.sticky-col:first-child{left:0}.st-table-container table tbody tr{background:var(--st-row-bg, #fff)}.st-table-container table tbody tr td{padding:var(--st-cell-padding, 1rem);color:var(--st-text-color, #333);vertical-align:middle;border-bottom:var(--st-row-border, 1px solid #eee)}.st-table-container table tbody tr td.sticky-col{position:sticky;z-index:2;background:var(--st-row-bg, #fff);box-shadow:var(--st-sticky-shadow, 2px 0 5px -2px rgba(0, 0, 0, .1));border-right:var(--st-sticky-border-right, 1px solid rgba(0, 0, 0, .05))}.st-table-container table tbody tr td.sticky-col:first-child{left:0}.st-table-container table tbody tr:hover td,.st-table-container table tbody tr:hover td.sticky-col{background:var(--st-row-hover-bg, #f9f9f9)}.st-table-container table tbody tr.selected td,.st-table-container table tbody tr.selected td.sticky-col{background:var(--st-row-selected-bg, #f3e5f5)}.st-table-container table tbody tr.clickable-row,.st-table-container table tbody tr.clickable-row td{cursor:pointer}.st-table-container table tbody tr.clickable-row:hover td,.st-table-container table tbody tr.clickable-row:hover td.sticky-col{background:var(--st-row-hover-bg, #f5f5f5)}input[type=checkbox]{accent-color:var(--st-checkbox-color, #6200EE);width:var(--st-checkbox-size, 16px);height:var(--st-checkbox-size, 16px);cursor:pointer}.st-badge{display:inline-block;padding:var(--st-badge-padding, 4px 12px);border-radius:var(--st-badge-radius, 12px);font-size:var(--st-badge-font-size, 12px);font-weight:var(--st-badge-font-weight, 500);text-align:center;white-space:nowrap}.st-badge.badge-success{background:var(--st-badge-success-bg, #e8f5e9);color:var(--st-badge-success-color, #2e7d32)}.st-badge.badge-warning{background:var(--st-badge-warning-bg, #fff3e0);color:var(--st-badge-warning-color, #ef6c00)}.st-badge.badge-danger{background:var(--st-badge-danger-bg, #ffebee);color:var(--st-badge-danger-color, #c62828)}.st-badge.badge-info{background:var(--st-badge-info-bg, #e3f2fd);color:var(--st-badge-info-color, #1565c0)}.st-badge.badge-neutral{background:var(--st-badge-neutral-bg, #f5f5f5);color:var(--st-badge-neutral-color, #616161)}.st-row-actions .action-buttons{display:flex;gap:.5rem;align-items:center}.no-data{text-align:center;padding:2rem;color:var(--st-no-data-color, #888)}.st-pagination{padding:var(--st-pagination-padding, 1rem);border-top:var(--st-pagination-border-top, none)}@media(max-width:768px){.st-toolbar{flex-direction:column;align-items:stretch}.st-toolbar .st-search,.st-toolbar .st-filters,.st-toolbar .st-actions,.st-toolbar .st-search input{width:100%}}.st-table-container{position:relative;min-height:200px}.st-table-container .st-table.loading-data{opacity:.5;pointer-events:none}.st-table-container .st-check-loader{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;justify-content:center;align-items:center;z-index:10}.st-table-container .st-check-loader .spinner{width:40px;height:40px;border:4px solid var(--st-spinner-border-color, rgba(0, 0, 0, .1));border-left-color:var(--st-loader-color);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
5457
+ args: [{ selector: 'lib-smart-table', standalone: false, template: "<div class=\"smart-table-wrapper\">\n <!-- Top Toolbar -->\n <div class=\"st-toolbar\" *ngIf=\"config.searchConfig?.enabled || (config.filters && config.filters.length > 0) || (config.topBarButtons && config.topBarButtons.length > 0)\">\n \n <!-- Search -->\n <div class=\"st-search\" *ngIf=\"config.searchConfig?.enabled\">\n <i class=\"fa fa-search\"></i>\n <input type=\"text\" [placeholder]=\"config.labels?.searchPlaceholder || 'Search'\" (input)=\"onSearch($event)\">\n </div>\n\n <!-- Filters -->\n <div class=\"st-filters\" *ngIf=\"config.filters\">\n <div class=\"st-filter-item\" *ngFor=\"let filter of config.filters\">\n <select (change)=\"onFilterChange(filter.key, $event)\">\n <option value=\"\">{{ filter.label }}</option>\n <option *ngFor=\"let opt of filter.options\" [value]=\"opt.value\">{{ opt.label }}</option>\n </select>\n </div>\n </div>\n\n <!-- Top Bar Buttons -->\n <div class=\"st-actions\" *ngIf=\"config.topBarButtons\">\n <lib-button *ngFor=\"let btn of config.topBarButtons\" \n [variant]=\"btn.btnVariant || 'primary'\"\n [icon]=\"btn.icon || ''\"\n (click)=\"onTopAction(btn)\">\n {{ btn.label }}\n </lib-button>\n </div>\n </div>\n\n <!-- Table Container -->\n <div class=\"st-table-container\">\n <div class=\"st-check-loader\" *ngIf=\"loading\">\n <div class=\"spinner\"></div>\n </div>\n <table class=\"st-table\" [class.loading-data]=\"loading\">\n <thead>\n <tr>\n <th *ngIf=\"config.selectable\" class=\"st-checkbox-col\">\n <input type=\"checkbox\" (change)=\"onSelectAll($event)\">\n </th>\n <th *ngFor=\"let col of config.columns\" \n #stickyHeader\n [class.sortable]=\"col.sortable\"\n [class.sticky-col]=\"col.sticky\"\n [ngStyle]=\"stickyColumnStyles[col.key]\"\n (click)=\"onSort(col)\">\n {{ col.label }}\n <span *ngIf=\"col.sortable\" class=\"sort-icon\">\n <i class=\"fa\" [ngClass]=\"getSortIcon(col.key)\"></i>\n </span>\n </th>\n <th *ngIf=\"config.actions && config.actions.length > 0\">{{ config.labels?.actionColumnHeader || 'Actions' }}</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of data\">\n <td *ngIf=\"config.selectable\" class=\"st-checkbox-col\">\n <input type=\"checkbox\" [(ngModel)]=\"row.selected\" (change)=\"onRowSelect(row)\">\n </td>\n <td *ngFor=\"let col of config.columns\" \n [class.sticky-col]=\"col.sticky\" \n [ngStyle]=\"stickyColumnStyles[col.key]\"\n [class.clickable-cell]=\"col.clickAction\"\n (click)=\"onColumnClick(row, col)\">\n <!-- Text/Number/Date -->\n <span *ngIf=\"col.type !== 'custom' && col.type !== 'html' && col.type !== 'badge'\">\n {{ getCellValue(row, col) }}\n </span>\n <!-- HTML -->\n <div *ngIf=\"col.type === 'html'\" [innerHTML]=\"getCellValue(row, col)\"></div>\n <!-- Badge -->\n <span *ngIf=\"col.type === 'badge'\" class=\"st-badge\" [ngClass]=\"getBadgeClass(row, col)\">\n {{ getCellValue(row, col) }}\n </span>\n </td>\n \n <!-- Row Actions -->\n <td *ngIf=\"config.actions && config.actions.length > 0\" class=\"st-row-actions\">\n <div class=\"action-buttons\">\n <ng-container *ngFor=\"let action of config.actions\">\n <lib-button \n [variant]=\"action.btnVariant || 'secondary'\"\n [icon]=\"action.icon || ''\"\n (click)=\"onAction(action, row)\">\n {{ action.label }}\n </lib-button>\n </ng-container>\n </div>\n <!-- Alternatively use specific icons if needed, but button component is requested -->\n </td>\n </tr>\n <tr *ngIf=\"data.length === 0 && !loading\">\n <td [attr.colspan]=\"columnCount + (config.selectable ? 1 : 0) + (config.actions ? 1 : 0)\" class=\"no-data\">\n {{ config.labels?.noDataMessage || 'No data available' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Pagination -->\n <div class=\"st-pagination\" *ngIf=\"config.pagination && config.pagination.enabled\">\n <lib-pagination\n [totalItems]=\"totalItems\"\n [itemsPerPage]=\"config.pagination.pageSize\"\n [currentPage]=\"currentPage\"\n [pageSizeOptions]=\"config.pagination.pageSizeOptions\"\n (pageChange)=\"onPageChange($event)\"\n (itemsPerPageChange)=\"onPageSizeChange($event)\">\n </lib-pagination>\n </div>\n</div>\n", styles: [".smart-table-wrapper{font-family:var(--st-font-family, \"Roboto\", sans-serif);background:var(--st-table-bg, #fff);border-radius:var(--st-border-radius, 8px);box-shadow:var(--st-box-shadow, 0 2px 4px rgba(0, 0, 0, .05));display:flex;flex-direction:column;gap:0;padding:0;border:var(--st-table-border, 1px solid #e0e0e0);overflow:hidden}.st-toolbar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;padding:var(--st-toolbar-padding, 1rem);background:var(--st-toolbar-bg, #fff);border-bottom:var(--st-toolbar-border-bottom, 1px solid #eee);gap:var(--st-toolbar-gap, 1rem)}.st-toolbar .st-search{position:relative;width:var(--st-search-width, auto)}.st-toolbar .st-search input{padding:var(--st-search-padding, .5rem .5rem .5rem 2rem);border:var(--st-search-border, 1px solid #ccc);border-radius:var(--st-search-radius, 4px);background:var(--st-search-bg, #fff);font-size:var(--st-font-size, 14px);width:100%;color:var(--st-text-color, #333)}.st-toolbar .st-search i{position:absolute;left:.75rem;top:50%;transform:translateY(-50%);color:var(--st-search-icon-color, #999)}.st-toolbar .st-filters{display:flex;gap:1rem}.st-toolbar .st-filters select{padding:var(--st-filter-padding, .5rem);border:var(--st-filter-border, 1px solid #ccc);border-radius:var(--st-filter-radius, 4px);font-size:var(--st-filter-font-size, 14px);background:var(--st-filter-bg, #fff);color:var(--st-filter-color, #333)}.st-toolbar .st-actions{display:flex;gap:.5rem}.st-table-container{overflow-x:auto;overflow-y:auto;padding:var(--st-table-padding, 1rem)}.st-table-container::-webkit-scrollbar{width:var(--st-scrollbar-width, 8px);height:var(--st-scrollbar-height, 8px)}.st-table-container::-webkit-scrollbar-track{background:var(--st-scrollbar-track-bg, #f1f1f1);border-radius:var(--st-scrollbar-track-radius, 4px)}.st-table-container::-webkit-scrollbar-thumb{background:var(--st-scrollbar-thumb-bg, #c1c1c1);border-radius:var(--st-scrollbar-thumb-radius, 4px)}.st-table-container::-webkit-scrollbar-thumb:hover{background:var(--st-scrollbar-thumb-hover-bg, #a8a8a8)}.st-table-container.has-sticky-header .st-table thead th{position:sticky;top:0;z-index:10;background:var(--st-header-bg, #f9f9f9);box-shadow:0 1px 2px -1px #0000001a}.st-table-container table{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--st-font-size, 14px)}.st-table-container table thead{background:var(--st-header-bg, #f9f9f9)}.st-table-container table thead th{padding:.75rem 1rem;text-align:left;color:var(--st-header-color, #333);font-weight:var(--st-header-weight, 500);font-size:var(--st-header-size, 14px);text-transform:var(--st-header-transform, none);border-bottom:var(--st-header-border, 1px solid #eee);white-space:nowrap}.st-table-container table thead th.sortable{cursor:pointer}.st-table-container table thead th.sortable:hover{opacity:.8}.st-table-container table thead th .sort-icon{margin-left:.5rem}.st-table-container table thead th .sort-icon .sort-icon{margin-left:.5rem;font-size:var(--st-sort-icon-size, .8em)}.st-table-container table thead th.st-checkbox-col{width:40px}.st-table-container table thead th.sticky-col{position:sticky;z-index:3;background:var(--st-header-bg, #f9f9f9);box-shadow:var(--st-sticky-shadow, 2px 0 5px -2px rgba(0, 0, 0, .1));border-right:var(--st-sticky-border-right, 1px solid rgba(0, 0, 0, .05))}.st-table-container table thead th.sticky-col:first-child{left:0}.st-table-container table tbody tr{background:var(--st-row-bg, #fff)}.st-table-container table tbody tr td{padding:var(--st-cell-padding, 1rem);color:var(--st-text-color, #333);vertical-align:middle;border-bottom:var(--st-row-border, 1px solid #eee)}.st-table-container table tbody tr td.sticky-col{position:sticky;z-index:2;background:var(--st-row-bg, #fff);box-shadow:var(--st-sticky-shadow, 2px 0 5px -2px rgba(0, 0, 0, .1));border-right:var(--st-sticky-border-right, 1px solid rgba(0, 0, 0, .05))}.st-table-container table tbody tr td.sticky-col:first-child{left:0}.st-table-container table tbody tr:hover td,.st-table-container table tbody tr:hover td.sticky-col{background:var(--st-row-hover-bg, #f9f9f9)}.st-table-container table tbody tr.selected td,.st-table-container table tbody tr.selected td.sticky-col{background:var(--st-row-selected-bg, #f3e5f5)}.st-table-container table tbody tr .clickable-cell{cursor:pointer;transition:background .2s}.st-table-container table tbody tr .clickable-cell:hover{background:var(--st-cell-hover-bg, #f0f0f0)!important}input[type=checkbox]{accent-color:var(--st-checkbox-color, #6200EE);width:var(--st-checkbox-size, 16px);height:var(--st-checkbox-size, 16px);cursor:pointer}.st-badge{display:inline-block;padding:var(--st-badge-padding, 4px 12px);border-radius:var(--st-badge-radius, 12px);font-size:var(--st-badge-font-size, 12px);font-weight:var(--st-badge-font-weight, 500);text-align:center;white-space:nowrap}.st-badge.badge-success{background:var(--st-badge-success-bg, #e8f5e9);color:var(--st-badge-success-color, #2e7d32)}.st-badge.badge-warning{background:var(--st-badge-warning-bg, #fff3e0);color:var(--st-badge-warning-color, #ef6c00)}.st-badge.badge-danger{background:var(--st-badge-danger-bg, #ffebee);color:var(--st-badge-danger-color, #c62828)}.st-badge.badge-info{background:var(--st-badge-info-bg, #e3f2fd);color:var(--st-badge-info-color, #1565c0)}.st-badge.badge-neutral{background:var(--st-badge-neutral-bg, #f5f5f5);color:var(--st-badge-neutral-color, #616161)}.st-row-actions .action-buttons{display:flex;gap:.5rem;align-items:center}.no-data{text-align:center;padding:2rem;color:var(--st-no-data-color, #888)}.st-pagination{padding:var(--st-pagination-padding, 1rem);border-top:var(--st-pagination-border-top, none)}@media(max-width:768px){.st-toolbar{flex-direction:column;align-items:stretch}.st-toolbar .st-search,.st-toolbar .st-filters,.st-toolbar .st-actions,.st-toolbar .st-search input{width:100%}}.st-table-container{position:relative;min-height:200px}.st-table-container .st-table.loading-data{opacity:.5;pointer-events:none}.st-table-container .st-check-loader{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;justify-content:center;align-items:center;z-index:10}.st-table-container .st-check-loader .spinner{width:40px;height:40px;border:4px solid var(--st-spinner-border-color, rgba(0, 0, 0, .1));border-left-color:var(--st-loader-color);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
3201
5458
  }], ctorParameters: () => [{ type: i3.HttpClient }, { type: i1$1.Router }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }], propDecorators: { config: [{
3202
5459
  type: Input
3203
5460
  }], action: [{
@@ -3208,7 +5465,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
3208
5465
  type: Output
3209
5466
  }], rowSelect: [{
3210
5467
  type: Output
3211
- }], rowClick: [{
5468
+ }], columnClick: [{
3212
5469
  type: Output
3213
5470
  }], stickyHeaders: [{
3214
5471
  type: ViewChildren,
@@ -3628,12 +5885,12 @@ var smartForm_examples = /*#__PURE__*/Object.freeze({
3628
5885
  });
3629
5886
 
3630
5887
  /*
3631
- * Public API Surface of shared-ui
5888
+ * Public API Surface of commons-shared-web-ui
3632
5889
  */
3633
5890
 
3634
5891
  /**
3635
5892
  * Generated bundle index. Do not edit.
3636
5893
  */
3637
5894
 
3638
- export { AlertComponent, AlertModule, ButtonComponent, ButtonModule, ConfigurableFormComponent, configurableForm_examples as ConfigurableFormExamples, ConfigurableFormModule, ConfirmationModalComponent, ConfirmationModalModule, DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE_SIZE_OPTIONS, ExpressionService, FilterSidebarComponent, FilterSidebarModule, MaterialModule, NAV_ORIENTATION_DEFAULT, NAV_VARIANT_DEFAULT, NavComponent, NavModule, PAGINATION_THEME_DARK, PAGINATION_THEME_DEFAULT, PaginationComponent, PaginationModule, SharedUiModule, SmartFormComponent, SmartFormController, smartForm_examples as SmartFormExamples, SmartFormModule, SmartTableComponent, SmartTableModule, SummaryCardComponent, SummaryCardModule, ValidationUtils, clearLocalStorage, clearSessionStorage, getLocalStorageItem, getSessionStorageItem, removeLocalStorageItem, removeSessionStorageItem, setLocalStorageItem, setSessionStorageItem };
5895
+ export { AlertComponent, AlertModule, ButtonComponent, ButtonModule, CheckboxComponent, ConfigurableFormComponent, configurableForm_examples as ConfigurableFormExamples, ConfigurableFormModule, ConfirmationModalComponent, ConfirmationModalModule, DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE_SIZE_OPTIONS, DatepickerComponent, DropdownComponent, ExpressionService, FilterComponent, FilterModule, FilterSidebarComponent, FilterSidebarModule, FormComponentsModule, InputComponent, MaterialModule, NAV_ORIENTATION_DEFAULT, NAV_VARIANT_DEFAULT, NavComponent, NavModule, PAGINATION_THEME_DARK, PAGINATION_THEME_DEFAULT, PaginationComponent, PaginationModule, RadioComponent, SearchComponent, SharedUiModule, SmartFormComponent, SmartFormController, smartForm_examples as SmartFormExamples, SmartFormModule, SmartTableComponent, SmartTableModule, SummaryCardComponent, SummaryCardModule, ToggleComponent, ValidationUtils, clearLocalStorage, clearSessionStorage, getLocalStorageItem, getSessionStorageItem, removeLocalStorageItem, removeSessionStorageItem, setLocalStorageItem, setSessionStorageItem };
3639
5896
  //# sourceMappingURL=commons-shared-web-ui.mjs.map