commons-shared-web-ui 0.0.1
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.
- package/fesm2022/commons-shared-web-ui.mjs +2051 -0
- package/fesm2022/commons-shared-web-ui.mjs.map +1 -0
- package/index.d.ts +742 -0
- package/package.json +33 -0
- package/src/lib/modules/alert/alert.theme.scss +85 -0
- package/src/lib/modules/button/button.theme.scss +121 -0
- package/src/lib/modules/configurable-form/configurable-form.theme.scss +78 -0
- package/src/lib/modules/confirmation-modal/confirmation-modal.theme.scss +87 -0
- package/src/lib/modules/filter-sidebar/filter-sidebar.theme.scss +50 -0
- package/src/lib/modules/nav/nav.theme.scss +86 -0
- package/src/lib/modules/pagination/pagination.theme.scss +66 -0
- package/src/lib/modules/summary-card/summary-card.theme.scss +184 -0
- package/src/lib/styles/global.scss +115 -0
|
@@ -0,0 +1,2051 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { NgModule, EventEmitter, Output, Input, Component, HostListener, forwardRef, HostBinding } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import { MatCardModule } from '@angular/material/card';
|
|
6
|
+
import * as i2$1 from '@angular/material/snack-bar';
|
|
7
|
+
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
8
|
+
import * as i4 from '@angular/material/checkbox';
|
|
9
|
+
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
10
|
+
import { MatDividerModule } from '@angular/material/divider';
|
|
11
|
+
import * as i6 from '@angular/material/radio';
|
|
12
|
+
import { MatRadioModule } from '@angular/material/radio';
|
|
13
|
+
import { MatDialogModule } from '@angular/material/dialog';
|
|
14
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
15
|
+
import * as i2 from '@angular/material/icon';
|
|
16
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
17
|
+
import * as i7 from '@angular/material/button';
|
|
18
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
19
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
20
|
+
import * as i7$1 from '@angular/material/datepicker';
|
|
21
|
+
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
22
|
+
import { MatTabsModule } from '@angular/material/tabs';
|
|
23
|
+
import { MatNativeDateModule } from '@angular/material/core';
|
|
24
|
+
import * as i8$1 from '@angular/material/input';
|
|
25
|
+
import { MatInputModule } from '@angular/material/input';
|
|
26
|
+
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
27
|
+
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
28
|
+
import * as i5 from '@angular/material/select';
|
|
29
|
+
import { MatSelectModule } from '@angular/material/select';
|
|
30
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
31
|
+
import { MatSliderModule } from '@angular/material/slider';
|
|
32
|
+
import { MatListModule } from '@angular/material/list';
|
|
33
|
+
import { MatChipsModule } from '@angular/material/chips';
|
|
34
|
+
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
35
|
+
import { MatTableModule } from '@angular/material/table';
|
|
36
|
+
import * as i8 from '@angular/material/expansion';
|
|
37
|
+
import { MatExpansionModule } from '@angular/material/expansion';
|
|
38
|
+
import { CdkAccordionModule } from '@angular/cdk/accordion';
|
|
39
|
+
import { MatSortModule } from '@angular/material/sort';
|
|
40
|
+
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
|
41
|
+
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
42
|
+
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
43
|
+
import * as i1$2 from '@angular/forms';
|
|
44
|
+
import { FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
45
|
+
import * as i1$1 from '@angular/router';
|
|
46
|
+
import * as i3 from '@angular/common/http';
|
|
47
|
+
import { HttpClientModule } from '@angular/common/http';
|
|
48
|
+
|
|
49
|
+
class MaterialModule {
|
|
50
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MaterialModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
51
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: MaterialModule, imports: [MatCardModule,
|
|
52
|
+
MatSnackBarModule,
|
|
53
|
+
MatCheckboxModule,
|
|
54
|
+
MatDividerModule,
|
|
55
|
+
MatSelectModule,
|
|
56
|
+
MatRadioModule,
|
|
57
|
+
MatDialogModule,
|
|
58
|
+
MatFormFieldModule,
|
|
59
|
+
MatDatepickerModule,
|
|
60
|
+
MatNativeDateModule,
|
|
61
|
+
MatInputModule,
|
|
62
|
+
MatIconModule,
|
|
63
|
+
MatProgressSpinnerModule,
|
|
64
|
+
MatTabsModule,
|
|
65
|
+
MatButtonModule,
|
|
66
|
+
MatMenuModule,
|
|
67
|
+
MatTabsModule,
|
|
68
|
+
MatProgressBarModule,
|
|
69
|
+
MatTooltipModule,
|
|
70
|
+
MatSliderModule,
|
|
71
|
+
MatListModule,
|
|
72
|
+
MatChipsModule,
|
|
73
|
+
MatSortModule,
|
|
74
|
+
MatAutocompleteModule,
|
|
75
|
+
MatSlideToggleModule,
|
|
76
|
+
MatButtonToggleModule], exports: [MatCardModule,
|
|
77
|
+
MatSnackBarModule,
|
|
78
|
+
MatCheckboxModule,
|
|
79
|
+
MatDividerModule,
|
|
80
|
+
MatSelectModule,
|
|
81
|
+
MatRadioModule,
|
|
82
|
+
MatDialogModule,
|
|
83
|
+
MatFormFieldModule,
|
|
84
|
+
MatDatepickerModule,
|
|
85
|
+
MatNativeDateModule,
|
|
86
|
+
MatInputModule,
|
|
87
|
+
MatIconModule,
|
|
88
|
+
MatProgressSpinnerModule,
|
|
89
|
+
MatTabsModule,
|
|
90
|
+
MatButtonModule,
|
|
91
|
+
MatMenuModule,
|
|
92
|
+
MatTabsModule,
|
|
93
|
+
MatProgressBarModule,
|
|
94
|
+
MatTooltipModule,
|
|
95
|
+
MatSliderModule,
|
|
96
|
+
MatListModule,
|
|
97
|
+
MatChipsModule,
|
|
98
|
+
MatPaginatorModule,
|
|
99
|
+
MatTableModule,
|
|
100
|
+
MatExpansionModule,
|
|
101
|
+
CdkAccordionModule,
|
|
102
|
+
MatSortModule,
|
|
103
|
+
MatAutocompleteModule,
|
|
104
|
+
MatSlideToggleModule,
|
|
105
|
+
MatButtonToggleModule] });
|
|
106
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MaterialModule, imports: [MatCardModule,
|
|
107
|
+
MatSnackBarModule,
|
|
108
|
+
MatCheckboxModule,
|
|
109
|
+
MatDividerModule,
|
|
110
|
+
MatSelectModule,
|
|
111
|
+
MatRadioModule,
|
|
112
|
+
MatDialogModule,
|
|
113
|
+
MatFormFieldModule,
|
|
114
|
+
MatDatepickerModule,
|
|
115
|
+
MatNativeDateModule,
|
|
116
|
+
MatInputModule,
|
|
117
|
+
MatIconModule,
|
|
118
|
+
MatProgressSpinnerModule,
|
|
119
|
+
MatTabsModule,
|
|
120
|
+
MatButtonModule,
|
|
121
|
+
MatMenuModule,
|
|
122
|
+
MatTabsModule,
|
|
123
|
+
MatProgressBarModule,
|
|
124
|
+
MatTooltipModule,
|
|
125
|
+
MatSliderModule,
|
|
126
|
+
MatListModule,
|
|
127
|
+
MatChipsModule,
|
|
128
|
+
MatSortModule,
|
|
129
|
+
MatAutocompleteModule,
|
|
130
|
+
MatSlideToggleModule,
|
|
131
|
+
MatButtonToggleModule, MatCardModule,
|
|
132
|
+
MatSnackBarModule,
|
|
133
|
+
MatCheckboxModule,
|
|
134
|
+
MatDividerModule,
|
|
135
|
+
MatSelectModule,
|
|
136
|
+
MatRadioModule,
|
|
137
|
+
MatDialogModule,
|
|
138
|
+
MatFormFieldModule,
|
|
139
|
+
MatDatepickerModule,
|
|
140
|
+
MatNativeDateModule,
|
|
141
|
+
MatInputModule,
|
|
142
|
+
MatIconModule,
|
|
143
|
+
MatProgressSpinnerModule,
|
|
144
|
+
MatTabsModule,
|
|
145
|
+
MatButtonModule,
|
|
146
|
+
MatMenuModule,
|
|
147
|
+
MatTabsModule,
|
|
148
|
+
MatProgressBarModule,
|
|
149
|
+
MatTooltipModule,
|
|
150
|
+
MatSliderModule,
|
|
151
|
+
MatListModule,
|
|
152
|
+
MatChipsModule,
|
|
153
|
+
MatPaginatorModule,
|
|
154
|
+
MatTableModule,
|
|
155
|
+
MatExpansionModule,
|
|
156
|
+
CdkAccordionModule,
|
|
157
|
+
MatSortModule,
|
|
158
|
+
MatAutocompleteModule,
|
|
159
|
+
MatSlideToggleModule,
|
|
160
|
+
MatButtonToggleModule] });
|
|
161
|
+
}
|
|
162
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MaterialModule, decorators: [{
|
|
163
|
+
type: NgModule,
|
|
164
|
+
args: [{
|
|
165
|
+
imports: [
|
|
166
|
+
MatCardModule,
|
|
167
|
+
MatSnackBarModule,
|
|
168
|
+
MatCheckboxModule,
|
|
169
|
+
MatDividerModule,
|
|
170
|
+
MatSelectModule,
|
|
171
|
+
MatRadioModule,
|
|
172
|
+
MatDialogModule,
|
|
173
|
+
MatFormFieldModule,
|
|
174
|
+
MatDatepickerModule,
|
|
175
|
+
MatNativeDateModule,
|
|
176
|
+
MatInputModule,
|
|
177
|
+
MatIconModule,
|
|
178
|
+
MatProgressSpinnerModule,
|
|
179
|
+
MatTabsModule,
|
|
180
|
+
MatButtonModule,
|
|
181
|
+
MatMenuModule,
|
|
182
|
+
MatTabsModule,
|
|
183
|
+
MatProgressBarModule,
|
|
184
|
+
MatTooltipModule,
|
|
185
|
+
MatSliderModule,
|
|
186
|
+
MatListModule,
|
|
187
|
+
MatChipsModule,
|
|
188
|
+
MatSortModule,
|
|
189
|
+
MatAutocompleteModule,
|
|
190
|
+
MatSlideToggleModule,
|
|
191
|
+
MatButtonToggleModule
|
|
192
|
+
],
|
|
193
|
+
exports: [
|
|
194
|
+
MatCardModule,
|
|
195
|
+
MatSnackBarModule,
|
|
196
|
+
MatCheckboxModule,
|
|
197
|
+
MatDividerModule,
|
|
198
|
+
MatSelectModule,
|
|
199
|
+
MatRadioModule,
|
|
200
|
+
MatDialogModule,
|
|
201
|
+
MatFormFieldModule,
|
|
202
|
+
MatDatepickerModule,
|
|
203
|
+
MatNativeDateModule,
|
|
204
|
+
MatInputModule,
|
|
205
|
+
MatIconModule,
|
|
206
|
+
MatProgressSpinnerModule,
|
|
207
|
+
MatTabsModule,
|
|
208
|
+
MatButtonModule,
|
|
209
|
+
MatMenuModule,
|
|
210
|
+
MatTabsModule,
|
|
211
|
+
MatProgressBarModule,
|
|
212
|
+
MatTooltipModule,
|
|
213
|
+
MatSliderModule,
|
|
214
|
+
MatListModule,
|
|
215
|
+
MatChipsModule,
|
|
216
|
+
MatPaginatorModule,
|
|
217
|
+
MatTableModule,
|
|
218
|
+
MatExpansionModule,
|
|
219
|
+
CdkAccordionModule,
|
|
220
|
+
MatSortModule,
|
|
221
|
+
MatAutocompleteModule,
|
|
222
|
+
MatSlideToggleModule,
|
|
223
|
+
MatButtonToggleModule
|
|
224
|
+
]
|
|
225
|
+
}]
|
|
226
|
+
}] });
|
|
227
|
+
|
|
228
|
+
class CardType1Component {
|
|
229
|
+
config;
|
|
230
|
+
theme = 'theme-1';
|
|
231
|
+
cardClick = new EventEmitter();
|
|
232
|
+
get valueStyle() {
|
|
233
|
+
return this.config.valueColor ? { color: this.config.valueColor } : {};
|
|
234
|
+
}
|
|
235
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CardType1Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
236
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: CardType1Component, isStandalone: false, selector: "lib-card-type-1", inputs: { config: "config", theme: "theme" }, outputs: { cardClick: "cardClick" }, ngImport: i0, template: "<div [class]=\"'cc-card ' + theme\" [style.width]=\"config.width || '100%'\" [style.height]=\"config.height || '100%'\" (click)=\"cardClick.emit()\">\n <div class=\"card-content\">\n <div class=\"card-label\">{{ config.label }}</div>\n <div class=\"card-value\" [ngStyle]=\"valueStyle\">{{ config.value }}</div>\n <div\n *ngIf=\"config.subtext\"\n class=\"card-subtext\"\n [ngClass]=\"config.subtextClass\"\n >\n {{ config.subtext }}\n </div>\n </div>\n</div>\n", styles: [".cc-card{display:flex;flex-direction:column;justify-content:center;max-width:100%;box-sizing:border-box;overflow:hidden}.card-label{font-family:var(--cc-font-family);font-size:var(--cc-text-size-label);color:var(--cc-text-color-secondary);text-transform:uppercase;font-weight:var(--cc-text-weight-medium);margin-bottom:8px}.card-value{font-family:var(--cc-font-family);font-size:var(--cc-text-size-value);color:var(--cc-text-color-primary);font-weight:var(--cc-text-weight-bold);margin-bottom:4px}.card-subtext{font-family:var(--cc-font-family);font-size:12px;color:var(--cc-text-color-secondary)}\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.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
|
|
237
|
+
}
|
|
238
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CardType1Component, decorators: [{
|
|
239
|
+
type: Component,
|
|
240
|
+
args: [{ selector: 'lib-card-type-1', standalone: false, template: "<div [class]=\"'cc-card ' + theme\" [style.width]=\"config.width || '100%'\" [style.height]=\"config.height || '100%'\" (click)=\"cardClick.emit()\">\n <div class=\"card-content\">\n <div class=\"card-label\">{{ config.label }}</div>\n <div class=\"card-value\" [ngStyle]=\"valueStyle\">{{ config.value }}</div>\n <div\n *ngIf=\"config.subtext\"\n class=\"card-subtext\"\n [ngClass]=\"config.subtextClass\"\n >\n {{ config.subtext }}\n </div>\n </div>\n</div>\n", styles: [".cc-card{display:flex;flex-direction:column;justify-content:center;max-width:100%;box-sizing:border-box;overflow:hidden}.card-label{font-family:var(--cc-font-family);font-size:var(--cc-text-size-label);color:var(--cc-text-color-secondary);text-transform:uppercase;font-weight:var(--cc-text-weight-medium);margin-bottom:8px}.card-value{font-family:var(--cc-font-family);font-size:var(--cc-text-size-value);color:var(--cc-text-color-primary);font-weight:var(--cc-text-weight-bold);margin-bottom:4px}.card-subtext{font-family:var(--cc-font-family);font-size:12px;color:var(--cc-text-color-secondary)}\n"] }]
|
|
241
|
+
}], propDecorators: { config: [{
|
|
242
|
+
type: Input
|
|
243
|
+
}], theme: [{
|
|
244
|
+
type: Input
|
|
245
|
+
}], cardClick: [{
|
|
246
|
+
type: Output
|
|
247
|
+
}] } });
|
|
248
|
+
|
|
249
|
+
class CardType2Component {
|
|
250
|
+
config;
|
|
251
|
+
theme = 'theme-1';
|
|
252
|
+
cardClick = new EventEmitter();
|
|
253
|
+
get iconBoxStyle() {
|
|
254
|
+
if (this.config.iconUrl) {
|
|
255
|
+
return { backgroundColor: 'transparent' };
|
|
256
|
+
}
|
|
257
|
+
return this.config.iconBackgroundColor ? { backgroundColor: this.config.iconBackgroundColor } : {};
|
|
258
|
+
}
|
|
259
|
+
get iconStyle() {
|
|
260
|
+
return this.config.iconColor ? { color: this.config.iconColor } : {};
|
|
261
|
+
}
|
|
262
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CardType2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
263
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: CardType2Component, isStandalone: false, selector: "lib-card-type-2", inputs: { config: "config", theme: "theme" }, outputs: { cardClick: "cardClick" }, ngImport: i0, template: "<div [class]=\"'cc-card ' + theme\" [style.width]=\"config.width || '100%'\" [style.height]=\"config.height || '100%'\" (click)=\"cardClick.emit()\">\n <div class=\"card-content-wrapper\">\n <div class=\"icon-box\" [ngStyle]=\"iconBoxStyle\">\n <img *ngIf=\"config.iconUrl; else matIconTpl\" [src]=\"config.iconUrl\" class=\"icon-image\" alt=\"icon\">\n <ng-template #matIconTpl>\n <mat-icon [ngStyle]=\"iconStyle\">{{ config.iconName }}</mat-icon>\n </ng-template>\n </div>\n <div class=\"text-content\">\n <div class=\"card-label\">{{ config.label }}</div>\n <div class=\"value-wrapper\">\n <span class=\"card-value\">{{ config.value }}</span>\n <span *ngIf=\"config.targetText\" class=\"card-target\">{{ config.targetText }}</span>\n </div>\n </div>\n </div>\n</div>\n", styles: [".cc-card{display:flex;flex-direction:column;justify-content:center;max-width:100%;box-sizing:border-box;overflow:hidden}.card-content-wrapper{display:flex;align-items:center;gap:16px}.icon-box{width:48px;height:48px;border-radius:8px;display:flex;align-items:center;justify-content:center;background-color:#fce8e6;color:#d32f2f}.icon-box mat-icon{font-size:24px;width:24px;height:24px}.icon-box .icon-image{object-fit:contain;border-radius:.5rem}.text-content{display:flex;flex-direction:column}.card-label{font-family:var(--cc-font-family);font-size:var(--cc-text-size-label);color:var(--cc-text-color-secondary);text-transform:uppercase;font-weight:var(--cc-text-weight-medium);margin-bottom:4px}.value-wrapper{display:flex;align-items:baseline;gap:8px}.card-value{font-family:var(--cc-font-family);font-size:var(--cc-text-size-value);color:var(--cc-text-color-primary);font-weight:var(--cc-text-weight-bold)}.card-target{font-family:var(--cc-font-family);font-size:12px;color:var(--cc-text-color-secondary)}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
|
|
264
|
+
}
|
|
265
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CardType2Component, decorators: [{
|
|
266
|
+
type: Component,
|
|
267
|
+
args: [{ selector: 'lib-card-type-2', standalone: false, template: "<div [class]=\"'cc-card ' + theme\" [style.width]=\"config.width || '100%'\" [style.height]=\"config.height || '100%'\" (click)=\"cardClick.emit()\">\n <div class=\"card-content-wrapper\">\n <div class=\"icon-box\" [ngStyle]=\"iconBoxStyle\">\n <img *ngIf=\"config.iconUrl; else matIconTpl\" [src]=\"config.iconUrl\" class=\"icon-image\" alt=\"icon\">\n <ng-template #matIconTpl>\n <mat-icon [ngStyle]=\"iconStyle\">{{ config.iconName }}</mat-icon>\n </ng-template>\n </div>\n <div class=\"text-content\">\n <div class=\"card-label\">{{ config.label }}</div>\n <div class=\"value-wrapper\">\n <span class=\"card-value\">{{ config.value }}</span>\n <span *ngIf=\"config.targetText\" class=\"card-target\">{{ config.targetText }}</span>\n </div>\n </div>\n </div>\n</div>\n", styles: [".cc-card{display:flex;flex-direction:column;justify-content:center;max-width:100%;box-sizing:border-box;overflow:hidden}.card-content-wrapper{display:flex;align-items:center;gap:16px}.icon-box{width:48px;height:48px;border-radius:8px;display:flex;align-items:center;justify-content:center;background-color:#fce8e6;color:#d32f2f}.icon-box mat-icon{font-size:24px;width:24px;height:24px}.icon-box .icon-image{object-fit:contain;border-radius:.5rem}.text-content{display:flex;flex-direction:column}.card-label{font-family:var(--cc-font-family);font-size:var(--cc-text-size-label);color:var(--cc-text-color-secondary);text-transform:uppercase;font-weight:var(--cc-text-weight-medium);margin-bottom:4px}.value-wrapper{display:flex;align-items:baseline;gap:8px}.card-value{font-family:var(--cc-font-family);font-size:var(--cc-text-size-value);color:var(--cc-text-color-primary);font-weight:var(--cc-text-weight-bold)}.card-target{font-family:var(--cc-font-family);font-size:12px;color:var(--cc-text-color-secondary)}\n"] }]
|
|
268
|
+
}], propDecorators: { config: [{
|
|
269
|
+
type: Input
|
|
270
|
+
}], theme: [{
|
|
271
|
+
type: Input
|
|
272
|
+
}], cardClick: [{
|
|
273
|
+
type: Output
|
|
274
|
+
}] } });
|
|
275
|
+
|
|
276
|
+
class CardsModule {
|
|
277
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CardsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
278
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: CardsModule, declarations: [CardType1Component,
|
|
279
|
+
CardType2Component], imports: [CommonModule,
|
|
280
|
+
MaterialModule], exports: [CardType1Component,
|
|
281
|
+
CardType2Component] });
|
|
282
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CardsModule, imports: [CommonModule,
|
|
283
|
+
MaterialModule] });
|
|
284
|
+
}
|
|
285
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CardsModule, decorators: [{
|
|
286
|
+
type: NgModule,
|
|
287
|
+
args: [{
|
|
288
|
+
declarations: [
|
|
289
|
+
CardType1Component,
|
|
290
|
+
CardType2Component
|
|
291
|
+
],
|
|
292
|
+
imports: [
|
|
293
|
+
CommonModule,
|
|
294
|
+
MaterialModule
|
|
295
|
+
],
|
|
296
|
+
exports: [
|
|
297
|
+
CardType1Component,
|
|
298
|
+
CardType2Component
|
|
299
|
+
]
|
|
300
|
+
}]
|
|
301
|
+
}] });
|
|
302
|
+
|
|
303
|
+
class AlertComponent {
|
|
304
|
+
variant = 'info';
|
|
305
|
+
title = '';
|
|
306
|
+
message = '';
|
|
307
|
+
icon = true;
|
|
308
|
+
customIcon = ''; // New input for custom class
|
|
309
|
+
// Customization Inputs
|
|
310
|
+
width;
|
|
311
|
+
height;
|
|
312
|
+
borderRadius;
|
|
313
|
+
padding;
|
|
314
|
+
gap;
|
|
315
|
+
backgroundColor;
|
|
316
|
+
color; // New input for custom text color
|
|
317
|
+
borderColor;
|
|
318
|
+
fontSize;
|
|
319
|
+
fontWeight;
|
|
320
|
+
boxShadow;
|
|
321
|
+
// Granular Border Radius Customization
|
|
322
|
+
borderTopLeftRadius;
|
|
323
|
+
borderTopRightRadius;
|
|
324
|
+
borderBottomLeftRadius;
|
|
325
|
+
borderBottomRightRadius;
|
|
326
|
+
constructor() { }
|
|
327
|
+
ngOnInit() {
|
|
328
|
+
}
|
|
329
|
+
get isDefaultIcon() {
|
|
330
|
+
return this.icon === true;
|
|
331
|
+
}
|
|
332
|
+
get isStringIcon() {
|
|
333
|
+
return typeof this.icon === 'string';
|
|
334
|
+
}
|
|
335
|
+
get isObjectIcon() {
|
|
336
|
+
return typeof this.icon === 'object' && this.icon !== null;
|
|
337
|
+
}
|
|
338
|
+
get iconString() {
|
|
339
|
+
return typeof this.icon === 'string' ? this.icon : '';
|
|
340
|
+
}
|
|
341
|
+
get isImgIcon() {
|
|
342
|
+
const icon = this.icon;
|
|
343
|
+
if (typeof icon === 'string') {
|
|
344
|
+
return icon.includes('/') || icon.includes('.') || icon.startsWith('http');
|
|
345
|
+
}
|
|
346
|
+
return typeof icon === 'object' && icon !== null && icon.type === 'img';
|
|
347
|
+
}
|
|
348
|
+
get iconObject() {
|
|
349
|
+
return typeof this.icon === 'object' ? this.icon : { type: '', value: '' };
|
|
350
|
+
}
|
|
351
|
+
get defaultIconClass() {
|
|
352
|
+
switch (this.variant) {
|
|
353
|
+
case 'success': return 'fa-solid fa-circle-check';
|
|
354
|
+
case 'warning':
|
|
355
|
+
case 'warning-shadow': return 'fa-solid fa-triangle-exclamation';
|
|
356
|
+
case 'error': return 'fa-solid fa-triangle-exclamation';
|
|
357
|
+
case 'info':
|
|
358
|
+
default: return 'fa-solid fa-circle-info';
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
362
|
+
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"] }] });
|
|
363
|
+
}
|
|
364
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlertComponent, decorators: [{
|
|
365
|
+
type: Component,
|
|
366
|
+
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"] }]
|
|
367
|
+
}], ctorParameters: () => [], propDecorators: { variant: [{
|
|
368
|
+
type: Input
|
|
369
|
+
}], title: [{
|
|
370
|
+
type: Input
|
|
371
|
+
}], message: [{
|
|
372
|
+
type: Input
|
|
373
|
+
}], icon: [{
|
|
374
|
+
type: Input
|
|
375
|
+
}], customIcon: [{
|
|
376
|
+
type: Input
|
|
377
|
+
}], width: [{
|
|
378
|
+
type: Input
|
|
379
|
+
}], height: [{
|
|
380
|
+
type: Input
|
|
381
|
+
}], borderRadius: [{
|
|
382
|
+
type: Input
|
|
383
|
+
}], padding: [{
|
|
384
|
+
type: Input
|
|
385
|
+
}], gap: [{
|
|
386
|
+
type: Input
|
|
387
|
+
}], backgroundColor: [{
|
|
388
|
+
type: Input
|
|
389
|
+
}], color: [{
|
|
390
|
+
type: Input
|
|
391
|
+
}], borderColor: [{
|
|
392
|
+
type: Input
|
|
393
|
+
}], fontSize: [{
|
|
394
|
+
type: Input
|
|
395
|
+
}], fontWeight: [{
|
|
396
|
+
type: Input
|
|
397
|
+
}], boxShadow: [{
|
|
398
|
+
type: Input
|
|
399
|
+
}], borderTopLeftRadius: [{
|
|
400
|
+
type: Input
|
|
401
|
+
}], borderTopRightRadius: [{
|
|
402
|
+
type: Input
|
|
403
|
+
}], borderBottomLeftRadius: [{
|
|
404
|
+
type: Input
|
|
405
|
+
}], borderBottomRightRadius: [{
|
|
406
|
+
type: Input
|
|
407
|
+
}] } });
|
|
408
|
+
|
|
409
|
+
class AlertModule {
|
|
410
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlertModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
411
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: AlertModule, declarations: [AlertComponent], imports: [CommonModule], exports: [AlertComponent] });
|
|
412
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlertModule, imports: [CommonModule] });
|
|
413
|
+
}
|
|
414
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlertModule, decorators: [{
|
|
415
|
+
type: NgModule,
|
|
416
|
+
args: [{
|
|
417
|
+
declarations: [
|
|
418
|
+
AlertComponent
|
|
419
|
+
],
|
|
420
|
+
imports: [
|
|
421
|
+
CommonModule
|
|
422
|
+
],
|
|
423
|
+
exports: [
|
|
424
|
+
AlertComponent
|
|
425
|
+
]
|
|
426
|
+
}]
|
|
427
|
+
}] });
|
|
428
|
+
|
|
429
|
+
class ButtonComponent {
|
|
430
|
+
variant = 'primary';
|
|
431
|
+
type = 'button';
|
|
432
|
+
disabled = false;
|
|
433
|
+
// Customization Inputs
|
|
434
|
+
width;
|
|
435
|
+
height;
|
|
436
|
+
borderRadius;
|
|
437
|
+
fontSize;
|
|
438
|
+
fontWeight;
|
|
439
|
+
backgroundColor;
|
|
440
|
+
color;
|
|
441
|
+
border;
|
|
442
|
+
icon = '';
|
|
443
|
+
constructor() { }
|
|
444
|
+
ngOnInit() {
|
|
445
|
+
}
|
|
446
|
+
get isDefaultIcon() {
|
|
447
|
+
return this.icon === true;
|
|
448
|
+
}
|
|
449
|
+
get isStringIcon() {
|
|
450
|
+
return typeof this.icon === 'string' && this.icon !== '';
|
|
451
|
+
}
|
|
452
|
+
get isImgIcon() {
|
|
453
|
+
const icon = this.icon;
|
|
454
|
+
if (typeof icon === 'string') {
|
|
455
|
+
return icon.includes('/') || icon.includes('.') || icon.startsWith('http');
|
|
456
|
+
}
|
|
457
|
+
return typeof icon === 'object' && icon !== null && !!icon.value && (icon.type === 'img' || icon.value.includes('/') || icon.value.includes('.') || icon.value.startsWith('http'));
|
|
458
|
+
}
|
|
459
|
+
get isObjectIcon() {
|
|
460
|
+
return typeof this.icon === 'object' && this.icon !== null;
|
|
461
|
+
}
|
|
462
|
+
get iconString() {
|
|
463
|
+
return typeof this.icon === 'string' ? this.icon : '';
|
|
464
|
+
}
|
|
465
|
+
get iconObject() {
|
|
466
|
+
return typeof this.icon === 'object' ? this.icon : { type: '', value: '' };
|
|
467
|
+
}
|
|
468
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
469
|
+
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"] }] });
|
|
470
|
+
}
|
|
471
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ButtonComponent, decorators: [{
|
|
472
|
+
type: Component,
|
|
473
|
+
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"] }]
|
|
474
|
+
}], ctorParameters: () => [], propDecorators: { variant: [{
|
|
475
|
+
type: Input
|
|
476
|
+
}], type: [{
|
|
477
|
+
type: Input
|
|
478
|
+
}], disabled: [{
|
|
479
|
+
type: Input
|
|
480
|
+
}], width: [{
|
|
481
|
+
type: Input
|
|
482
|
+
}], height: [{
|
|
483
|
+
type: Input
|
|
484
|
+
}], borderRadius: [{
|
|
485
|
+
type: Input
|
|
486
|
+
}], fontSize: [{
|
|
487
|
+
type: Input
|
|
488
|
+
}], fontWeight: [{
|
|
489
|
+
type: Input
|
|
490
|
+
}], backgroundColor: [{
|
|
491
|
+
type: Input
|
|
492
|
+
}], color: [{
|
|
493
|
+
type: Input
|
|
494
|
+
}], border: [{
|
|
495
|
+
type: Input
|
|
496
|
+
}], icon: [{
|
|
497
|
+
type: Input
|
|
498
|
+
}] } });
|
|
499
|
+
|
|
500
|
+
class ButtonModule {
|
|
501
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ButtonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
502
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: ButtonModule, declarations: [ButtonComponent], imports: [CommonModule], exports: [ButtonComponent] });
|
|
503
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ButtonModule, imports: [CommonModule] });
|
|
504
|
+
}
|
|
505
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ButtonModule, decorators: [{
|
|
506
|
+
type: NgModule,
|
|
507
|
+
args: [{
|
|
508
|
+
declarations: [
|
|
509
|
+
ButtonComponent
|
|
510
|
+
],
|
|
511
|
+
imports: [
|
|
512
|
+
CommonModule
|
|
513
|
+
],
|
|
514
|
+
exports: [
|
|
515
|
+
ButtonComponent
|
|
516
|
+
]
|
|
517
|
+
}]
|
|
518
|
+
}] });
|
|
519
|
+
|
|
520
|
+
class ConfirmationModalComponent {
|
|
521
|
+
config;
|
|
522
|
+
isOpen = false;
|
|
523
|
+
confirm = new EventEmitter();
|
|
524
|
+
cancel = new EventEmitter();
|
|
525
|
+
close = new EventEmitter();
|
|
526
|
+
showCodeSnippet = new EventEmitter();
|
|
527
|
+
// Default configuration
|
|
528
|
+
defaultConfig = {
|
|
529
|
+
headerTheme: 'dark', // Changed to dark as per new default requirement
|
|
530
|
+
width: '560px',
|
|
531
|
+
size: 'md',
|
|
532
|
+
closeOnBackdrop: true,
|
|
533
|
+
closeOnEsc: true,
|
|
534
|
+
showCloseButton: true,
|
|
535
|
+
cancelButton: {
|
|
536
|
+
label: 'Cancel',
|
|
537
|
+
show: true
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
mergedConfig;
|
|
541
|
+
previousActiveElement = null;
|
|
542
|
+
ngOnInit() {
|
|
543
|
+
this.updateConfig();
|
|
544
|
+
// Store currently focused element
|
|
545
|
+
this.previousActiveElement = document.activeElement;
|
|
546
|
+
// Prevent body scroll when modal is open
|
|
547
|
+
if (this.isOpen) {
|
|
548
|
+
this.toggleBodyScroll(true);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
ngOnChanges() {
|
|
552
|
+
this.updateConfig();
|
|
553
|
+
if (this.isOpen !== undefined) {
|
|
554
|
+
this.toggleBodyScroll(this.isOpen);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
updateConfig() {
|
|
558
|
+
// Merge user config with defaults
|
|
559
|
+
this.mergedConfig = {
|
|
560
|
+
...this.defaultConfig,
|
|
561
|
+
...this.config,
|
|
562
|
+
cancelButton: {
|
|
563
|
+
...this.defaultConfig.cancelButton,
|
|
564
|
+
...this.config.cancelButton
|
|
565
|
+
},
|
|
566
|
+
confirmButton: {
|
|
567
|
+
...this.config.confirmButton
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
ngOnDestroy() {
|
|
572
|
+
// Restore body scroll
|
|
573
|
+
this.toggleBodyScroll(false);
|
|
574
|
+
// Restore focus to previous element
|
|
575
|
+
if (this.previousActiveElement) {
|
|
576
|
+
this.previousActiveElement.focus();
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
toggleBodyScroll(disable) {
|
|
580
|
+
if (disable) {
|
|
581
|
+
document.body.style.overflow = 'hidden';
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
document.body.style.overflow = '';
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
handleEscape(event) {
|
|
588
|
+
if (this.isOpen && this.mergedConfig.closeOnEsc) {
|
|
589
|
+
event.preventDefault();
|
|
590
|
+
this.onClose();
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
onBackdropClick(event) {
|
|
594
|
+
// Only close if clicking directly on backdrop, not modal content
|
|
595
|
+
if (this.mergedConfig.closeOnBackdrop &&
|
|
596
|
+
event.target === event.currentTarget) {
|
|
597
|
+
this.onClose();
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
onConfirm() {
|
|
601
|
+
if (!this.mergedConfig.confirmButton.disabled &&
|
|
602
|
+
!this.mergedConfig.confirmButton.loading) {
|
|
603
|
+
this.confirm.emit();
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
onCancel() {
|
|
607
|
+
this.cancel.emit();
|
|
608
|
+
}
|
|
609
|
+
onClose() {
|
|
610
|
+
this.close.emit();
|
|
611
|
+
}
|
|
612
|
+
onShowCodeSnippet() {
|
|
613
|
+
this.showCodeSnippet.emit();
|
|
614
|
+
}
|
|
615
|
+
getModalWidth() {
|
|
616
|
+
if (this.mergedConfig.size) {
|
|
617
|
+
const sizeMap = {
|
|
618
|
+
sm: '400px',
|
|
619
|
+
md: '560px',
|
|
620
|
+
lg: '720px'
|
|
621
|
+
};
|
|
622
|
+
return sizeMap[this.mergedConfig.size];
|
|
623
|
+
}
|
|
624
|
+
return this.mergedConfig.width || '560px';
|
|
625
|
+
}
|
|
626
|
+
getConfirmButtonClass() {
|
|
627
|
+
const typeMap = {
|
|
628
|
+
primary: 'cc-btn-primary',
|
|
629
|
+
danger: 'cc-btn-danger',
|
|
630
|
+
warning: 'cc-btn-warning'
|
|
631
|
+
};
|
|
632
|
+
return `cc-btn ${typeMap[this.mergedConfig.confirmButton.type]}`;
|
|
633
|
+
}
|
|
634
|
+
getHeaderClass() {
|
|
635
|
+
return `modal-header modal-header--${this.mergedConfig.headerTheme}`;
|
|
636
|
+
}
|
|
637
|
+
resolveIconType(icon) {
|
|
638
|
+
if (typeof icon === 'string') {
|
|
639
|
+
if (icon.includes('/') || icon.includes('.') || icon.startsWith('http')) {
|
|
640
|
+
return 'img';
|
|
641
|
+
}
|
|
642
|
+
return 'material';
|
|
643
|
+
}
|
|
644
|
+
if (icon && typeof icon === 'object') {
|
|
645
|
+
if (icon.type === 'custom' || (icon.value && (icon.value.includes('/') || icon.value.includes('.') || icon.value.startsWith('http')))) {
|
|
646
|
+
return 'custom';
|
|
647
|
+
}
|
|
648
|
+
return icon.type || 'material';
|
|
649
|
+
}
|
|
650
|
+
return 'material';
|
|
651
|
+
}
|
|
652
|
+
getIconValue(icon) {
|
|
653
|
+
return typeof icon === 'string' ? icon : icon?.value;
|
|
654
|
+
}
|
|
655
|
+
getIconColor(icon) {
|
|
656
|
+
return typeof icon === 'object' ? icon.color : undefined;
|
|
657
|
+
}
|
|
658
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
659
|
+
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"] }] });
|
|
660
|
+
}
|
|
661
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalComponent, decorators: [{
|
|
662
|
+
type: Component,
|
|
663
|
+
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"] }]
|
|
664
|
+
}], propDecorators: { config: [{
|
|
665
|
+
type: Input
|
|
666
|
+
}], isOpen: [{
|
|
667
|
+
type: Input
|
|
668
|
+
}], confirm: [{
|
|
669
|
+
type: Output
|
|
670
|
+
}], cancel: [{
|
|
671
|
+
type: Output
|
|
672
|
+
}], close: [{
|
|
673
|
+
type: Output
|
|
674
|
+
}], showCodeSnippet: [{
|
|
675
|
+
type: Output
|
|
676
|
+
}], handleEscape: [{
|
|
677
|
+
type: HostListener,
|
|
678
|
+
args: ['document:keydown.escape', ['$event']]
|
|
679
|
+
}] } });
|
|
680
|
+
|
|
681
|
+
class ConfirmationModalModule {
|
|
682
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
683
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, declarations: [ConfirmationModalComponent], imports: [CommonModule,
|
|
684
|
+
MatIconModule, // For material icons support
|
|
685
|
+
FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
|
|
686
|
+
], exports: [ConfirmationModalComponent] });
|
|
687
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, imports: [CommonModule,
|
|
688
|
+
MatIconModule, // For material icons support
|
|
689
|
+
FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
|
|
690
|
+
] });
|
|
691
|
+
}
|
|
692
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationModalModule, decorators: [{
|
|
693
|
+
type: NgModule,
|
|
694
|
+
args: [{
|
|
695
|
+
declarations: [
|
|
696
|
+
ConfirmationModalComponent
|
|
697
|
+
],
|
|
698
|
+
imports: [
|
|
699
|
+
CommonModule,
|
|
700
|
+
MatIconModule, // For material icons support
|
|
701
|
+
FormsModule // For ngModel in user examples (although mostly projected content, user might need it)
|
|
702
|
+
],
|
|
703
|
+
exports: [
|
|
704
|
+
ConfirmationModalComponent
|
|
705
|
+
]
|
|
706
|
+
}]
|
|
707
|
+
}] });
|
|
708
|
+
|
|
709
|
+
class FilterSidebarComponent {
|
|
710
|
+
router;
|
|
711
|
+
route;
|
|
712
|
+
config;
|
|
713
|
+
initialFilters = {};
|
|
714
|
+
filterChange = new EventEmitter();
|
|
715
|
+
filterApply = new EventEmitter();
|
|
716
|
+
filterClear = new EventEmitter();
|
|
717
|
+
tabChange = new EventEmitter();
|
|
718
|
+
showCodeSnippet = new EventEmitter();
|
|
719
|
+
filters = {};
|
|
720
|
+
selectedTabId = null;
|
|
721
|
+
// ControlValueAccessor callbacks
|
|
722
|
+
onChange = () => { };
|
|
723
|
+
onTouched = () => { };
|
|
724
|
+
constructor(router, route) {
|
|
725
|
+
this.router = router;
|
|
726
|
+
this.route = route;
|
|
727
|
+
}
|
|
728
|
+
ngOnInit() {
|
|
729
|
+
if (this.initialFilters) {
|
|
730
|
+
this.filters = { ...this.initialFilters };
|
|
731
|
+
}
|
|
732
|
+
// Initialize from URL query params
|
|
733
|
+
this.route.queryParams.subscribe(params => {
|
|
734
|
+
if (Object.keys(params).length > 0) {
|
|
735
|
+
// Merge params into filters, handling potential array/string conversions if needed
|
|
736
|
+
// For now assuming direct mapping or basic string values
|
|
737
|
+
this.filters = { ...this.filters, ...params };
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
// Initialize Tabs
|
|
741
|
+
if (this.config?.tabs?.items?.length) {
|
|
742
|
+
if (this.config.tabs.defaultActive) {
|
|
743
|
+
this.selectedTabId = this.config.tabs.defaultActive;
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
this.selectedTabId = this.config.tabs.items[0].id;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
// ControlValueAccessor Implementation
|
|
751
|
+
writeValue(value) {
|
|
752
|
+
if (value) {
|
|
753
|
+
this.filters = { ...value };
|
|
754
|
+
}
|
|
755
|
+
else {
|
|
756
|
+
this.filters = {};
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
registerOnChange(fn) {
|
|
760
|
+
this.onChange = fn;
|
|
761
|
+
}
|
|
762
|
+
registerOnTouched(fn) {
|
|
763
|
+
this.onTouched = fn;
|
|
764
|
+
}
|
|
765
|
+
// Component Logic
|
|
766
|
+
onTabClick(tab) {
|
|
767
|
+
this.selectedTabId = tab.id;
|
|
768
|
+
this.tabChange.emit(tab.id);
|
|
769
|
+
}
|
|
770
|
+
onFilterChange(key, value, isMulti = false) {
|
|
771
|
+
if (isMulti) {
|
|
772
|
+
this.toggleFilterValue(key, value);
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
this.filters[key] = value;
|
|
776
|
+
}
|
|
777
|
+
// Notify Generic Change
|
|
778
|
+
this.notifyChanges(key, this.filters[key]);
|
|
779
|
+
}
|
|
780
|
+
toggleFilterValue(key, value) {
|
|
781
|
+
const currentValues = this.filters[key] || [];
|
|
782
|
+
if (Array.isArray(currentValues)) {
|
|
783
|
+
const index = currentValues.indexOf(value);
|
|
784
|
+
if (index > -1) {
|
|
785
|
+
// Remove value
|
|
786
|
+
this.filters[key] = currentValues.filter((v) => v !== value);
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
// Add value
|
|
790
|
+
this.filters[key] = [...currentValues, value];
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
// Initialize array if undefined
|
|
795
|
+
this.filters[key] = [value];
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
notifyChanges(key, value) {
|
|
799
|
+
this.onChange(this.filters);
|
|
800
|
+
// Update URL
|
|
801
|
+
this.updateUrl();
|
|
802
|
+
this.filterChange.emit({
|
|
803
|
+
key,
|
|
804
|
+
value,
|
|
805
|
+
allFilters: this.filters
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
updateUrl() {
|
|
809
|
+
this.router.navigate([], {
|
|
810
|
+
relativeTo: this.route,
|
|
811
|
+
queryParams: this.filters,
|
|
812
|
+
queryParamsHandling: 'merge', // Merge with existing params
|
|
813
|
+
replaceUrl: true // Don't create new history entry for every filter change
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
applyFilters() {
|
|
817
|
+
this.filterApply.emit(this.filters);
|
|
818
|
+
}
|
|
819
|
+
clearFilters() {
|
|
820
|
+
this.filters = {};
|
|
821
|
+
this.onChange(this.filters);
|
|
822
|
+
// Clear URL params (navigate with empty queryParams to clear, or reset to defaults)
|
|
823
|
+
// Since we don't know "defaults" specifically for URL here without config,
|
|
824
|
+
// we'll remove the keys currently in filters from the URL.
|
|
825
|
+
// Actually, easiest way to clear specific params is passing null.
|
|
826
|
+
// However, to clear ALL filter related params, we might need a more robust strategy
|
|
827
|
+
// if there are other params we want to keep.
|
|
828
|
+
// For this task, we will just navigate with empty paramsObject for the keys in `filters`
|
|
829
|
+
// or just clear all if that's the intention.
|
|
830
|
+
// Let's try to clear only the keys we know about from the config if possible,
|
|
831
|
+
// but since `filters` is dynamic, let's clear the keys present in the current state before clearing.
|
|
832
|
+
// A safer approach for "Clear All" in a filter sidebar is often to strip query params.
|
|
833
|
+
this.router.navigate([], {
|
|
834
|
+
relativeTo: this.route,
|
|
835
|
+
queryParams: {}, // Clear all query params
|
|
836
|
+
// queryParamsHandling: 'merge' // attributes to merge would need to be null to remove
|
|
837
|
+
});
|
|
838
|
+
this.filterClear.emit();
|
|
839
|
+
}
|
|
840
|
+
trackByFn(index, item) {
|
|
841
|
+
return item.key || index;
|
|
842
|
+
}
|
|
843
|
+
onShowCodeSnippet() {
|
|
844
|
+
this.showCodeSnippet.emit();
|
|
845
|
+
}
|
|
846
|
+
isImgUrl(icon) {
|
|
847
|
+
return icon.includes('/') || icon.includes('.') || icon.startsWith('http');
|
|
848
|
+
}
|
|
849
|
+
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 });
|
|
850
|
+
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: [
|
|
851
|
+
{
|
|
852
|
+
provide: NG_VALUE_ACCESSOR,
|
|
853
|
+
useExisting: forwardRef(() => FilterSidebarComponent),
|
|
854
|
+
multi: true
|
|
855
|
+
}
|
|
856
|
+
], 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" }] });
|
|
857
|
+
}
|
|
858
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarComponent, decorators: [{
|
|
859
|
+
type: Component,
|
|
860
|
+
args: [{ selector: 'lib-filter-sidebar', standalone: false, providers: [
|
|
861
|
+
{
|
|
862
|
+
provide: NG_VALUE_ACCESSOR,
|
|
863
|
+
useExisting: forwardRef(() => FilterSidebarComponent),
|
|
864
|
+
multi: true
|
|
865
|
+
}
|
|
866
|
+
], 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"] }]
|
|
867
|
+
}], ctorParameters: () => [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }], propDecorators: { config: [{
|
|
868
|
+
type: Input
|
|
869
|
+
}], initialFilters: [{
|
|
870
|
+
type: Input
|
|
871
|
+
}], filterChange: [{
|
|
872
|
+
type: Output
|
|
873
|
+
}], filterApply: [{
|
|
874
|
+
type: Output
|
|
875
|
+
}], filterClear: [{
|
|
876
|
+
type: Output
|
|
877
|
+
}], tabChange: [{
|
|
878
|
+
type: Output
|
|
879
|
+
}], showCodeSnippet: [{
|
|
880
|
+
type: Output
|
|
881
|
+
}] } });
|
|
882
|
+
|
|
883
|
+
class FilterSidebarModule {
|
|
884
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
885
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarModule, declarations: [FilterSidebarComponent], imports: [CommonModule,
|
|
886
|
+
FormsModule,
|
|
887
|
+
ReactiveFormsModule,
|
|
888
|
+
MaterialModule], exports: [FilterSidebarComponent] });
|
|
889
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarModule, imports: [CommonModule,
|
|
890
|
+
FormsModule,
|
|
891
|
+
ReactiveFormsModule,
|
|
892
|
+
MaterialModule] });
|
|
893
|
+
}
|
|
894
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarModule, decorators: [{
|
|
895
|
+
type: NgModule,
|
|
896
|
+
args: [{
|
|
897
|
+
declarations: [
|
|
898
|
+
FilterSidebarComponent
|
|
899
|
+
],
|
|
900
|
+
imports: [
|
|
901
|
+
CommonModule,
|
|
902
|
+
FormsModule,
|
|
903
|
+
ReactiveFormsModule,
|
|
904
|
+
MaterialModule
|
|
905
|
+
],
|
|
906
|
+
exports: [
|
|
907
|
+
FilterSidebarComponent
|
|
908
|
+
]
|
|
909
|
+
}]
|
|
910
|
+
}] });
|
|
911
|
+
|
|
912
|
+
class SummaryCardComponent {
|
|
913
|
+
config;
|
|
914
|
+
theme = 'theme-1';
|
|
915
|
+
cardClick = new EventEmitter();
|
|
916
|
+
get hostClasses() {
|
|
917
|
+
return `${this.theme} ${this.config?.isDisabled ? 'disabled' : ''} ${this.config?.isClickable !== false && !this.config?.isDisabled ? 'clickable' : ''}`;
|
|
918
|
+
}
|
|
919
|
+
constructor() { }
|
|
920
|
+
onCardClick() {
|
|
921
|
+
if (this.config?.isDisabled || this.config?.isClickable === false) {
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
this.cardClick.emit();
|
|
925
|
+
}
|
|
926
|
+
get cardClasses() {
|
|
927
|
+
return {
|
|
928
|
+
'disabled': !!this.config?.isDisabled,
|
|
929
|
+
'clickable': this.config?.isClickable !== false && !this.config?.isDisabled
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
get iconStyles() {
|
|
933
|
+
const styles = {};
|
|
934
|
+
if (this.config.iconBackgroundColor) {
|
|
935
|
+
styles['backgroundColor'] = this.config.iconBackgroundColor;
|
|
936
|
+
}
|
|
937
|
+
if (this.config.iconColor) {
|
|
938
|
+
styles['color'] = this.config.iconColor;
|
|
939
|
+
}
|
|
940
|
+
return styles;
|
|
941
|
+
}
|
|
942
|
+
get headerStyles() {
|
|
943
|
+
const styles = {};
|
|
944
|
+
if (this.config.headerColor) {
|
|
945
|
+
styles['color'] = this.config.headerColor;
|
|
946
|
+
}
|
|
947
|
+
return styles;
|
|
948
|
+
}
|
|
949
|
+
get valueStyles() {
|
|
950
|
+
const styles = {};
|
|
951
|
+
if (this.config.valueColor) {
|
|
952
|
+
styles['color'] = this.config.valueColor;
|
|
953
|
+
}
|
|
954
|
+
return styles;
|
|
955
|
+
}
|
|
956
|
+
get descriptionStyles() {
|
|
957
|
+
const styles = {};
|
|
958
|
+
if (this.config.descriptionColor) {
|
|
959
|
+
styles['color'] = this.config.descriptionColor;
|
|
960
|
+
}
|
|
961
|
+
return styles;
|
|
962
|
+
}
|
|
963
|
+
get isDescriptionInline() {
|
|
964
|
+
return this.config.descriptionPosition === 'inline';
|
|
965
|
+
}
|
|
966
|
+
getMetaStyles(meta) {
|
|
967
|
+
const styles = {};
|
|
968
|
+
if (meta.color) {
|
|
969
|
+
styles['color'] = meta.color;
|
|
970
|
+
}
|
|
971
|
+
if (meta.backgroundColor && meta.type === 'pill') {
|
|
972
|
+
styles['backgroundColor'] = meta.backgroundColor;
|
|
973
|
+
}
|
|
974
|
+
return styles;
|
|
975
|
+
}
|
|
976
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SummaryCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
977
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SummaryCardComponent, isStandalone: false, selector: "lib-summary-card", inputs: { config: "config", theme: "theme" }, outputs: { cardClick: "cardClick" }, host: { properties: { "class": "this.hostClasses" } }, ngImport: i0, template: "<div class=\"cc-summary-card\" (click)=\"onCardClick()\">\r\n <!-- Icon Section (Left Side) -->\r\n <div class=\"icon-section\" *ngIf=\"config.icon || config.iconImage\" [ngClass]=\"config.iconClass\"\r\n [ngStyle]=\"iconStyles\">\r\n <mat-icon *ngIf=\"config.icon\">{{ config.icon }}</mat-icon>\r\n <img *ngIf=\"!config.icon && config.iconImage\" [src]=\"config.iconImage\" alt=\"icon\">\r\n </div>\r\n\r\n <!-- Right Section (Header + Value/Meta) -->\r\n <div class=\"right-section\">\r\n <!-- Header (Full Width on Right) -->\r\n <div class=\"header\" [ngClass]=\"config.headerClass\" [ngStyle]=\"headerStyles\">\r\n {{ config.header }}\r\n </div>\r\n\r\n <!-- Value and Meta Row -->\r\n <div class=\"value-meta-row\">\r\n <!-- Content Section -->\r\n <div class=\"content-section\">\r\n <!-- Value Row (with optional inline description) -->\r\n <div class=\"value-row\" [class.inline-layout]=\"isDescriptionInline\">\r\n <div class=\"value-container\">\r\n <div class=\"value\" [ngClass]=\"config.valueClass\" [ngStyle]=\"valueStyles\">\r\n {{ config.value }}\r\n <span *ngIf=\"config.valueSubtext\" class=\"value-subtext\">{{ config.valueSubtext }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Description (inline or bottom based on config) -->\r\n <div class=\"description\" *ngIf=\"config.description\" [ngClass]=\"config.descriptionClass\"\r\n [ngStyle]=\"descriptionStyles\">\r\n {{ config.description }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Meta/Status Section (Aligned with Value) -->\r\n <div class=\"meta-section\" *ngIf=\"config.metaData && config.metaData.length > 0\">\r\n <div *ngFor=\"let meta of config.metaData\" class=\"meta-item\"\r\n [ngClass]=\"[meta.type === 'pill' ? 'meta-pill' : 'meta-text', meta.cssClass || '']\"\r\n [ngStyle]=\"getMetaStyles(meta)\">\r\n {{ meta.text }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [":host{display:block;width:100%}.cc-summary-card{display:flex;flex-direction:row;align-items:stretch;box-sizing:border-box;font-family:var(--cc-sc-font-family, \"Inter\", sans-serif);background-color:var(--cc-sc-bg-color, #ffffff);border-radius:var(--cc-sc-border-radius, 8px);border:var(--cc-sc-border, 1px solid #e0e0e0);padding:var(--cc-sc-padding, 16px);box-shadow:var(--cc-sc-shadow, 0 2px 4px rgba(0, 0, 0, .05));transition:all var(--cc-sc-transition-duration, .2s) ease;height:100%;width:100%;overflow:hidden;gap:var(--cc-sc-icon-margin, 1rem)}.cc-summary-card.clickable{cursor:pointer}.cc-summary-card.clickable:hover{transform:var(--cc-sc-hover-transform);box-shadow:var(--cc-sc-hover-shadow)}.cc-summary-card.disabled{opacity:var(--cc-sc-disabled-opacity);cursor:not-allowed;pointer-events:none}.cc-summary-card .icon-section{width:var(--cc-sc-icon-box-size);height:var(--cc-sc-icon-box-size);min-width:var(--cc-sc-icon-box-size);display:flex;align-items:center;justify-content:center;border-radius:var(--cc-sc-icon-radius);background-color:var(--cc-sc-icon-bg);color:var(--cc-sc-icon-color);flex-shrink:0;align-self:center}.cc-summary-card .icon-section mat-icon{width:var(--cc-sc-icon-size);height:var(--cc-sc-icon-size);font-size:var(--cc-sc-icon-size);line-height:var(--cc-sc-icon-size)}.cc-summary-card .icon-section img{width:var(--cc-sc-icon-size);height:var(--cc-sc-icon-size);object-fit:contain}.cc-summary-card .right-section{display:flex;flex-direction:column;flex:1;min-width:0;gap:var(--cc-sc-content-gap, .5rem)}.cc-summary-card .right-section .header{font-size:var(--cc-sc-header-size);font-weight:var(--cc-sc-header-weight);text-transform:var(--cc-sc-header-transform);color:var(--cc-sc-header-color);letter-spacing:var(--cc-sc-header-letter-spacing);line-height:var(--cc-sc-header-line-height);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100%}.cc-summary-card .right-section .value-meta-row{display:flex;flex-direction:row;align-items:flex-start;justify-content:space-between;gap:1rem;flex:1}.cc-summary-card .right-section .value-meta-row .content-section{display:flex;flex-direction:column;justify-content:flex-start;flex:1;min-width:0}.cc-summary-card .right-section .value-meta-row .content-section .value-row{display:flex;flex-direction:column;gap:var(--cc-sc-value-desc-gap)}.cc-summary-card .right-section .value-meta-row .content-section .value-row.inline-layout{flex-direction:row;align-items:baseline;flex-wrap:wrap}.cc-summary-card .right-section .value-meta-row .content-section .value-row .value{font-size:var(--cc-sc-value-size);font-weight:var(--cc-sc-value-weight);color:var(--cc-sc-value-color);line-height:var(--cc-sc-value-line-height);white-space:nowrap}.cc-summary-card .right-section .value-meta-row .content-section .value-row .value .value-subtext{font-size:var(--cc-sc-desc-size);font-weight:var(--cc-sc-desc-weight);color:var(--cc-sc-desc-color);margin-left:4px}.cc-summary-card .right-section .value-meta-row .content-section .value-row .description{font-size:var(--cc-sc-desc-size);font-weight:var(--cc-sc-desc-weight);color:var(--cc-sc-desc-color);line-height:var(--cc-sc-desc-line-height)}.cc-summary-card .right-section .value-meta-row .meta-section{display:flex;flex-direction:column;align-items:flex-end;justify-content:flex-start;flex-shrink:0;gap:6px}.cc-summary-card .right-section .value-meta-row .meta-section .meta-item{font-size:.8125rem;line-height:1.4;white-space:nowrap;text-align:right;flex-shrink:0}.cc-summary-card .right-section .value-meta-row .meta-section .meta-item.meta-text{color:var(--cc-sc-desc-color, #64748b);font-weight:500}.cc-summary-card .right-section .value-meta-row .meta-section .meta-item.meta-pill{display:inline-flex;align-items:center;justify-content:center;padding:var(--cc-sc-meta-pill-padding, 4px 12px);border-radius:var(--cc-sc-meta-pill-radius, 20px);font-size:var(--cc-sc-meta-pill-font-size, .75rem);font-weight:var(--cc-sc-meta-pill-font-weight, 600);line-height:1.2;background-color:var(--cc-sc-meta-pill-bg, #f1f5f9);color:var(--cc-sc-meta-pill-color, #475569)}@media(max-width:600px){.cc-summary-card .icon-section{margin-right:var(--cc-sc-icon-margin-mobile, .75rem)}.cc-summary-card .content-section .header{font-size:var(--cc-sc-header-size-mobile, .7rem)}.cc-summary-card .content-section .value-row .value{font-size:var(--cc-sc-value-size-mobile, 1.25rem)}.cc-summary-card .content-section .value-row .description{font-size:var(--cc-sc-desc-size-mobile, .7rem)}}\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: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
|
|
978
|
+
}
|
|
979
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SummaryCardComponent, decorators: [{
|
|
980
|
+
type: Component,
|
|
981
|
+
args: [{ selector: 'lib-summary-card', standalone: false, template: "<div class=\"cc-summary-card\" (click)=\"onCardClick()\">\r\n <!-- Icon Section (Left Side) -->\r\n <div class=\"icon-section\" *ngIf=\"config.icon || config.iconImage\" [ngClass]=\"config.iconClass\"\r\n [ngStyle]=\"iconStyles\">\r\n <mat-icon *ngIf=\"config.icon\">{{ config.icon }}</mat-icon>\r\n <img *ngIf=\"!config.icon && config.iconImage\" [src]=\"config.iconImage\" alt=\"icon\">\r\n </div>\r\n\r\n <!-- Right Section (Header + Value/Meta) -->\r\n <div class=\"right-section\">\r\n <!-- Header (Full Width on Right) -->\r\n <div class=\"header\" [ngClass]=\"config.headerClass\" [ngStyle]=\"headerStyles\">\r\n {{ config.header }}\r\n </div>\r\n\r\n <!-- Value and Meta Row -->\r\n <div class=\"value-meta-row\">\r\n <!-- Content Section -->\r\n <div class=\"content-section\">\r\n <!-- Value Row (with optional inline description) -->\r\n <div class=\"value-row\" [class.inline-layout]=\"isDescriptionInline\">\r\n <div class=\"value-container\">\r\n <div class=\"value\" [ngClass]=\"config.valueClass\" [ngStyle]=\"valueStyles\">\r\n {{ config.value }}\r\n <span *ngIf=\"config.valueSubtext\" class=\"value-subtext\">{{ config.valueSubtext }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Description (inline or bottom based on config) -->\r\n <div class=\"description\" *ngIf=\"config.description\" [ngClass]=\"config.descriptionClass\"\r\n [ngStyle]=\"descriptionStyles\">\r\n {{ config.description }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Meta/Status Section (Aligned with Value) -->\r\n <div class=\"meta-section\" *ngIf=\"config.metaData && config.metaData.length > 0\">\r\n <div *ngFor=\"let meta of config.metaData\" class=\"meta-item\"\r\n [ngClass]=\"[meta.type === 'pill' ? 'meta-pill' : 'meta-text', meta.cssClass || '']\"\r\n [ngStyle]=\"getMetaStyles(meta)\">\r\n {{ meta.text }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [":host{display:block;width:100%}.cc-summary-card{display:flex;flex-direction:row;align-items:stretch;box-sizing:border-box;font-family:var(--cc-sc-font-family, \"Inter\", sans-serif);background-color:var(--cc-sc-bg-color, #ffffff);border-radius:var(--cc-sc-border-radius, 8px);border:var(--cc-sc-border, 1px solid #e0e0e0);padding:var(--cc-sc-padding, 16px);box-shadow:var(--cc-sc-shadow, 0 2px 4px rgba(0, 0, 0, .05));transition:all var(--cc-sc-transition-duration, .2s) ease;height:100%;width:100%;overflow:hidden;gap:var(--cc-sc-icon-margin, 1rem)}.cc-summary-card.clickable{cursor:pointer}.cc-summary-card.clickable:hover{transform:var(--cc-sc-hover-transform);box-shadow:var(--cc-sc-hover-shadow)}.cc-summary-card.disabled{opacity:var(--cc-sc-disabled-opacity);cursor:not-allowed;pointer-events:none}.cc-summary-card .icon-section{width:var(--cc-sc-icon-box-size);height:var(--cc-sc-icon-box-size);min-width:var(--cc-sc-icon-box-size);display:flex;align-items:center;justify-content:center;border-radius:var(--cc-sc-icon-radius);background-color:var(--cc-sc-icon-bg);color:var(--cc-sc-icon-color);flex-shrink:0;align-self:center}.cc-summary-card .icon-section mat-icon{width:var(--cc-sc-icon-size);height:var(--cc-sc-icon-size);font-size:var(--cc-sc-icon-size);line-height:var(--cc-sc-icon-size)}.cc-summary-card .icon-section img{width:var(--cc-sc-icon-size);height:var(--cc-sc-icon-size);object-fit:contain}.cc-summary-card .right-section{display:flex;flex-direction:column;flex:1;min-width:0;gap:var(--cc-sc-content-gap, .5rem)}.cc-summary-card .right-section .header{font-size:var(--cc-sc-header-size);font-weight:var(--cc-sc-header-weight);text-transform:var(--cc-sc-header-transform);color:var(--cc-sc-header-color);letter-spacing:var(--cc-sc-header-letter-spacing);line-height:var(--cc-sc-header-line-height);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100%}.cc-summary-card .right-section .value-meta-row{display:flex;flex-direction:row;align-items:flex-start;justify-content:space-between;gap:1rem;flex:1}.cc-summary-card .right-section .value-meta-row .content-section{display:flex;flex-direction:column;justify-content:flex-start;flex:1;min-width:0}.cc-summary-card .right-section .value-meta-row .content-section .value-row{display:flex;flex-direction:column;gap:var(--cc-sc-value-desc-gap)}.cc-summary-card .right-section .value-meta-row .content-section .value-row.inline-layout{flex-direction:row;align-items:baseline;flex-wrap:wrap}.cc-summary-card .right-section .value-meta-row .content-section .value-row .value{font-size:var(--cc-sc-value-size);font-weight:var(--cc-sc-value-weight);color:var(--cc-sc-value-color);line-height:var(--cc-sc-value-line-height);white-space:nowrap}.cc-summary-card .right-section .value-meta-row .content-section .value-row .value .value-subtext{font-size:var(--cc-sc-desc-size);font-weight:var(--cc-sc-desc-weight);color:var(--cc-sc-desc-color);margin-left:4px}.cc-summary-card .right-section .value-meta-row .content-section .value-row .description{font-size:var(--cc-sc-desc-size);font-weight:var(--cc-sc-desc-weight);color:var(--cc-sc-desc-color);line-height:var(--cc-sc-desc-line-height)}.cc-summary-card .right-section .value-meta-row .meta-section{display:flex;flex-direction:column;align-items:flex-end;justify-content:flex-start;flex-shrink:0;gap:6px}.cc-summary-card .right-section .value-meta-row .meta-section .meta-item{font-size:.8125rem;line-height:1.4;white-space:nowrap;text-align:right;flex-shrink:0}.cc-summary-card .right-section .value-meta-row .meta-section .meta-item.meta-text{color:var(--cc-sc-desc-color, #64748b);font-weight:500}.cc-summary-card .right-section .value-meta-row .meta-section .meta-item.meta-pill{display:inline-flex;align-items:center;justify-content:center;padding:var(--cc-sc-meta-pill-padding, 4px 12px);border-radius:var(--cc-sc-meta-pill-radius, 20px);font-size:var(--cc-sc-meta-pill-font-size, .75rem);font-weight:var(--cc-sc-meta-pill-font-weight, 600);line-height:1.2;background-color:var(--cc-sc-meta-pill-bg, #f1f5f9);color:var(--cc-sc-meta-pill-color, #475569)}@media(max-width:600px){.cc-summary-card .icon-section{margin-right:var(--cc-sc-icon-margin-mobile, .75rem)}.cc-summary-card .content-section .header{font-size:var(--cc-sc-header-size-mobile, .7rem)}.cc-summary-card .content-section .value-row .value{font-size:var(--cc-sc-value-size-mobile, 1.25rem)}.cc-summary-card .content-section .value-row .description{font-size:var(--cc-sc-desc-size-mobile, .7rem)}}\n"] }]
|
|
982
|
+
}], ctorParameters: () => [], propDecorators: { config: [{
|
|
983
|
+
type: Input
|
|
984
|
+
}], theme: [{
|
|
985
|
+
type: Input
|
|
986
|
+
}], cardClick: [{
|
|
987
|
+
type: Output
|
|
988
|
+
}], hostClasses: [{
|
|
989
|
+
type: HostBinding,
|
|
990
|
+
args: ['class']
|
|
991
|
+
}] } });
|
|
992
|
+
|
|
993
|
+
class SummaryCardModule {
|
|
994
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SummaryCardModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
995
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SummaryCardModule, declarations: [SummaryCardComponent], imports: [CommonModule,
|
|
996
|
+
MatIconModule], exports: [SummaryCardComponent] });
|
|
997
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SummaryCardModule, imports: [CommonModule,
|
|
998
|
+
MatIconModule] });
|
|
999
|
+
}
|
|
1000
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SummaryCardModule, decorators: [{
|
|
1001
|
+
type: NgModule,
|
|
1002
|
+
args: [{
|
|
1003
|
+
declarations: [
|
|
1004
|
+
SummaryCardComponent
|
|
1005
|
+
],
|
|
1006
|
+
imports: [
|
|
1007
|
+
CommonModule,
|
|
1008
|
+
MatIconModule
|
|
1009
|
+
],
|
|
1010
|
+
exports: [
|
|
1011
|
+
SummaryCardComponent
|
|
1012
|
+
]
|
|
1013
|
+
}]
|
|
1014
|
+
}] });
|
|
1015
|
+
|
|
1016
|
+
class ConfigurableFormComponent {
|
|
1017
|
+
fb;
|
|
1018
|
+
snackBar;
|
|
1019
|
+
http;
|
|
1020
|
+
config;
|
|
1021
|
+
jsonConfig;
|
|
1022
|
+
data = {};
|
|
1023
|
+
baseApiUrl = '';
|
|
1024
|
+
formSubmit = new EventEmitter();
|
|
1025
|
+
formCancel = new EventEmitter();
|
|
1026
|
+
optionsLoad = new EventEmitter();
|
|
1027
|
+
form;
|
|
1028
|
+
processedConfig;
|
|
1029
|
+
fieldVisibilityMap = new Map();
|
|
1030
|
+
constructor(fb, snackBar, http) {
|
|
1031
|
+
this.fb = fb;
|
|
1032
|
+
this.snackBar = snackBar;
|
|
1033
|
+
this.http = http;
|
|
1034
|
+
}
|
|
1035
|
+
ngOnInit() {
|
|
1036
|
+
this.initializeForm();
|
|
1037
|
+
}
|
|
1038
|
+
ngOnChanges(changes) {
|
|
1039
|
+
if (changes['config'] || changes['jsonConfig']) {
|
|
1040
|
+
this.initializeForm();
|
|
1041
|
+
}
|
|
1042
|
+
if (changes['data'] && this.form) {
|
|
1043
|
+
this.form.patchValue(this.data);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
initializeForm() {
|
|
1047
|
+
// Transform JSON config if provided, otherwise use config directly
|
|
1048
|
+
if (this.jsonConfig) {
|
|
1049
|
+
this.processedConfig = this.transformJsonConfig(this.jsonConfig);
|
|
1050
|
+
}
|
|
1051
|
+
else if (this.config) {
|
|
1052
|
+
this.processedConfig = JSON.parse(JSON.stringify(this.config));
|
|
1053
|
+
}
|
|
1054
|
+
else {
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
this.normalizeFields();
|
|
1058
|
+
this.initializeFieldVisibility();
|
|
1059
|
+
this.buildForm();
|
|
1060
|
+
this.setupDependencies();
|
|
1061
|
+
// Patch initial data if provided
|
|
1062
|
+
if (this.data && Object.keys(this.data).length > 0) {
|
|
1063
|
+
this.form.patchValue(this.data);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
// Transform JSON config format to internal FormConfig format
|
|
1067
|
+
transformJsonConfig(jsonConfig) {
|
|
1068
|
+
const fields = jsonConfig.jsonConfig
|
|
1069
|
+
.sort((a, b) => a.sequence - b.sequence)
|
|
1070
|
+
.map(field => this.transformJsonField(field));
|
|
1071
|
+
return {
|
|
1072
|
+
sections: [{
|
|
1073
|
+
sectionTitle: jsonConfig.label,
|
|
1074
|
+
fields: fields
|
|
1075
|
+
}],
|
|
1076
|
+
entityType: jsonConfig.entityType
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
// Transform individual JSON field to FormField
|
|
1080
|
+
transformJsonField(jsonField) {
|
|
1081
|
+
const fieldType = this.mapUISubTypeToFieldType(jsonField.uiConfig.subType);
|
|
1082
|
+
return {
|
|
1083
|
+
name: jsonField.jsonKey,
|
|
1084
|
+
jsonKey: jsonField.jsonKey,
|
|
1085
|
+
label: jsonField.label,
|
|
1086
|
+
type: fieldType,
|
|
1087
|
+
sequence: jsonField.sequence,
|
|
1088
|
+
keyType: jsonField.keyType,
|
|
1089
|
+
uiConfig: jsonField.uiConfig,
|
|
1090
|
+
validationRules: jsonField.validationRules,
|
|
1091
|
+
required: jsonField.validationRules?.isMandatory || jsonField.validationRules?.isRequired,
|
|
1092
|
+
mandatory: jsonField.validationRules?.isMandatory,
|
|
1093
|
+
dependsOn: undefined, // Will be set based on dependent array
|
|
1094
|
+
dependent: jsonField.uiConfig.dependent,
|
|
1095
|
+
optionConfigs: jsonField.uiConfig.optionConfigs,
|
|
1096
|
+
class: 'col-12'
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
// Map UI subtype to field type
|
|
1100
|
+
mapUISubTypeToFieldType(subType) {
|
|
1101
|
+
switch (subType) {
|
|
1102
|
+
case 'UI_SUBTYPE.SHORT_TEXT':
|
|
1103
|
+
return 'text';
|
|
1104
|
+
case 'UI_SUBTYPE.LONG_TEXT':
|
|
1105
|
+
return 'textarea';
|
|
1106
|
+
case 'UI_SUBTYPE.NUMBER':
|
|
1107
|
+
return 'number';
|
|
1108
|
+
case 'UI_SUBTYPE.EMAIL':
|
|
1109
|
+
return 'email';
|
|
1110
|
+
case 'UI_SUBTYPE.PHONE':
|
|
1111
|
+
return 'tel';
|
|
1112
|
+
case 'UI_SUBTYPE.URL':
|
|
1113
|
+
return 'url';
|
|
1114
|
+
default:
|
|
1115
|
+
return 'text';
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
// Normalize fields to ensure all required properties exist
|
|
1119
|
+
normalizeFields() {
|
|
1120
|
+
this.processedConfig.sections.forEach(section => {
|
|
1121
|
+
section.fields.forEach(field => {
|
|
1122
|
+
// Set default type if not specified
|
|
1123
|
+
if (!field.type) {
|
|
1124
|
+
field.type = 'text';
|
|
1125
|
+
}
|
|
1126
|
+
// Merge uiConfig with field-level properties
|
|
1127
|
+
if (field.uiConfig) {
|
|
1128
|
+
if (field.uiConfig.type === 'UI_TYPE.DROP_DOWN') {
|
|
1129
|
+
field.type = 'dropdown';
|
|
1130
|
+
}
|
|
1131
|
+
if (field.uiConfig.optionConfigs) {
|
|
1132
|
+
field.optionConfigs = field.uiConfig.optionConfigs;
|
|
1133
|
+
}
|
|
1134
|
+
if (field.uiConfig.dependent) {
|
|
1135
|
+
field.dependent = field.uiConfig.dependent;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
// Initialize visibility
|
|
1139
|
+
if (field.visible === undefined) {
|
|
1140
|
+
field.visible = true;
|
|
1141
|
+
}
|
|
1142
|
+
// Load options for dropdowns
|
|
1143
|
+
if ((field.type === 'dropdown' || field.type === 'select') && field.optionConfigs) {
|
|
1144
|
+
this.loadFieldOptions(field);
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
// Initialize field visibility map
|
|
1150
|
+
initializeFieldVisibility() {
|
|
1151
|
+
this.processedConfig.sections.forEach(section => {
|
|
1152
|
+
section.fields.forEach(field => {
|
|
1153
|
+
this.fieldVisibilityMap.set(field.name, field.visible !== false);
|
|
1154
|
+
});
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
buildForm() {
|
|
1158
|
+
const formGroupConfig = {};
|
|
1159
|
+
this.processedConfig.sections.forEach(section => {
|
|
1160
|
+
if (section.isRepeater) {
|
|
1161
|
+
// Create FormArray for repeater sections
|
|
1162
|
+
const arrayName = section.formArrayName || 'items';
|
|
1163
|
+
const minItems = section.minItems || 1;
|
|
1164
|
+
const initialItems = [];
|
|
1165
|
+
for (let i = 0; i < minItems; i++) {
|
|
1166
|
+
initialItems.push(this.createGroup(section.fields));
|
|
1167
|
+
}
|
|
1168
|
+
formGroupConfig[arrayName] = this.fb.array(initialItems);
|
|
1169
|
+
}
|
|
1170
|
+
else {
|
|
1171
|
+
// Add regular fields to form group
|
|
1172
|
+
section.fields.forEach(field => {
|
|
1173
|
+
if (field.subFields) {
|
|
1174
|
+
// Composite field - add all sub-fields
|
|
1175
|
+
field.subFields.forEach(subField => {
|
|
1176
|
+
if (field.required || field.mandatory) {
|
|
1177
|
+
subField.required = true;
|
|
1178
|
+
}
|
|
1179
|
+
formGroupConfig[subField.name] = this.createControl(subField);
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
formGroupConfig[field.name] = this.createControl(field);
|
|
1184
|
+
}
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
this.form = this.fb.group(formGroupConfig);
|
|
1189
|
+
// Apply composite validators to the root form group
|
|
1190
|
+
this.processedConfig.sections.forEach(section => {
|
|
1191
|
+
if (!section.isRepeater) {
|
|
1192
|
+
section.fields.forEach(field => {
|
|
1193
|
+
if (field.type === 'composite' && field.compositeValidationRule && field.subFields) {
|
|
1194
|
+
this.form.addValidators(this.createCompositeValidator(field));
|
|
1195
|
+
}
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
this.form.updateValueAndValidity();
|
|
1200
|
+
}
|
|
1201
|
+
createCompositeValidator(field) {
|
|
1202
|
+
return (control) => {
|
|
1203
|
+
const group = control;
|
|
1204
|
+
if (!field.subFields || field.subFields.length < 2)
|
|
1205
|
+
return null;
|
|
1206
|
+
if (field.compositeValidationRule === 'minMax') {
|
|
1207
|
+
const minControl = group.get(field.subFields[0].name);
|
|
1208
|
+
const maxControl = group.get(field.subFields[1].name);
|
|
1209
|
+
if (minControl && maxControl && minControl.value !== null && maxControl.value !== null) {
|
|
1210
|
+
if (Number(minControl.value) > Number(maxControl.value)) {
|
|
1211
|
+
return { [`invalid_minMax_${field.name}`]: true };
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
if (field.compositeValidationRule === 'percentageTotal') {
|
|
1216
|
+
let total = 0;
|
|
1217
|
+
let allPresent = true;
|
|
1218
|
+
field.subFields.forEach(sub => {
|
|
1219
|
+
const ctrl = group.get(sub.name);
|
|
1220
|
+
if (ctrl && ctrl.value !== null && ctrl.value !== '') {
|
|
1221
|
+
total += Number(ctrl.value);
|
|
1222
|
+
}
|
|
1223
|
+
else {
|
|
1224
|
+
allPresent = false;
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1227
|
+
if (allPresent && total !== 100) {
|
|
1228
|
+
return { [`invalid_percentageTotal_${field.name}`]: true };
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return null;
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
createControl(field) {
|
|
1235
|
+
const validators = [];
|
|
1236
|
+
// Add validators based on field configuration
|
|
1237
|
+
if (field.required || field.mandatory || field.validationRules?.isMandatory || field.validationRules?.isRequired) {
|
|
1238
|
+
validators.push(Validators.required);
|
|
1239
|
+
}
|
|
1240
|
+
if (field.validationRules?.minLength) {
|
|
1241
|
+
validators.push(Validators.minLength(field.validationRules.minLength));
|
|
1242
|
+
}
|
|
1243
|
+
if (field.validationRules?.maxLength) {
|
|
1244
|
+
validators.push(Validators.maxLength(field.validationRules.maxLength));
|
|
1245
|
+
}
|
|
1246
|
+
if (field.validationRules?.pattern) {
|
|
1247
|
+
validators.push(Validators.pattern(field.validationRules.pattern));
|
|
1248
|
+
}
|
|
1249
|
+
if (field.validationRules?.min !== undefined) {
|
|
1250
|
+
validators.push(Validators.min(field.validationRules.min));
|
|
1251
|
+
}
|
|
1252
|
+
if (field.validationRules?.max !== undefined) {
|
|
1253
|
+
validators.push(Validators.max(field.validationRules.max));
|
|
1254
|
+
}
|
|
1255
|
+
if (field.type === 'email') {
|
|
1256
|
+
validators.push(Validators.email);
|
|
1257
|
+
}
|
|
1258
|
+
const initialValue = field.value !== undefined ? field.value : '';
|
|
1259
|
+
return this.fb.control({ value: initialValue, disabled: field.disabled || false }, validators);
|
|
1260
|
+
}
|
|
1261
|
+
createGroup(fields) {
|
|
1262
|
+
const groupConfig = {};
|
|
1263
|
+
fields.forEach(field => {
|
|
1264
|
+
if (field.subFields) {
|
|
1265
|
+
field.subFields.forEach(subField => {
|
|
1266
|
+
groupConfig[subField.name] = this.createControl(subField);
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
else {
|
|
1270
|
+
groupConfig[field.name] = this.createControl(field);
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
return this.fb.group(groupConfig);
|
|
1274
|
+
}
|
|
1275
|
+
getFormArray(name) {
|
|
1276
|
+
return this.form.get(name);
|
|
1277
|
+
}
|
|
1278
|
+
addRepeaterItem(section) {
|
|
1279
|
+
const arrayName = section.formArrayName || 'items';
|
|
1280
|
+
const formArray = this.getFormArray(arrayName);
|
|
1281
|
+
// Check max items
|
|
1282
|
+
if (section.maxItems && formArray.length >= section.maxItems) {
|
|
1283
|
+
this.snackBar.open(`Maximum ${section.maxItems} items allowed`, 'Close', { duration: 3000 });
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
formArray.push(this.createGroup(section.fields));
|
|
1287
|
+
}
|
|
1288
|
+
removeRepeaterItem(sectionName, index) {
|
|
1289
|
+
const formArray = this.getFormArray(sectionName);
|
|
1290
|
+
formArray.removeAt(index);
|
|
1291
|
+
}
|
|
1292
|
+
onSubmit() {
|
|
1293
|
+
if (this.form.invalid) {
|
|
1294
|
+
this.form.markAllAsTouched();
|
|
1295
|
+
this.scrollToFirstInvalidControl();
|
|
1296
|
+
this.snackBar.open('Please fill all required fields', 'Close', { duration: 3000 });
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
this.formSubmit.emit(this.form.value);
|
|
1300
|
+
}
|
|
1301
|
+
scrollToFirstInvalidControl() {
|
|
1302
|
+
const firstInvalidControl = document.querySelector('.is-invalid');
|
|
1303
|
+
if (firstInvalidControl) {
|
|
1304
|
+
firstInvalidControl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
setupDependencies() {
|
|
1308
|
+
this.processedConfig.sections.forEach(section => {
|
|
1309
|
+
section.fields.forEach(field => {
|
|
1310
|
+
if (field.dependsOn) {
|
|
1311
|
+
const control = this.form.get(field.dependsOn);
|
|
1312
|
+
if (control) {
|
|
1313
|
+
control.valueChanges.subscribe(value => {
|
|
1314
|
+
this.onFieldValueChange(field, value);
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
// Also setup for fields with dependent array
|
|
1319
|
+
if (field.dependent && field.dependent.length > 0) {
|
|
1320
|
+
const control = this.form.get(field.name);
|
|
1321
|
+
if (control) {
|
|
1322
|
+
control.valueChanges.subscribe(value => {
|
|
1323
|
+
this.onFieldValueChange(field, value);
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
});
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
onFieldValueChange(field, value) {
|
|
1331
|
+
// Handle dependent fields
|
|
1332
|
+
if (field.dependent && field.dependent.length > 0) {
|
|
1333
|
+
field.dependent.forEach(dependentFieldName => {
|
|
1334
|
+
const dependentField = this.findFieldByName(dependentFieldName);
|
|
1335
|
+
if (dependentField) {
|
|
1336
|
+
// Clear the dependent field value
|
|
1337
|
+
const control = this.form.get(dependentFieldName);
|
|
1338
|
+
if (control) {
|
|
1339
|
+
control.setValue('');
|
|
1340
|
+
control.markAsUntouched();
|
|
1341
|
+
}
|
|
1342
|
+
// Load new options for the dependent field
|
|
1343
|
+
if (value) {
|
|
1344
|
+
this.loadFieldOptions(dependentField, { [field.name]: value });
|
|
1345
|
+
}
|
|
1346
|
+
else {
|
|
1347
|
+
// Clear options if parent value is cleared
|
|
1348
|
+
dependentField.loadedOptions = [];
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
// Load options for a dropdown field
|
|
1355
|
+
loadFieldOptions(field, parentValues) {
|
|
1356
|
+
// Emit event for parent to notify about options load request
|
|
1357
|
+
// Allow parent to mark as handled to skip internal API call
|
|
1358
|
+
const event = { field, parentValue: parentValues, handled: false };
|
|
1359
|
+
this.optionsLoad.emit(event);
|
|
1360
|
+
if (event.handled) {
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
if (!field.optionConfigs) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
const config = field.optionConfigs;
|
|
1367
|
+
// Handle static options
|
|
1368
|
+
if (config.optionDTO === 'OPTION_DTO.STATIC' && config.staticOptions) {
|
|
1369
|
+
field.loadedOptions = config.staticOptions;
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
// Handle API-based options
|
|
1373
|
+
if (config.optionDTO === 'OPTION_DTO.REF_DATA' && config.url) {
|
|
1374
|
+
let url = config.url;
|
|
1375
|
+
// Replace placeholders in URL with parent values
|
|
1376
|
+
if (parentValues) {
|
|
1377
|
+
Object.keys(parentValues).forEach(key => {
|
|
1378
|
+
url = url.replace(`{${key}}`, parentValues[key]);
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
// Prepend base API URL if provided
|
|
1382
|
+
if (this.baseApiUrl && !url.startsWith('http')) {
|
|
1383
|
+
url = `${this.baseApiUrl}/${url}`;
|
|
1384
|
+
}
|
|
1385
|
+
this.http.get(url).subscribe({
|
|
1386
|
+
next: (response) => {
|
|
1387
|
+
// Extract data from response
|
|
1388
|
+
const data = response.data || response.content || response;
|
|
1389
|
+
field.loadedOptions = this.extractOptions(data, config);
|
|
1390
|
+
},
|
|
1391
|
+
error: (error) => {
|
|
1392
|
+
console.error('Error loading options:', error);
|
|
1393
|
+
field.loadedOptions = [];
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
// Extract options from API response
|
|
1399
|
+
extractOptions(data, config) {
|
|
1400
|
+
if (!Array.isArray(data)) {
|
|
1401
|
+
return [];
|
|
1402
|
+
}
|
|
1403
|
+
return data.map(item => ({
|
|
1404
|
+
label: item[config.labelKey || 'name'],
|
|
1405
|
+
value: item[config.requestKey || 'code'] || item[config.valueKey || 'id'],
|
|
1406
|
+
code: item.code,
|
|
1407
|
+
name: item.name
|
|
1408
|
+
}));
|
|
1409
|
+
}
|
|
1410
|
+
// Get options for a field (either static or loaded)
|
|
1411
|
+
getFieldOptions(field) {
|
|
1412
|
+
return field.loadedOptions || field.options || [];
|
|
1413
|
+
}
|
|
1414
|
+
// Check if field is visible
|
|
1415
|
+
isFieldVisible(field) {
|
|
1416
|
+
return this.fieldVisibilityMap.get(field.name) !== false;
|
|
1417
|
+
}
|
|
1418
|
+
// Toggle field visibility
|
|
1419
|
+
toggleFieldVisibility(field, visible) {
|
|
1420
|
+
this.fieldVisibilityMap.set(field.name, visible);
|
|
1421
|
+
const control = this.form.get(field.name);
|
|
1422
|
+
if (control) {
|
|
1423
|
+
if (visible) {
|
|
1424
|
+
// Re-enable and restore validators
|
|
1425
|
+
control.enable();
|
|
1426
|
+
this.updateControlValidators(control, field);
|
|
1427
|
+
}
|
|
1428
|
+
else {
|
|
1429
|
+
// Disable and clear validators
|
|
1430
|
+
control.disable();
|
|
1431
|
+
control.clearValidators();
|
|
1432
|
+
control.updateValueAndValidity();
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
// Update control validators based on field config
|
|
1437
|
+
updateControlValidators(control, field) {
|
|
1438
|
+
const validators = [];
|
|
1439
|
+
if (field.required || field.mandatory || field.validationRules?.isMandatory) {
|
|
1440
|
+
validators.push(Validators.required);
|
|
1441
|
+
}
|
|
1442
|
+
if (field.validationRules?.minLength) {
|
|
1443
|
+
validators.push(Validators.minLength(field.validationRules.minLength));
|
|
1444
|
+
}
|
|
1445
|
+
if (field.validationRules?.maxLength) {
|
|
1446
|
+
validators.push(Validators.maxLength(field.validationRules.maxLength));
|
|
1447
|
+
}
|
|
1448
|
+
if (field.validationRules?.pattern) {
|
|
1449
|
+
validators.push(Validators.pattern(field.validationRules.pattern));
|
|
1450
|
+
}
|
|
1451
|
+
control.setValidators(validators);
|
|
1452
|
+
control.updateValueAndValidity();
|
|
1453
|
+
}
|
|
1454
|
+
onFileChange(event, field) {
|
|
1455
|
+
const files = event.target.files;
|
|
1456
|
+
if (!files || files.length === 0) {
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
// Initialize uploadedFiles if not present
|
|
1460
|
+
// Initialize uploadedFiles if not present
|
|
1461
|
+
if (!field.uploadedFiles) {
|
|
1462
|
+
field.uploadedFiles = [];
|
|
1463
|
+
}
|
|
1464
|
+
const uploadedFiles = [];
|
|
1465
|
+
// Handle files
|
|
1466
|
+
for (let i = 0; i < files.length; i++) {
|
|
1467
|
+
const file = files[i];
|
|
1468
|
+
// Check file size (5MB limit)
|
|
1469
|
+
if (file.size > 5 * 1024 * 1024) {
|
|
1470
|
+
this.snackBar.open(`File ${file.name} exceeds 5MB limit`, 'Close', { duration: 3000 });
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
uploadedFiles.push({
|
|
1474
|
+
name: file.name,
|
|
1475
|
+
size: file.size,
|
|
1476
|
+
type: file.type,
|
|
1477
|
+
file: file
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
if (field.multiple) {
|
|
1481
|
+
field.uploadedFiles.push(...uploadedFiles);
|
|
1482
|
+
}
|
|
1483
|
+
else {
|
|
1484
|
+
field.uploadedFiles = uploadedFiles;
|
|
1485
|
+
}
|
|
1486
|
+
// Update form control value for validation
|
|
1487
|
+
this.updateFileControlValue(field);
|
|
1488
|
+
// Clear the input
|
|
1489
|
+
event.target.value = '';
|
|
1490
|
+
}
|
|
1491
|
+
// Remove uploaded file
|
|
1492
|
+
removeFile(field, index) {
|
|
1493
|
+
if (field.uploadedFiles) {
|
|
1494
|
+
field.uploadedFiles.splice(index, 1);
|
|
1495
|
+
this.updateFileControlValue(field);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
// Update file control value for validation
|
|
1499
|
+
updateFileControlValue(field) {
|
|
1500
|
+
const control = this.form.get(field.name);
|
|
1501
|
+
if (control) {
|
|
1502
|
+
const hasFiles = field.uploadedFiles && field.uploadedFiles.length > 0;
|
|
1503
|
+
control.setValue(hasFiles ? field.uploadedFiles : null);
|
|
1504
|
+
control.markAsTouched();
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
// Get character count for text field
|
|
1508
|
+
getCharacterCount(fieldName) {
|
|
1509
|
+
const control = this.form.get(fieldName);
|
|
1510
|
+
if (control && control.value) {
|
|
1511
|
+
return control.value.toString().length;
|
|
1512
|
+
}
|
|
1513
|
+
return 0;
|
|
1514
|
+
}
|
|
1515
|
+
// Toggle section collapse
|
|
1516
|
+
toggleSection(section) {
|
|
1517
|
+
section.collapsed = !section.collapsed;
|
|
1518
|
+
}
|
|
1519
|
+
onCancel() {
|
|
1520
|
+
this.formCancel.emit();
|
|
1521
|
+
}
|
|
1522
|
+
// Helper method to find field by name
|
|
1523
|
+
findFieldByName(name) {
|
|
1524
|
+
for (const section of this.processedConfig.sections) {
|
|
1525
|
+
const field = section.fields.find(f => f.name === name);
|
|
1526
|
+
if (field) {
|
|
1527
|
+
return field;
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
return undefined;
|
|
1531
|
+
}
|
|
1532
|
+
// Get the processed config for template use
|
|
1533
|
+
get sections() {
|
|
1534
|
+
return this.processedConfig?.sections || [];
|
|
1535
|
+
}
|
|
1536
|
+
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 });
|
|
1537
|
+
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"] }] });
|
|
1538
|
+
}
|
|
1539
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigurableFormComponent, decorators: [{
|
|
1540
|
+
type: Component,
|
|
1541
|
+
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"] }]
|
|
1542
|
+
}], ctorParameters: () => [{ type: i1$2.FormBuilder }, { type: i2$1.MatSnackBar }, { type: i3.HttpClient }], propDecorators: { config: [{
|
|
1543
|
+
type: Input
|
|
1544
|
+
}], jsonConfig: [{
|
|
1545
|
+
type: Input
|
|
1546
|
+
}], data: [{
|
|
1547
|
+
type: Input
|
|
1548
|
+
}], baseApiUrl: [{
|
|
1549
|
+
type: Input
|
|
1550
|
+
}], formSubmit: [{
|
|
1551
|
+
type: Output
|
|
1552
|
+
}], formCancel: [{
|
|
1553
|
+
type: Output
|
|
1554
|
+
}], optionsLoad: [{
|
|
1555
|
+
type: Output
|
|
1556
|
+
}] } });
|
|
1557
|
+
|
|
1558
|
+
class ConfigurableFormModule {
|
|
1559
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigurableFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1560
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: ConfigurableFormModule, imports: [CommonModule,
|
|
1561
|
+
ReactiveFormsModule,
|
|
1562
|
+
HttpClientModule,
|
|
1563
|
+
MaterialModule,
|
|
1564
|
+
ConfigurableFormComponent], exports: [ConfigurableFormComponent] });
|
|
1565
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigurableFormModule, imports: [CommonModule,
|
|
1566
|
+
ReactiveFormsModule,
|
|
1567
|
+
HttpClientModule,
|
|
1568
|
+
MaterialModule,
|
|
1569
|
+
ConfigurableFormComponent] });
|
|
1570
|
+
}
|
|
1571
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigurableFormModule, decorators: [{
|
|
1572
|
+
type: NgModule,
|
|
1573
|
+
args: [{
|
|
1574
|
+
declarations: [],
|
|
1575
|
+
imports: [
|
|
1576
|
+
CommonModule,
|
|
1577
|
+
ReactiveFormsModule,
|
|
1578
|
+
HttpClientModule,
|
|
1579
|
+
MaterialModule,
|
|
1580
|
+
ConfigurableFormComponent
|
|
1581
|
+
],
|
|
1582
|
+
exports: [
|
|
1583
|
+
ConfigurableFormComponent
|
|
1584
|
+
]
|
|
1585
|
+
}]
|
|
1586
|
+
}] });
|
|
1587
|
+
|
|
1588
|
+
class SharedUiModule {
|
|
1589
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedUiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1590
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SharedUiModule, imports: [CommonModule,
|
|
1591
|
+
MaterialModule,
|
|
1592
|
+
CardsModule, AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
|
|
1593
|
+
SummaryCardModule,
|
|
1594
|
+
ConfigurableFormModule], exports: [MaterialModule,
|
|
1595
|
+
CardsModule, AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
|
|
1596
|
+
SummaryCardModule,
|
|
1597
|
+
ConfigurableFormModule] });
|
|
1598
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedUiModule, imports: [CommonModule,
|
|
1599
|
+
MaterialModule,
|
|
1600
|
+
CardsModule, AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
|
|
1601
|
+
SummaryCardModule,
|
|
1602
|
+
ConfigurableFormModule, MaterialModule,
|
|
1603
|
+
CardsModule, AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
|
|
1604
|
+
SummaryCardModule,
|
|
1605
|
+
ConfigurableFormModule] });
|
|
1606
|
+
}
|
|
1607
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedUiModule, decorators: [{
|
|
1608
|
+
type: NgModule,
|
|
1609
|
+
args: [{
|
|
1610
|
+
declarations: [],
|
|
1611
|
+
imports: [
|
|
1612
|
+
CommonModule,
|
|
1613
|
+
MaterialModule,
|
|
1614
|
+
CardsModule, AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
|
|
1615
|
+
SummaryCardModule,
|
|
1616
|
+
ConfigurableFormModule,
|
|
1617
|
+
],
|
|
1618
|
+
exports: [
|
|
1619
|
+
MaterialModule,
|
|
1620
|
+
CardsModule, AlertModule, ButtonModule, ConfirmationModalModule, FilterSidebarModule,
|
|
1621
|
+
SummaryCardModule,
|
|
1622
|
+
ConfigurableFormModule,
|
|
1623
|
+
],
|
|
1624
|
+
}]
|
|
1625
|
+
}] });
|
|
1626
|
+
|
|
1627
|
+
/**
|
|
1628
|
+
* Utility functions for LocalStorage operations
|
|
1629
|
+
*/
|
|
1630
|
+
const getLocalStorageItem = (key) => {
|
|
1631
|
+
return localStorage.getItem(key);
|
|
1632
|
+
};
|
|
1633
|
+
const setLocalStorageItem = (key, value) => {
|
|
1634
|
+
localStorage.setItem(key, value);
|
|
1635
|
+
};
|
|
1636
|
+
const removeLocalStorageItem = (key) => {
|
|
1637
|
+
localStorage.removeItem(key);
|
|
1638
|
+
};
|
|
1639
|
+
const clearLocalStorage = () => {
|
|
1640
|
+
localStorage.clear();
|
|
1641
|
+
};
|
|
1642
|
+
/**
|
|
1643
|
+
* Utility functions for SessionStorage operations
|
|
1644
|
+
*/
|
|
1645
|
+
const getSessionStorageItem = (key) => {
|
|
1646
|
+
return sessionStorage.getItem(key);
|
|
1647
|
+
};
|
|
1648
|
+
const setSessionStorageItem = (key, value) => {
|
|
1649
|
+
sessionStorage.setItem(key, value);
|
|
1650
|
+
};
|
|
1651
|
+
const removeSessionStorageItem = (key) => {
|
|
1652
|
+
sessionStorage.removeItem(key);
|
|
1653
|
+
};
|
|
1654
|
+
const clearSessionStorage = () => {
|
|
1655
|
+
sessionStorage.clear();
|
|
1656
|
+
};
|
|
1657
|
+
|
|
1658
|
+
/**
|
|
1659
|
+
* Example: Basic Form Configuration
|
|
1660
|
+
* This is a generic example for testing and demonstration purposes.
|
|
1661
|
+
*/
|
|
1662
|
+
const EXAMPLE_FORM_CONFIG = {
|
|
1663
|
+
sections: [
|
|
1664
|
+
{
|
|
1665
|
+
sectionTitle: 'User Information',
|
|
1666
|
+
fields: [
|
|
1667
|
+
{
|
|
1668
|
+
name: 'fullName',
|
|
1669
|
+
label: 'Full Name',
|
|
1670
|
+
type: 'text',
|
|
1671
|
+
placeholder: 'Enter full name',
|
|
1672
|
+
required: true,
|
|
1673
|
+
class: 'col-12'
|
|
1674
|
+
},
|
|
1675
|
+
{
|
|
1676
|
+
name: 'email',
|
|
1677
|
+
label: 'Email Address',
|
|
1678
|
+
type: 'email',
|
|
1679
|
+
placeholder: 'Enter email address',
|
|
1680
|
+
required: true,
|
|
1681
|
+
class: 'col-6'
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
name: 'phone',
|
|
1685
|
+
label: 'Phone Number',
|
|
1686
|
+
type: 'tel',
|
|
1687
|
+
placeholder: '+91 9999999999',
|
|
1688
|
+
class: 'col-6'
|
|
1689
|
+
},
|
|
1690
|
+
{
|
|
1691
|
+
name: 'role',
|
|
1692
|
+
label: 'Role',
|
|
1693
|
+
type: 'dropdown',
|
|
1694
|
+
placeholder: 'Select Role',
|
|
1695
|
+
options: [
|
|
1696
|
+
{ label: 'Admin', value: 'admin' },
|
|
1697
|
+
{ label: 'User', value: 'user' },
|
|
1698
|
+
{ label: 'Guest', value: 'guest' }
|
|
1699
|
+
],
|
|
1700
|
+
class: 'col-12'
|
|
1701
|
+
}
|
|
1702
|
+
]
|
|
1703
|
+
},
|
|
1704
|
+
{
|
|
1705
|
+
sectionTitle: 'Preferences',
|
|
1706
|
+
fields: [
|
|
1707
|
+
{
|
|
1708
|
+
name: 'notifications',
|
|
1709
|
+
label: 'Receive Notifications',
|
|
1710
|
+
type: 'radio',
|
|
1711
|
+
options: [
|
|
1712
|
+
{ label: 'Yes', value: 'yes' },
|
|
1713
|
+
{ label: 'No', value: 'no' }
|
|
1714
|
+
],
|
|
1715
|
+
value: 'yes',
|
|
1716
|
+
class: 'col-12'
|
|
1717
|
+
}
|
|
1718
|
+
]
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
sectionTitle: 'Documents',
|
|
1722
|
+
fields: [
|
|
1723
|
+
{
|
|
1724
|
+
name: 'profilePicture',
|
|
1725
|
+
label: 'Profile Picture',
|
|
1726
|
+
type: 'file',
|
|
1727
|
+
accept: '.jpg,.png',
|
|
1728
|
+
multiple: false,
|
|
1729
|
+
helpText: 'Upload a single profile picture (Max 5MB)',
|
|
1730
|
+
class: 'col-12'
|
|
1731
|
+
},
|
|
1732
|
+
{
|
|
1733
|
+
name: 'certificates',
|
|
1734
|
+
label: 'Certificates',
|
|
1735
|
+
type: 'file',
|
|
1736
|
+
accept: '.pdf,.doc,.docx',
|
|
1737
|
+
multiple: true,
|
|
1738
|
+
helpText: 'Upload multiple certificates (Max 5MB each)',
|
|
1739
|
+
class: 'col-12'
|
|
1740
|
+
}
|
|
1741
|
+
]
|
|
1742
|
+
}
|
|
1743
|
+
],
|
|
1744
|
+
submitLabel: 'Save',
|
|
1745
|
+
cancelLabel: 'Cancel',
|
|
1746
|
+
entityType: 'User'
|
|
1747
|
+
};
|
|
1748
|
+
/**
|
|
1749
|
+
* Example: Target Group Configuration
|
|
1750
|
+
* Demonstrates composite fields for Age Group and Gender Split
|
|
1751
|
+
*/
|
|
1752
|
+
const TARGET_GROUP_CONFIG = {
|
|
1753
|
+
sections: [
|
|
1754
|
+
{
|
|
1755
|
+
sectionTitle: 'Target Group Settings',
|
|
1756
|
+
fields: [
|
|
1757
|
+
{
|
|
1758
|
+
name: 'targetAgeGroup',
|
|
1759
|
+
label: 'Target Age Group',
|
|
1760
|
+
type: 'composite',
|
|
1761
|
+
separator: '-',
|
|
1762
|
+
subFields: [
|
|
1763
|
+
{
|
|
1764
|
+
label: "Min Age",
|
|
1765
|
+
name: 'minAge',
|
|
1766
|
+
type: 'number',
|
|
1767
|
+
placeholder: 'Min Age',
|
|
1768
|
+
validationRules: { min: 0 }
|
|
1769
|
+
},
|
|
1770
|
+
{
|
|
1771
|
+
label: "Max Age",
|
|
1772
|
+
name: 'maxAge',
|
|
1773
|
+
type: 'number',
|
|
1774
|
+
placeholder: 'Max Age',
|
|
1775
|
+
validationRules: { min: 0 }
|
|
1776
|
+
}
|
|
1777
|
+
],
|
|
1778
|
+
compositeValidationRule: 'minMax',
|
|
1779
|
+
class: 'col-12'
|
|
1780
|
+
},
|
|
1781
|
+
{
|
|
1782
|
+
name: 'genderSplit',
|
|
1783
|
+
label: 'Target Gender Split',
|
|
1784
|
+
type: 'composite',
|
|
1785
|
+
subFields: [
|
|
1786
|
+
{
|
|
1787
|
+
label: "Male",
|
|
1788
|
+
name: 'malePercentage',
|
|
1789
|
+
type: 'number',
|
|
1790
|
+
placeholder: 'Male',
|
|
1791
|
+
suffixText: '%',
|
|
1792
|
+
validationRules: { min: 0, max: 100 }
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
label: "Female",
|
|
1796
|
+
name: 'femalePercentage',
|
|
1797
|
+
type: 'number',
|
|
1798
|
+
placeholder: 'Female',
|
|
1799
|
+
suffixText: '%',
|
|
1800
|
+
validationRules: { min: 0, max: 100 }
|
|
1801
|
+
}
|
|
1802
|
+
],
|
|
1803
|
+
compositeValidationRule: 'percentageTotal',
|
|
1804
|
+
class: 'col-12'
|
|
1805
|
+
}
|
|
1806
|
+
]
|
|
1807
|
+
}
|
|
1808
|
+
],
|
|
1809
|
+
submitLabel: 'Save Configuration',
|
|
1810
|
+
cancelLabel: 'Cancel'
|
|
1811
|
+
};
|
|
1812
|
+
|
|
1813
|
+
var configurableForm_examples = /*#__PURE__*/Object.freeze({
|
|
1814
|
+
__proto__: null,
|
|
1815
|
+
EXAMPLE_FORM_CONFIG: EXAMPLE_FORM_CONFIG,
|
|
1816
|
+
TARGET_GROUP_CONFIG: TARGET_GROUP_CONFIG
|
|
1817
|
+
});
|
|
1818
|
+
|
|
1819
|
+
const DEFAULT_ITEMS_PER_PAGE = 10;
|
|
1820
|
+
const DEFAULT_PAGE_SIZE_OPTIONS = [10, 20, 50];
|
|
1821
|
+
const PAGINATION_THEME_DEFAULT = 'theme-1';
|
|
1822
|
+
const PAGINATION_THEME_DARK = 'theme-2';
|
|
1823
|
+
// Nav
|
|
1824
|
+
const NAV_VARIANT_DEFAULT = 'filled';
|
|
1825
|
+
const NAV_ORIENTATION_DEFAULT = 'horizontal';
|
|
1826
|
+
|
|
1827
|
+
class PaginationComponent {
|
|
1828
|
+
totalItems = 0;
|
|
1829
|
+
itemsPerPage = DEFAULT_ITEMS_PER_PAGE;
|
|
1830
|
+
currentPage = 1;
|
|
1831
|
+
pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS;
|
|
1832
|
+
theme = PAGINATION_THEME_DEFAULT;
|
|
1833
|
+
labels = {
|
|
1834
|
+
items: 'items',
|
|
1835
|
+
of: 'of',
|
|
1836
|
+
perPage: 'Per Page'
|
|
1837
|
+
};
|
|
1838
|
+
pageChange = new EventEmitter();
|
|
1839
|
+
itemsPerPageChange = new EventEmitter();
|
|
1840
|
+
totalPages = 0;
|
|
1841
|
+
pages = [];
|
|
1842
|
+
startItem = 0;
|
|
1843
|
+
endItem = 0;
|
|
1844
|
+
constructor() { }
|
|
1845
|
+
ngOnInit() {
|
|
1846
|
+
this.calculatePagination();
|
|
1847
|
+
}
|
|
1848
|
+
ngOnChanges(changes) {
|
|
1849
|
+
if (changes['totalItems'] || changes['itemsPerPage'] || changes['currentPage']) {
|
|
1850
|
+
this.calculatePagination();
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
calculatePagination() {
|
|
1854
|
+
this.totalPages = Math.ceil(this.totalItems / this.itemsPerPage);
|
|
1855
|
+
// Ensure current page is valid
|
|
1856
|
+
if (this.currentPage < 1) {
|
|
1857
|
+
this.currentPage = 1;
|
|
1858
|
+
}
|
|
1859
|
+
else if (this.currentPage > this.totalPages && this.totalPages > 0) {
|
|
1860
|
+
this.currentPage = this.totalPages;
|
|
1861
|
+
}
|
|
1862
|
+
this.startItem = (this.currentPage - 1) * this.itemsPerPage + 1;
|
|
1863
|
+
this.endItem = Math.min(this.currentPage * this.itemsPerPage, this.totalItems);
|
|
1864
|
+
if (this.totalItems === 0) {
|
|
1865
|
+
this.startItem = 0;
|
|
1866
|
+
this.endItem = 0;
|
|
1867
|
+
}
|
|
1868
|
+
this.pages = this.getVisiblePages(this.currentPage, this.totalPages);
|
|
1869
|
+
}
|
|
1870
|
+
getVisiblePages(current, total) {
|
|
1871
|
+
if (total <= 7) {
|
|
1872
|
+
return Array.from({ length: total }, (_, i) => i + 1);
|
|
1873
|
+
}
|
|
1874
|
+
if (current <= 4) {
|
|
1875
|
+
return [1, 2, 3, 4, 5, '...', total];
|
|
1876
|
+
}
|
|
1877
|
+
if (current >= total - 3) {
|
|
1878
|
+
return [1, '...', total - 4, total - 3, total - 2, total - 1, total];
|
|
1879
|
+
}
|
|
1880
|
+
return [1, '...', current - 1, current, current + 1, '...', total];
|
|
1881
|
+
}
|
|
1882
|
+
onPageChange(page) {
|
|
1883
|
+
if (typeof page === 'string')
|
|
1884
|
+
return;
|
|
1885
|
+
if (page < 1 || page > this.totalPages || page === this.currentPage)
|
|
1886
|
+
return;
|
|
1887
|
+
this.pageChange.emit(page);
|
|
1888
|
+
}
|
|
1889
|
+
onItemsPerPageChange(event) {
|
|
1890
|
+
const target = event.target;
|
|
1891
|
+
const newSize = Number(target.value);
|
|
1892
|
+
this.itemsPerPageChange.emit(newSize);
|
|
1893
|
+
}
|
|
1894
|
+
nextPage() {
|
|
1895
|
+
if (this.currentPage < this.totalPages) {
|
|
1896
|
+
this.onPageChange(this.currentPage + 1);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
prevPage() {
|
|
1900
|
+
if (this.currentPage > 1) {
|
|
1901
|
+
this.onPageChange(this.currentPage - 1);
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1905
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: PaginationComponent, isStandalone: false, selector: "lib-pagination", inputs: { totalItems: "totalItems", itemsPerPage: "itemsPerPage", currentPage: "currentPage", pageSizeOptions: "pageSizeOptions", theme: "theme", labels: "labels" }, outputs: { pageChange: "pageChange", itemsPerPageChange: "itemsPerPageChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-pagination\" [ngClass]=\"theme\">\n <!-- Left Side: Items Info & Per Page -->\n <div class=\"pagination-left\" *ngIf=\"pageSizeOptions.length > 1 || totalItems > 0\">\n <span class=\"items-info\">\n {{ startItem }}-{{ endItem }} {{ labels.of }} {{ totalItems }} {{ labels.items }}\n </span>\n\n <div class=\"per-page-selector\" *ngIf=\"pageSizeOptions.length > 1\">\n <div class=\"select-wrapper\">\n <select [value]=\"itemsPerPage\" (change)=\"onItemsPerPageChange($event)\">\n <option *ngFor=\"let option of pageSizeOptions\" [value]=\"option\">\n {{ option }}\n </option>\n </select>\n <span class=\"select-arrow\"></span>\n </div>\n <span class=\"per-page-label\">{{ labels.perPage }}</span>\n </div>\n </div>\n\n <!-- Right Side: Page Controls -->\n <div class=\"pagination-right\">\n <button \n class=\"page-btn prev-btn\" \n [disabled]=\"currentPage === 1\" \n (click)=\"prevPage()\"\n aria-label=\"Previous Page\">\n <span class=\"icon\">‹</span>\n </button>\n\n <div class=\"page-numbers\">\n <ng-container *ngFor=\"let page of pages\">\n <button \n *ngIf=\"page !== '...'\"\n class=\"page-btn number-btn\" \n [class.active]=\"page === currentPage\"\n (click)=\"onPageChange(page)\">\n {{ page }}\n </button>\n <span *ngIf=\"page === '...'\" class=\"ellipsis\">...</span>\n </ng-container>\n </div>\n\n <button \n class=\"page-btn next-btn\" \n [disabled]=\"currentPage === totalPages || totalPages === 0\" \n (click)=\"nextPage()\"\n aria-label=\"Next Page\">\n <span class=\"icon\">›</span>\n </button>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.cc-pagination{display:flex;justify-content:space-between;align-items:center;padding:1rem;font-family:var(--cc-pagination-font-family);color:var(--cc-pagination-text-color);font-size:var(--cc-pagination-font-size);flex-wrap:wrap;gap:1rem;width:100%;box-sizing:border-box}.cc-pagination .pagination-left{display:flex;align-items:center;gap:1.5rem;flex-wrap:wrap}.cc-pagination .pagination-left .items-info{white-space:nowrap}.cc-pagination .pagination-left .per-page-selector{display:flex;align-items:center;gap:.5rem}.cc-pagination .pagination-left .per-page-selector .select-wrapper{position:relative;display:inline-block}.cc-pagination .pagination-left .per-page-selector .select-wrapper select{appearance:none;background-color:var(--cc-pagination-select-bg);border:var(--cc-pagination-select-border);border-radius:var(--cc-pagination-select-radius);padding:var(--cc-pagination-select-padding);padding-right:2rem;color:var(--cc-pagination-select-text-color);font-family:inherit;font-size:inherit;cursor:pointer;min-width:60px}.cc-pagination .pagination-left .per-page-selector .select-wrapper select:focus{outline:none;box-shadow:0 0 0 2px #0000001a}.cc-pagination .pagination-left .per-page-selector .select-wrapper:after{content:\"\\25bc\";position:absolute;right:10px;top:50%;transform:translateY(-50%);font-size:.7em;color:var(--cc-pagination-select-arrow-color);pointer-events:none}.cc-pagination .pagination-left .per-page-selector .per-page-label{white-space:nowrap}.cc-pagination .pagination-right{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.cc-pagination .pagination-right .page-btn{display:flex;align-items:center;justify-content:center;min-width:var(--cc-pagination-btn-size);height:var(--cc-pagination-btn-size);background-color:var(--cc-pagination-btn-bg);border:var(--cc-pagination-btn-border);border-radius:var(--cc-pagination-btn-radius);color:var(--cc-pagination-btn-text-color);font-family:inherit;cursor:pointer;transition:all .2s ease;padding:0 .5rem;-webkit-user-select:none;user-select:none}.cc-pagination .pagination-right .page-btn:hover:not(:disabled){background-color:var(--cc-pagination-btn-hover-bg)}.cc-pagination .pagination-right .page-btn:disabled{opacity:var(--cc-pagination-disabled-opacity);background-color:var(--cc-pagination-disabled-bg);cursor:not-allowed}.cc-pagination .pagination-right .page-btn.active{background-color:var(--cc-pagination-btn-active-bg);border:var(--cc-pagination-btn-active-border);color:var(--cc-pagination-btn-active-text);font-weight:700}.cc-pagination .pagination-right .page-btn .icon{font-size:1.2em;line-height:1}.cc-pagination .pagination-right .page-numbers{display:flex;gap:.5rem;flex-wrap:wrap}.cc-pagination .pagination-right .ellipsis{display:flex;align-items:center;justify-content:center;color:var(--cc-pagination-text-color);width:20px}@media(max-width:600px){.cc-pagination{flex-direction:column;align-items:center;gap:1.5rem}.cc-pagination .pagination-left{width:100%;justify-content:space-between;order:2}.cc-pagination .pagination-right{width:100%;justify-content:center;order:1}.cc-pagination .pagination-right .page-numbers{justify-content:center}}\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"] }] });
|
|
1906
|
+
}
|
|
1907
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PaginationComponent, decorators: [{
|
|
1908
|
+
type: Component,
|
|
1909
|
+
args: [{ selector: 'lib-pagination', standalone: false, template: "<div class=\"cc-pagination\" [ngClass]=\"theme\">\n <!-- Left Side: Items Info & Per Page -->\n <div class=\"pagination-left\" *ngIf=\"pageSizeOptions.length > 1 || totalItems > 0\">\n <span class=\"items-info\">\n {{ startItem }}-{{ endItem }} {{ labels.of }} {{ totalItems }} {{ labels.items }}\n </span>\n\n <div class=\"per-page-selector\" *ngIf=\"pageSizeOptions.length > 1\">\n <div class=\"select-wrapper\">\n <select [value]=\"itemsPerPage\" (change)=\"onItemsPerPageChange($event)\">\n <option *ngFor=\"let option of pageSizeOptions\" [value]=\"option\">\n {{ option }}\n </option>\n </select>\n <span class=\"select-arrow\"></span>\n </div>\n <span class=\"per-page-label\">{{ labels.perPage }}</span>\n </div>\n </div>\n\n <!-- Right Side: Page Controls -->\n <div class=\"pagination-right\">\n <button \n class=\"page-btn prev-btn\" \n [disabled]=\"currentPage === 1\" \n (click)=\"prevPage()\"\n aria-label=\"Previous Page\">\n <span class=\"icon\">‹</span>\n </button>\n\n <div class=\"page-numbers\">\n <ng-container *ngFor=\"let page of pages\">\n <button \n *ngIf=\"page !== '...'\"\n class=\"page-btn number-btn\" \n [class.active]=\"page === currentPage\"\n (click)=\"onPageChange(page)\">\n {{ page }}\n </button>\n <span *ngIf=\"page === '...'\" class=\"ellipsis\">...</span>\n </ng-container>\n </div>\n\n <button \n class=\"page-btn next-btn\" \n [disabled]=\"currentPage === totalPages || totalPages === 0\" \n (click)=\"nextPage()\"\n aria-label=\"Next Page\">\n <span class=\"icon\">›</span>\n </button>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.cc-pagination{display:flex;justify-content:space-between;align-items:center;padding:1rem;font-family:var(--cc-pagination-font-family);color:var(--cc-pagination-text-color);font-size:var(--cc-pagination-font-size);flex-wrap:wrap;gap:1rem;width:100%;box-sizing:border-box}.cc-pagination .pagination-left{display:flex;align-items:center;gap:1.5rem;flex-wrap:wrap}.cc-pagination .pagination-left .items-info{white-space:nowrap}.cc-pagination .pagination-left .per-page-selector{display:flex;align-items:center;gap:.5rem}.cc-pagination .pagination-left .per-page-selector .select-wrapper{position:relative;display:inline-block}.cc-pagination .pagination-left .per-page-selector .select-wrapper select{appearance:none;background-color:var(--cc-pagination-select-bg);border:var(--cc-pagination-select-border);border-radius:var(--cc-pagination-select-radius);padding:var(--cc-pagination-select-padding);padding-right:2rem;color:var(--cc-pagination-select-text-color);font-family:inherit;font-size:inherit;cursor:pointer;min-width:60px}.cc-pagination .pagination-left .per-page-selector .select-wrapper select:focus{outline:none;box-shadow:0 0 0 2px #0000001a}.cc-pagination .pagination-left .per-page-selector .select-wrapper:after{content:\"\\25bc\";position:absolute;right:10px;top:50%;transform:translateY(-50%);font-size:.7em;color:var(--cc-pagination-select-arrow-color);pointer-events:none}.cc-pagination .pagination-left .per-page-selector .per-page-label{white-space:nowrap}.cc-pagination .pagination-right{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.cc-pagination .pagination-right .page-btn{display:flex;align-items:center;justify-content:center;min-width:var(--cc-pagination-btn-size);height:var(--cc-pagination-btn-size);background-color:var(--cc-pagination-btn-bg);border:var(--cc-pagination-btn-border);border-radius:var(--cc-pagination-btn-radius);color:var(--cc-pagination-btn-text-color);font-family:inherit;cursor:pointer;transition:all .2s ease;padding:0 .5rem;-webkit-user-select:none;user-select:none}.cc-pagination .pagination-right .page-btn:hover:not(:disabled){background-color:var(--cc-pagination-btn-hover-bg)}.cc-pagination .pagination-right .page-btn:disabled{opacity:var(--cc-pagination-disabled-opacity);background-color:var(--cc-pagination-disabled-bg);cursor:not-allowed}.cc-pagination .pagination-right .page-btn.active{background-color:var(--cc-pagination-btn-active-bg);border:var(--cc-pagination-btn-active-border);color:var(--cc-pagination-btn-active-text);font-weight:700}.cc-pagination .pagination-right .page-btn .icon{font-size:1.2em;line-height:1}.cc-pagination .pagination-right .page-numbers{display:flex;gap:.5rem;flex-wrap:wrap}.cc-pagination .pagination-right .ellipsis{display:flex;align-items:center;justify-content:center;color:var(--cc-pagination-text-color);width:20px}@media(max-width:600px){.cc-pagination{flex-direction:column;align-items:center;gap:1.5rem}.cc-pagination .pagination-left{width:100%;justify-content:space-between;order:2}.cc-pagination .pagination-right{width:100%;justify-content:center;order:1}.cc-pagination .pagination-right .page-numbers{justify-content:center}}\n"] }]
|
|
1910
|
+
}], ctorParameters: () => [], propDecorators: { totalItems: [{
|
|
1911
|
+
type: Input
|
|
1912
|
+
}], itemsPerPage: [{
|
|
1913
|
+
type: Input
|
|
1914
|
+
}], currentPage: [{
|
|
1915
|
+
type: Input
|
|
1916
|
+
}], pageSizeOptions: [{
|
|
1917
|
+
type: Input
|
|
1918
|
+
}], theme: [{
|
|
1919
|
+
type: Input
|
|
1920
|
+
}], labels: [{
|
|
1921
|
+
type: Input
|
|
1922
|
+
}], pageChange: [{
|
|
1923
|
+
type: Output
|
|
1924
|
+
}], itemsPerPageChange: [{
|
|
1925
|
+
type: Output
|
|
1926
|
+
}] } });
|
|
1927
|
+
|
|
1928
|
+
class PaginationModule {
|
|
1929
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PaginationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1930
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: PaginationModule, declarations: [PaginationComponent], imports: [CommonModule], exports: [PaginationComponent] });
|
|
1931
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PaginationModule, imports: [CommonModule] });
|
|
1932
|
+
}
|
|
1933
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PaginationModule, decorators: [{
|
|
1934
|
+
type: NgModule,
|
|
1935
|
+
args: [{
|
|
1936
|
+
declarations: [
|
|
1937
|
+
PaginationComponent
|
|
1938
|
+
],
|
|
1939
|
+
imports: [
|
|
1940
|
+
CommonModule
|
|
1941
|
+
],
|
|
1942
|
+
exports: [
|
|
1943
|
+
PaginationComponent
|
|
1944
|
+
]
|
|
1945
|
+
}]
|
|
1946
|
+
}] });
|
|
1947
|
+
|
|
1948
|
+
class NavComponent {
|
|
1949
|
+
items = [];
|
|
1950
|
+
activeId = null;
|
|
1951
|
+
variant = NAV_VARIANT_DEFAULT;
|
|
1952
|
+
orientation = NAV_ORIENTATION_DEFAULT;
|
|
1953
|
+
styleConfig = {};
|
|
1954
|
+
selectionChange = new EventEmitter();
|
|
1955
|
+
ngOnChanges(changes) {
|
|
1956
|
+
if (changes['styleConfig']) {
|
|
1957
|
+
console.log(' [NavComponent] styleConfig changed:', this.styleConfig);
|
|
1958
|
+
console.log(' [NavComponent] computedStyles:', this.computedStyles);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
get computedStyles() {
|
|
1962
|
+
const c = this.styleConfig;
|
|
1963
|
+
return {
|
|
1964
|
+
// Container (direct CSS)
|
|
1965
|
+
'width': c.width,
|
|
1966
|
+
'box-shadow': c.boxShadow,
|
|
1967
|
+
// Container (CSS Variables)
|
|
1968
|
+
'--cc-nav-container-bg': c.backgroundColor,
|
|
1969
|
+
'--cc-nav-container-radius': c.borderRadius,
|
|
1970
|
+
'--cc-nav-container-border': c.border,
|
|
1971
|
+
'--cc-nav-container-padding': c.padding,
|
|
1972
|
+
'--cc-nav-container-gap': c.gap,
|
|
1973
|
+
// Item (CSS Variables)
|
|
1974
|
+
'--cc-nav-font-size': c.fontSize,
|
|
1975
|
+
'--cc-nav-font-weight': c.fontWeight,
|
|
1976
|
+
'--cc-nav-item-color': c.itemColor,
|
|
1977
|
+
'--cc-nav-item-radius': c.itemRadius,
|
|
1978
|
+
'--cc-nav-item-padding': c.itemPadding,
|
|
1979
|
+
// Active Item (CSS Variables)
|
|
1980
|
+
'--cc-nav-item-active-bg': c.activeItemBg,
|
|
1981
|
+
'--cc-nav-item-active-color': c.activeItemColor,
|
|
1982
|
+
'--cc-nav-item-active-font-weight': c.activeItemFontWeight,
|
|
1983
|
+
'--cc-nav-item-active-border-color': c.activeItemBorderColor,
|
|
1984
|
+
// Hover Item (CSS Variables)
|
|
1985
|
+
'--cc-nav-item-hover-bg': c.hoverItemBg,
|
|
1986
|
+
'--cc-nav-item-hover-color': c.hoverItemColor,
|
|
1987
|
+
// Badge (CSS Variables)
|
|
1988
|
+
'--cc-nav-badge-bg': c.badgeBg,
|
|
1989
|
+
'--cc-nav-badge-color': c.badgeColor,
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
onItemClick(item) {
|
|
1993
|
+
if (item.disabled)
|
|
1994
|
+
return;
|
|
1995
|
+
if (item.id === this.activeId)
|
|
1996
|
+
return;
|
|
1997
|
+
this.selectionChange.emit(item);
|
|
1998
|
+
}
|
|
1999
|
+
trackById(index, item) {
|
|
2000
|
+
return item.id;
|
|
2001
|
+
}
|
|
2002
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2003
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: NavComponent, isStandalone: false, selector: "lib-nav", inputs: { items: "items", activeId: "activeId", variant: "variant", orientation: "orientation", styleConfig: "styleConfig" }, outputs: { selectionChange: "selectionChange" }, usesOnChanges: true, ngImport: i0, template: "<nav\r\n class=\"cc-nav\"\r\n [ngClass]=\"[variant, orientation]\"\r\n [ngStyle]=\"computedStyles\"\r\n role=\"tablist\"\r\n [attr.aria-orientation]=\"orientation\">\r\n\r\n <button\r\n *ngFor=\"let item of items; trackBy: trackById\"\r\n class=\"cc-nav-item\"\r\n [class.active]=\"item.id === activeId\"\r\n [class.disabled]=\"item.disabled\"\r\n [disabled]=\"item.disabled\"\r\n role=\"tab\"\r\n [attr.aria-selected]=\"item.id === activeId\"\r\n [attr.aria-disabled]=\"item.disabled || null\"\r\n (click)=\"onItemClick(item)\">\r\n\r\n <!-- Icon (optional) -->\r\n <span *ngIf=\"item.icon\" class=\"cc-nav-item-icon\">\r\n <i [ngClass]=\"item.icon\"></i>\r\n </span>\r\n\r\n <!-- Label -->\r\n <span class=\"cc-nav-item-label\">{{ item.label }}</span>\r\n\r\n <!-- Badge (optional) -->\r\n <span *ngIf=\"item.badge != null\" class=\"cc-nav-item-badge\">\r\n {{ item.badge }}\r\n </span>\r\n\r\n </button>\r\n\r\n</nav>\r\n", styles: [".cc-nav{display:flex;align-items:center;background-color:var(--cc-nav-container-bg);padding:var(--cc-nav-container-padding);border-radius:var(--cc-nav-container-radius);border:var(--cc-nav-container-border);gap:var(--cc-nav-container-gap);font-family:var(--cc-nav-font-family);font-size:var(--cc-nav-font-size);box-sizing:border-box;width:100%}.cc-nav.horizontal{flex-direction:row;overflow-x:auto;-ms-overflow-style:none;scrollbar-width:none}.cc-nav.horizontal::-webkit-scrollbar{display:none}.cc-nav.vertical{flex-direction:column;align-items:stretch}.cc-nav .cc-nav-item{display:inline-flex;align-items:center;gap:6px;padding:var(--cc-nav-item-padding);border-radius:var(--cc-nav-item-radius);border:var(--cc-nav-item-border);background-color:var(--cc-nav-item-bg);color:var(--cc-nav-item-color);font-family:inherit;font-size:inherit;font-weight:var(--cc-nav-font-weight);cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none;transition:all .2s ease;position:relative;outline:none}.cc-nav .cc-nav-item:hover:not(:disabled):not(.active){background-color:var(--cc-nav-item-hover-bg);color:var(--cc-nav-item-hover-color)}.cc-nav .cc-nav-item.active{background-color:var(--cc-nav-item-active-bg);color:var(--cc-nav-item-active-color);font-weight:var(--cc-nav-item-active-font-weight);box-shadow:var(--cc-nav-item-active-shadow)}.cc-nav .cc-nav-item:disabled,.cc-nav .cc-nav-item.disabled{opacity:var(--cc-nav-disabled-opacity);cursor:not-allowed}.cc-nav .cc-nav-item .cc-nav-item-icon{display:inline-flex;align-items:center;font-size:1.1em;line-height:1}.cc-nav .cc-nav-item .cc-nav-item-badge{display:inline-flex;align-items:center;justify-content:center;min-width:var(--cc-nav-badge-size);height:var(--cc-nav-badge-size);border-radius:50%;background-color:var(--cc-nav-badge-bg);color:var(--cc-nav-badge-color);font-size:var(--cc-nav-badge-font-size);font-weight:var(--cc-nav-badge-font-weight, 600);padding:0 4px;line-height:1}.cc-nav.filled .cc-nav-item.active{border-bottom:var(--cc-nav-item-active-border-width) solid var(--cc-nav-item-active-border-color)}.cc-nav.underline{background-color:transparent;border-radius:0;padding:0;border-bottom:1px solid #e0e0e0}.cc-nav.underline .cc-nav-item{background-color:transparent;border-radius:0;border:none;border-bottom:var(--cc-nav-item-active-border-width) solid transparent;box-shadow:none}.cc-nav.underline .cc-nav-item:hover:not(:disabled):not(.active){background-color:transparent;border-bottom-color:#ccc}.cc-nav.underline .cc-nav-item.active{background-color:transparent;border-bottom-color:var(--cc-nav-item-active-border-color);box-shadow:none}.cc-nav.pills{background-color:transparent;padding:0}.cc-nav.pills .cc-nav-item,.cc-nav.pills .cc-nav-item.active{border-radius:999px}@media(max-width:600px){.cc-nav.horizontal{gap:2px}.cc-nav.horizontal .cc-nav-item{padding:6px 12px;font-size:13px}}\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"] }] });
|
|
2004
|
+
}
|
|
2005
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NavComponent, decorators: [{
|
|
2006
|
+
type: Component,
|
|
2007
|
+
args: [{ selector: 'lib-nav', standalone: false, template: "<nav\r\n class=\"cc-nav\"\r\n [ngClass]=\"[variant, orientation]\"\r\n [ngStyle]=\"computedStyles\"\r\n role=\"tablist\"\r\n [attr.aria-orientation]=\"orientation\">\r\n\r\n <button\r\n *ngFor=\"let item of items; trackBy: trackById\"\r\n class=\"cc-nav-item\"\r\n [class.active]=\"item.id === activeId\"\r\n [class.disabled]=\"item.disabled\"\r\n [disabled]=\"item.disabled\"\r\n role=\"tab\"\r\n [attr.aria-selected]=\"item.id === activeId\"\r\n [attr.aria-disabled]=\"item.disabled || null\"\r\n (click)=\"onItemClick(item)\">\r\n\r\n <!-- Icon (optional) -->\r\n <span *ngIf=\"item.icon\" class=\"cc-nav-item-icon\">\r\n <i [ngClass]=\"item.icon\"></i>\r\n </span>\r\n\r\n <!-- Label -->\r\n <span class=\"cc-nav-item-label\">{{ item.label }}</span>\r\n\r\n <!-- Badge (optional) -->\r\n <span *ngIf=\"item.badge != null\" class=\"cc-nav-item-badge\">\r\n {{ item.badge }}\r\n </span>\r\n\r\n </button>\r\n\r\n</nav>\r\n", styles: [".cc-nav{display:flex;align-items:center;background-color:var(--cc-nav-container-bg);padding:var(--cc-nav-container-padding);border-radius:var(--cc-nav-container-radius);border:var(--cc-nav-container-border);gap:var(--cc-nav-container-gap);font-family:var(--cc-nav-font-family);font-size:var(--cc-nav-font-size);box-sizing:border-box;width:100%}.cc-nav.horizontal{flex-direction:row;overflow-x:auto;-ms-overflow-style:none;scrollbar-width:none}.cc-nav.horizontal::-webkit-scrollbar{display:none}.cc-nav.vertical{flex-direction:column;align-items:stretch}.cc-nav .cc-nav-item{display:inline-flex;align-items:center;gap:6px;padding:var(--cc-nav-item-padding);border-radius:var(--cc-nav-item-radius);border:var(--cc-nav-item-border);background-color:var(--cc-nav-item-bg);color:var(--cc-nav-item-color);font-family:inherit;font-size:inherit;font-weight:var(--cc-nav-font-weight);cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none;transition:all .2s ease;position:relative;outline:none}.cc-nav .cc-nav-item:hover:not(:disabled):not(.active){background-color:var(--cc-nav-item-hover-bg);color:var(--cc-nav-item-hover-color)}.cc-nav .cc-nav-item.active{background-color:var(--cc-nav-item-active-bg);color:var(--cc-nav-item-active-color);font-weight:var(--cc-nav-item-active-font-weight);box-shadow:var(--cc-nav-item-active-shadow)}.cc-nav .cc-nav-item:disabled,.cc-nav .cc-nav-item.disabled{opacity:var(--cc-nav-disabled-opacity);cursor:not-allowed}.cc-nav .cc-nav-item .cc-nav-item-icon{display:inline-flex;align-items:center;font-size:1.1em;line-height:1}.cc-nav .cc-nav-item .cc-nav-item-badge{display:inline-flex;align-items:center;justify-content:center;min-width:var(--cc-nav-badge-size);height:var(--cc-nav-badge-size);border-radius:50%;background-color:var(--cc-nav-badge-bg);color:var(--cc-nav-badge-color);font-size:var(--cc-nav-badge-font-size);font-weight:var(--cc-nav-badge-font-weight, 600);padding:0 4px;line-height:1}.cc-nav.filled .cc-nav-item.active{border-bottom:var(--cc-nav-item-active-border-width) solid var(--cc-nav-item-active-border-color)}.cc-nav.underline{background-color:transparent;border-radius:0;padding:0;border-bottom:1px solid #e0e0e0}.cc-nav.underline .cc-nav-item{background-color:transparent;border-radius:0;border:none;border-bottom:var(--cc-nav-item-active-border-width) solid transparent;box-shadow:none}.cc-nav.underline .cc-nav-item:hover:not(:disabled):not(.active){background-color:transparent;border-bottom-color:#ccc}.cc-nav.underline .cc-nav-item.active{background-color:transparent;border-bottom-color:var(--cc-nav-item-active-border-color);box-shadow:none}.cc-nav.pills{background-color:transparent;padding:0}.cc-nav.pills .cc-nav-item,.cc-nav.pills .cc-nav-item.active{border-radius:999px}@media(max-width:600px){.cc-nav.horizontal{gap:2px}.cc-nav.horizontal .cc-nav-item{padding:6px 12px;font-size:13px}}\n"] }]
|
|
2008
|
+
}], propDecorators: { items: [{
|
|
2009
|
+
type: Input
|
|
2010
|
+
}], activeId: [{
|
|
2011
|
+
type: Input
|
|
2012
|
+
}], variant: [{
|
|
2013
|
+
type: Input
|
|
2014
|
+
}], orientation: [{
|
|
2015
|
+
type: Input
|
|
2016
|
+
}], styleConfig: [{
|
|
2017
|
+
type: Input
|
|
2018
|
+
}], selectionChange: [{
|
|
2019
|
+
type: Output
|
|
2020
|
+
}] } });
|
|
2021
|
+
|
|
2022
|
+
class NavModule {
|
|
2023
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NavModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
2024
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: NavModule, declarations: [NavComponent], imports: [CommonModule], exports: [NavComponent] });
|
|
2025
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NavModule, imports: [CommonModule] });
|
|
2026
|
+
}
|
|
2027
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NavModule, decorators: [{
|
|
2028
|
+
type: NgModule,
|
|
2029
|
+
args: [{
|
|
2030
|
+
declarations: [
|
|
2031
|
+
NavComponent
|
|
2032
|
+
],
|
|
2033
|
+
imports: [
|
|
2034
|
+
CommonModule
|
|
2035
|
+
],
|
|
2036
|
+
exports: [
|
|
2037
|
+
NavComponent
|
|
2038
|
+
]
|
|
2039
|
+
}]
|
|
2040
|
+
}] });
|
|
2041
|
+
|
|
2042
|
+
/*
|
|
2043
|
+
* Public API Surface of shared-ui
|
|
2044
|
+
*/
|
|
2045
|
+
|
|
2046
|
+
/**
|
|
2047
|
+
* Generated bundle index. Do not edit.
|
|
2048
|
+
*/
|
|
2049
|
+
|
|
2050
|
+
export { AlertComponent, AlertModule, ButtonComponent, ButtonModule, CardType1Component, CardType2Component, CardsModule, ConfigurableFormComponent, configurableForm_examples as ConfigurableFormExamples, ConfigurableFormModule, ConfirmationModalComponent, ConfirmationModalModule, DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE_SIZE_OPTIONS, FilterSidebarComponent, FilterSidebarModule, MaterialModule, NAV_ORIENTATION_DEFAULT, NAV_VARIANT_DEFAULT, NavComponent, NavModule, PAGINATION_THEME_DARK, PAGINATION_THEME_DEFAULT, PaginationComponent, PaginationModule, SharedUiModule, SummaryCardComponent, SummaryCardModule, clearLocalStorage, clearSessionStorage, getLocalStorageItem, getSessionStorageItem, removeLocalStorageItem, removeSessionStorageItem, setLocalStorageItem, setSessionStorageItem };
|
|
2051
|
+
//# sourceMappingURL=commons-shared-web-ui.mjs.map
|