@fxlt/common-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.
Files changed (44) hide show
  1. package/BeVietnamPro-Regular.ttf +0 -0
  2. package/README.md +63 -0
  3. package/SpaceMono-Regular.ttf +0 -0
  4. package/animations.css +115 -0
  5. package/components.css +383 -0
  6. package/dialogs.css +116 -0
  7. package/fesm2022/fxlt-common-ui.mjs +2439 -0
  8. package/fesm2022/fxlt-common-ui.mjs.map +1 -0
  9. package/fonts.css +13 -0
  10. package/index.d.ts +739 -0
  11. package/package.json +53 -0
  12. package/src/lib/styles/animations.css +115 -0
  13. package/src/lib/styles/components.css +383 -0
  14. package/src/lib/styles/dialogs.css +116 -0
  15. package/src/lib/styles/fonts.css +13 -0
  16. package/src/lib/styles/tailwind.css +18 -0
  17. package/src/lib/styles/theme.css +63 -0
  18. package/src/lib/ui/components/button/button.component.html +223 -0
  19. package/src/lib/ui/components/chart/chart.component.html +13 -0
  20. package/src/lib/ui/components/checkbox/checkbox.component.html +43 -0
  21. package/src/lib/ui/components/datetime-picker/datetime-picker.component.html +25 -0
  22. package/src/lib/ui/components/dnd-upload/dnd-upload.component.html +34 -0
  23. package/src/lib/ui/components/hero-icon/hero-icon.component.html +8 -0
  24. package/src/lib/ui/components/input/input.component.css +0 -0
  25. package/src/lib/ui/components/input/input.component.html +46 -0
  26. package/src/lib/ui/components/loading-panel/loading-panel.component.html +51 -0
  27. package/src/lib/ui/components/radio-button/radio-button.component.css +0 -0
  28. package/src/lib/ui/components/radio-button/radio-button.component.html +35 -0
  29. package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +34 -0
  30. package/src/lib/ui/components/search-bar/search-bar.component.html +22 -0
  31. package/src/lib/ui/components/select/select.component.css +80 -0
  32. package/src/lib/ui/components/select/select.component.html +25 -0
  33. package/src/lib/ui/components/slider/slider.component.html +54 -0
  34. package/src/lib/ui/components/switch/switch.component.html +21 -0
  35. package/src/lib/ui/components/tab-component/tab.component.html +1 -0
  36. package/src/lib/ui/components/tab-group/tab-group.component.html +75 -0
  37. package/src/lib/ui/components/tag/tag.component.html +43 -0
  38. package/src/lib/ui/components/toast/toast.component.html +48 -0
  39. package/src/lib/ui/components/toast-container/toast-container.component.html +12 -0
  40. package/src/lib/ui/dialogs/confirmation/confirmation.component.html +10 -0
  41. package/tailwind-config.d.ts +4 -0
  42. package/tailwind.config.js +69 -0
  43. package/tailwind.css +18 -0
  44. package/theme.css +63 -0
@@ -0,0 +1,2439 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Directive, Input, Component, createComponent, Injectable, ViewChild, Inject, EventEmitter, NgModule, Output, HostListener, Optional, Self, ChangeDetectionStrategy, TemplateRef, ContentChildren, importProvidersFrom } from '@angular/core';
3
+ import * as i26 from '@angular/material/paginator';
4
+ import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
5
+ import * as i27 from '@angular/material/table';
6
+ import { MatTableDataSource, MatTable, MatTableModule } from '@angular/material/table';
7
+ import * as i2 from '@angular/common';
8
+ import { CommonModule } from '@angular/common';
9
+ import * as i1 from '@dimaslz/ng-heroicons';
10
+ import { NgHeroiconsModule } from '@dimaslz/ng-heroicons';
11
+ import _, { clamp } from 'lodash';
12
+ import { Observable, firstValueFrom, BehaviorSubject, Subject, throwError } from 'rxjs';
13
+ import * as i1$1 from '@angular/material/dialog';
14
+ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
15
+ import * as i2$1 from '@angular/common/http';
16
+ import { HttpClient } from '@angular/common/http';
17
+ import * as i1$2 from '@ngx-translate/core';
18
+ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
19
+ import { TranslateHttpLoader } from '@ngx-translate/http-loader';
20
+ import * as i2$2 from '@angular/router';
21
+ import { catchError } from 'rxjs/operators';
22
+ import * as i1$3 from '@angular/forms';
23
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
24
+ import * as i3$1 from '@angular/material/select';
25
+ import { MatSelectModule } from '@angular/material/select';
26
+ import * as i23 from '@angular/material/radio';
27
+ import { MatRadioModule } from '@angular/material/radio';
28
+ import * as i24 from '@angular/material/button';
29
+ import { MatButtonModule } from '@angular/material/button';
30
+ import * as i25 from '@angular/material/icon';
31
+ import { MatIconModule } from '@angular/material/icon';
32
+ import * as i28 from '@angular/material/snack-bar';
33
+ import { MatSnackBarModule } from '@angular/material/snack-bar';
34
+ import * as i30 from '@angular/material/checkbox';
35
+ import { MatCheckboxModule } from '@angular/material/checkbox';
36
+ import * as i31 from '@angular/material/card';
37
+ import { MatCardModule } from '@angular/material/card';
38
+ import * as i32 from '@angular/material/datepicker';
39
+ import { MatDatepickerModule } from '@angular/material/datepicker';
40
+ import * as i33 from '@angular/material/timepicker';
41
+ import { MatTimepickerModule } from '@angular/material/timepicker';
42
+ import * as i34 from '@angular/material/badge';
43
+ import { MatBadgeModule } from '@angular/material/badge';
44
+ import * as i35 from '@angular/material/expansion';
45
+ import { MatExpansionModule } from '@angular/material/expansion';
46
+ import * as i36 from '@angular/material/form-field';
47
+ import { MatFormFieldModule } from '@angular/material/form-field';
48
+ import * as i3 from '@danielmoncada/angular-datetime-picker';
49
+ import { OwlDateTimeModule, OwlNativeDateTimeModule } from '@danielmoncada/angular-datetime-picker';
50
+ import * as i2$3 from 'ngx-echarts';
51
+ import { NgxEchartsModule } from 'ngx-echarts';
52
+ import { __decorate, __param } from 'tslib';
53
+
54
+ class BaseComponent {
55
+ injector;
56
+ constructor(injector) {
57
+ this.injector = injector;
58
+ }
59
+ ngOnDestroy() {
60
+ // clean up if needed later
61
+ }
62
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseComponent, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive });
63
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: BaseComponent, isStandalone: true, ngImport: i0 });
64
+ }
65
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseComponent, decorators: [{
66
+ type: Directive
67
+ }], ctorParameters: () => [{ type: i0.Injector }] });
68
+
69
+ class HeroIconComponent {
70
+ icon;
71
+ solid;
72
+ outline;
73
+ size;
74
+ color;
75
+ class;
76
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HeroIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
77
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: HeroIconComponent, isStandalone: false, selector: "fx-ui-hero-icon", inputs: { icon: "icon", solid: "solid", outline: "outline", size: "size", color: "color", class: "class" }, ngImport: i0, template: "<ng-heroicons\n [icon]=\"icon\"\n [size]=\"size\"\n [solid]=\"solid\"\n [outline]=\"outline\"\n [color]=\"color\"\n [class]=\"class\"\n/>\n", styles: [""], dependencies: [{ kind: "component", type: i1.DynamicComponent, selector: "ng-heroicons", inputs: ["icon", "size", "color", "stroke", "outline", "solid", "class", "style"] }] });
78
+ }
79
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HeroIconComponent, decorators: [{
80
+ type: Component,
81
+ args: [{ selector: 'fx-ui-hero-icon', standalone: false, template: "<ng-heroicons\n [icon]=\"icon\"\n [size]=\"size\"\n [solid]=\"solid\"\n [outline]=\"outline\"\n [color]=\"color\"\n [class]=\"class\"\n/>\n" }]
82
+ }], propDecorators: { icon: [{
83
+ type: Input
84
+ }], solid: [{
85
+ type: Input
86
+ }], outline: [{
87
+ type: Input
88
+ }], size: [{
89
+ type: Input
90
+ }], color: [{
91
+ type: Input
92
+ }], class: [{
93
+ type: Input
94
+ }] } });
95
+
96
+ class ToastComponent {
97
+ toastId;
98
+ title = '';
99
+ message = '';
100
+ type;
101
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
102
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ToastComponent, isStandalone: false, selector: "fx-ui-toast", inputs: { toastId: "toastId", title: "title", message: "message", type: "type" }, ngImport: i0, template: "<div\n animate.enter=\"horizontal-fade-in-animation\"\n animate.leave=\"horizontal-fade-out-animation\"\n class=\"flex border-l-[3px] items-center bg-bg-primary gap-semi min-w-[250px] max-w-[320px] px-large py-semi rounded shadow-lg transition-all duration-300 ease-in-out transform opacity-100 translate-y-0\"\n [ngClass]=\"{\n 'border-success': type === 'success',\n 'border-critical': type === 'error',\n 'border-warning': type === 'warning',\n 'border-information': type === 'info'\n }\"\n>\n <div class=\"\">\n @switch (type) { @case('success') {\n <fx-ui-hero-icon\n icon=\"check-circle\"\n [solid]=\"true\"\n [size]=\"30\"\n class=\"text-success\"\n ></fx-ui-hero-icon>\n } @case('error') {\n <fx-ui-hero-icon\n icon=\"exclamation-circle\"\n [solid]=\"true\"\n [size]=\"30\"\n class=\"text-critical\"\n ></fx-ui-hero-icon>\n } @case('warning') {\n <fx-ui-hero-icon\n icon=\"exclamation-triangle\"\n [solid]=\"true\"\n [size]=\"30\"\n class=\"text-warning\"\n ></fx-ui-hero-icon>\n } @default {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [solid]=\"true\"\n [size]=\"30\"\n class=\"text-information\"\n ></fx-ui-hero-icon>\n } }\n </div>\n\n <div class=\"flex flex-col\">\n <strong *ngIf=\"title\" class=\"txt-field-label\">{{ title }}</strong>\n <p class=\"txt-default\">{{ message }}</p>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["icon", "solid", "outline", "size", "color", "class"] }] });
103
+ }
104
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastComponent, decorators: [{
105
+ type: Component,
106
+ args: [{ selector: 'fx-ui-toast', standalone: false, template: "<div\n animate.enter=\"horizontal-fade-in-animation\"\n animate.leave=\"horizontal-fade-out-animation\"\n class=\"flex border-l-[3px] items-center bg-bg-primary gap-semi min-w-[250px] max-w-[320px] px-large py-semi rounded shadow-lg transition-all duration-300 ease-in-out transform opacity-100 translate-y-0\"\n [ngClass]=\"{\n 'border-success': type === 'success',\n 'border-critical': type === 'error',\n 'border-warning': type === 'warning',\n 'border-information': type === 'info'\n }\"\n>\n <div class=\"\">\n @switch (type) { @case('success') {\n <fx-ui-hero-icon\n icon=\"check-circle\"\n [solid]=\"true\"\n [size]=\"30\"\n class=\"text-success\"\n ></fx-ui-hero-icon>\n } @case('error') {\n <fx-ui-hero-icon\n icon=\"exclamation-circle\"\n [solid]=\"true\"\n [size]=\"30\"\n class=\"text-critical\"\n ></fx-ui-hero-icon>\n } @case('warning') {\n <fx-ui-hero-icon\n icon=\"exclamation-triangle\"\n [solid]=\"true\"\n [size]=\"30\"\n class=\"text-warning\"\n ></fx-ui-hero-icon>\n } @default {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [solid]=\"true\"\n [size]=\"30\"\n class=\"text-information\"\n ></fx-ui-hero-icon>\n } }\n </div>\n\n <div class=\"flex flex-col\">\n <strong *ngIf=\"title\" class=\"txt-field-label\">{{ title }}</strong>\n <p class=\"txt-default\">{{ message }}</p>\n </div>\n</div>\n" }]
107
+ }], propDecorators: { toastId: [{
108
+ type: Input
109
+ }], title: [{
110
+ type: Input
111
+ }], message: [{
112
+ type: Input
113
+ }], type: [{
114
+ type: Input
115
+ }] } });
116
+
117
+ class ToastContainerComponent {
118
+ ref;
119
+ toasts = [];
120
+ constructor(ref) {
121
+ this.ref = ref;
122
+ }
123
+ addToast(toast) {
124
+ this.toasts.push(toast);
125
+ this.ref.detectChanges();
126
+ setTimeout(() => this.removeToast(toast.id), 3000);
127
+ }
128
+ removeToast(id) {
129
+ this.toasts = this.toasts.filter(t => t.id !== id);
130
+ this.ref.detectChanges();
131
+ }
132
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastContainerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
133
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ToastContainerComponent, isStandalone: false, selector: "fx-ui-toast-container", ngImport: i0, template: "<div\n class=\"fixed top-5 right-5 flex flex-col items-end gap-3 z-[10000] pointer-events-none\"\n>\n @for (toast of toasts; track toast) {\n <fx-ui-toast\n class=\"pointer-events-auto\"\n [message]=\"toast.message\"\n [title]=\"toast.title\"\n [type]=\"toast.type\"\n ></fx-ui-toast>\n }\n</div>", styles: [""], dependencies: [{ kind: "component", type: ToastComponent, selector: "fx-ui-toast", inputs: ["toastId", "title", "message", "type"] }] });
134
+ }
135
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastContainerComponent, decorators: [{
136
+ type: Component,
137
+ args: [{ selector: 'fx-ui-toast-container', standalone: false, template: "<div\n class=\"fixed top-5 right-5 flex flex-col items-end gap-3 z-[10000] pointer-events-none\"\n>\n @for (toast of toasts; track toast) {\n <fx-ui-toast\n class=\"pointer-events-auto\"\n [message]=\"toast.message\"\n [title]=\"toast.title\"\n [type]=\"toast.type\"\n ></fx-ui-toast>\n }\n</div>" }]
138
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
139
+
140
+ class FxToastrService {
141
+ appRef;
142
+ containerRef;
143
+ idCounter = 0;
144
+ constructor(appRef) {
145
+ this.appRef = appRef;
146
+ this.ensureContainerExists();
147
+ }
148
+ ensureContainerExists() {
149
+ if (!this.containerRef) {
150
+ this.containerRef = createComponent(ToastContainerComponent, {
151
+ environmentInjector: this.appRef.injector,
152
+ });
153
+ this.appRef.attachView(this.containerRef.hostView);
154
+ document.body.appendChild(this.containerRef.location.nativeElement);
155
+ }
156
+ }
157
+ show(message, type, title) {
158
+ const toast = {
159
+ id: ++this.idCounter,
160
+ message,
161
+ title,
162
+ type,
163
+ };
164
+ this.containerRef?.instance.addToast(toast);
165
+ }
166
+ success(message, title) {
167
+ this.show(message, 'success', title);
168
+ }
169
+ error(message, title) {
170
+ this.show(message, 'error', title);
171
+ }
172
+ info(message, title) {
173
+ this.show(message, 'info', title);
174
+ }
175
+ warning(message, title) {
176
+ this.show(message, 'warning', title);
177
+ }
178
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxToastrService, deps: [{ token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Injectable });
179
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxToastrService, providedIn: 'root' });
180
+ }
181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxToastrService, decorators: [{
182
+ type: Injectable,
183
+ args: [{
184
+ providedIn: 'root',
185
+ }]
186
+ }], ctorParameters: () => [{ type: i0.ApplicationRef }] });
187
+
188
+ class FxUtils {
189
+ static async preresolve(promises, value, key) {
190
+ if (key === 'callback' || key === 'socket' || key === 'listener') {
191
+ promises.push(value);
192
+ return;
193
+ }
194
+ if (value instanceof Function) {
195
+ this.preresolve(promises, value());
196
+ }
197
+ else if (value instanceof Array) {
198
+ const inpromises = [];
199
+ value.forEach((v) => {
200
+ this.preresolve(inpromises, v);
201
+ });
202
+ promises.push(Promise.all(inpromises));
203
+ }
204
+ else if (value instanceof Observable) {
205
+ promises.push(firstValueFrom(value));
206
+ }
207
+ else if (value instanceof Promise) {
208
+ promises.push(value);
209
+ }
210
+ else if (value instanceof Object) {
211
+ promises.push(this.resolve(value));
212
+ }
213
+ else {
214
+ promises.push(value);
215
+ }
216
+ }
217
+ static async resolve(value) {
218
+ const keys = [];
219
+ const promises = [];
220
+ for (const i in value) {
221
+ if (value.hasOwnProperty(i)) {
222
+ keys.push(i);
223
+ this.preresolve(promises, value[i], i);
224
+ }
225
+ }
226
+ const values = await Promise.all(promises);
227
+ const raw = {};
228
+ keys.forEach((key, index) => {
229
+ _.set(raw, key, values[index]);
230
+ });
231
+ return raw;
232
+ }
233
+ static isNotNull(obj) {
234
+ return !this.isNull(obj);
235
+ }
236
+ static isNull(obj) {
237
+ return obj === undefined || obj === null;
238
+ }
239
+ static isFunction(obj) {
240
+ return this.isNotNull(obj) && obj instanceof Function;
241
+ }
242
+ static isNotFunction(obj) {
243
+ return !this.isFunction(obj);
244
+ }
245
+ static isStringEmpty(obj) {
246
+ return this.isNull(obj) || obj === '';
247
+ }
248
+ static isStringNotEmpty(obj) {
249
+ return !this.isStringEmpty(obj);
250
+ }
251
+ static isArrayEmpty(obj) {
252
+ return this.isNull(obj) || obj.length === 0;
253
+ }
254
+ static isArrayNotEmpty(obj) {
255
+ return !FxUtils.isArrayEmpty(obj);
256
+ }
257
+ static replaceStartWithAsterisk(inputString, numToReplace) {
258
+ if (numToReplace >= inputString.length) {
259
+ return '*'.repeat(inputString.length);
260
+ }
261
+ else if (numToReplace <= 0) {
262
+ return inputString;
263
+ }
264
+ else {
265
+ const asterisks = '*'.repeat(numToReplace);
266
+ const remainingString = inputString.substring(numToReplace);
267
+ return asterisks + remainingString;
268
+ }
269
+ }
270
+ static checkInvalidField(form) {
271
+ Object.keys(form.controls).forEach((field) => {
272
+ const control = form.controls[field];
273
+ control.markAsTouched({ onlySelf: true });
274
+ });
275
+ }
276
+ static checkInlineErrorField(err, f) {
277
+ if (err) {
278
+ Object.keys(err).forEach((field) => {
279
+ const formControl = f.form.get(field);
280
+ if (formControl) {
281
+ const error = { apiError: err[field] };
282
+ formControl.setErrors(error);
283
+ }
284
+ });
285
+ }
286
+ }
287
+ static isSameCollection(collection, compareCollection) {
288
+ return _.isEmpty(_.xor(collection, compareCollection));
289
+ }
290
+ static isSameValue(model, compareModel) {
291
+ return _.isEqual(model, compareModel);
292
+ }
293
+ static parseError(err) {
294
+ if (_.get(err, 'status') === 401) {
295
+ return 'Session timeout. Please login again.';
296
+ }
297
+ if (this.isStringEmpty(_.get(err, 'error.code'))) {
298
+ return _.get(err, 'error.message', 'Unknown Error');
299
+ }
300
+ return `${_.get(err, 'error.code')}: ${_.get(err, 'error.message', 'Unknown Error')}`;
301
+ }
302
+ static convertColorFromVariable(name, alpha = 1) {
303
+ const value = getComputedStyle(document.body)
304
+ .getPropertyValue(name)
305
+ .trim()
306
+ .replace(/\s+/g, ' ');
307
+ return value ? `rgba(${value} / ${alpha})` : `rgba(255 255 255 / ${alpha})`;
308
+ }
309
+ static getTagClass(key, isCriticalExist = false) {
310
+ switch (key.toLowerCase()) {
311
+ case 'error':
312
+ case 'failed':
313
+ case 'inactive':
314
+ case 'critical':
315
+ return 'critical';
316
+ case 'high':
317
+ if (isCriticalExist) {
318
+ return 'danger';
319
+ }
320
+ return 'critical';
321
+ case 'inprogress':
322
+ case 'paused':
323
+ case 'medium':
324
+ return 'warning';
325
+ case 'completed':
326
+ case 'success':
327
+ case 'active':
328
+ case 'low':
329
+ return 'success';
330
+ case 'queue':
331
+ case 'info':
332
+ return 'information';
333
+ case 'discovery':
334
+ return 'discovery';
335
+ case 'disabled':
336
+ default:
337
+ return 'default';
338
+ }
339
+ }
340
+ static validateEmail(value) {
341
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
342
+ const isEmail = emailRegex.test(value);
343
+ return isEmail;
344
+ }
345
+ }
346
+
347
+ class HttpWrapper {
348
+ http;
349
+ baseURL;
350
+ constructor(http, baseURL) {
351
+ this.http = http;
352
+ this.baseURL = baseURL;
353
+ }
354
+ addCredentials(options = {}) {
355
+ return {
356
+ withCredentials: true,
357
+ ...options,
358
+ };
359
+ }
360
+ async get(url = '', params) {
361
+ const options = {
362
+ withCredentials: true,
363
+ params: {
364
+ ...params,
365
+ },
366
+ };
367
+ return firstValueFrom(this.http.get(this.baseURL + url, options));
368
+ }
369
+ async post(url, body = {}, options = {}) {
370
+ return firstValueFrom(this.http.post(this.baseURL + url, body, this.addCredentials(options)));
371
+ }
372
+ async put(url, body, options = {}) {
373
+ return firstValueFrom(this.http.put(this.baseURL + url, body, this.addCredentials(options)));
374
+ }
375
+ async delete(url, options = {}) {
376
+ return firstValueFrom(this.http.delete(this.baseURL + url, this.addCredentials(options)));
377
+ }
378
+ async search(params = {}) {
379
+ return await this.get('/search', params);
380
+ }
381
+ async detail(params) {
382
+ return await this.get(`/detail`, params);
383
+ }
384
+ async remove(params = {}) {
385
+ return await this.delete(`/remove`, params);
386
+ }
387
+ async create(data) {
388
+ return await this.post(`/create`, data);
389
+ }
390
+ async updateInfo(data, params) {
391
+ return await this.put(`/update-info`, data, { params: params });
392
+ }
393
+ async updateStatus(data, params) {
394
+ return await this.put(`/update-status`, data, { params: params });
395
+ }
396
+ async update(data, params) {
397
+ return await this.put(`/update`, data, { params: params });
398
+ }
399
+ async single(code) {
400
+ return await this.post(`/${code}`, {});
401
+ }
402
+ async selectize() {
403
+ return await this.post('/search', {});
404
+ }
405
+ async fetch(filter = {}, params = {}) {
406
+ return await this.post('', filter, { params: params });
407
+ }
408
+ async published(idOrCode) {
409
+ return await this.post(`/published/${idOrCode}`);
410
+ }
411
+ async unpublished(idOrCode) {
412
+ return await this.post(`/unpublished/${idOrCode}`);
413
+ }
414
+ async terminated(idOrCode) {
415
+ return await this.post(`/terminated/${idOrCode}`);
416
+ }
417
+ async disable(params) {
418
+ return await this.post(`/disable`, params);
419
+ }
420
+ }
421
+
422
+ class BaseTableComponent extends BaseComponent {
423
+ api;
424
+ modal;
425
+ ref;
426
+ dataSource = new MatTableDataSource();
427
+ cols = [];
428
+ total = 0;
429
+ page = 1;
430
+ pageSize = 5;
431
+ filters = {};
432
+ loading = false;
433
+ expandedElement;
434
+ toastr;
435
+ _lock = false;
436
+ config;
437
+ paginator;
438
+ table;
439
+ constructor(injector, api, modal, ref) {
440
+ super(injector);
441
+ this.api = api;
442
+ this.modal = modal;
443
+ this.ref = ref;
444
+ this.toastr = injector.get(FxToastrService);
445
+ }
446
+ ngOnInit() {
447
+ this.init();
448
+ }
449
+ init() { }
450
+ ngAfterViewInit() {
451
+ this.dataSource.paginator = this.paginator;
452
+ this.ref.detectChanges();
453
+ }
454
+ async refresh() {
455
+ this.page = 1;
456
+ await this.fetch();
457
+ }
458
+ setDataSource(result) {
459
+ this.dataSource.data = _.get(result, 'data');
460
+ this.total = _.get(result, 'total');
461
+ }
462
+ async fetch() {
463
+ this.loading = true;
464
+ try {
465
+ const params = { page: this.page, pageSize: this.pageSize, ...this.filters };
466
+ const result = await this.api.search(params);
467
+ this.setDataSource(result);
468
+ this.ref.detectChanges();
469
+ }
470
+ catch (err) {
471
+ this.toastr.error(FxUtils.parseError(err), 'Error');
472
+ }
473
+ finally {
474
+ this.loading = false;
475
+ }
476
+ }
477
+ async onPageChange(event) {
478
+ this.page = event.pageIndex;
479
+ this.pageSize = event.pageSize;
480
+ await this.fetch();
481
+ }
482
+ resolve() {
483
+ return {};
484
+ }
485
+ empty() {
486
+ return {};
487
+ }
488
+ async create() {
489
+ const conf = _.get(this.config, 'create');
490
+ const dialog = _.get(conf, 'dialog');
491
+ const size = _.get(conf, 'size');
492
+ if (_.isNil(conf) || _.isNil(dialog)) {
493
+ return;
494
+ }
495
+ if (this._lock) {
496
+ return;
497
+ }
498
+ this._lock = true;
499
+ let panelClass = 'fx-dialog';
500
+ if (size == '100%') {
501
+ panelClass = 'fx-fullsize-dialog';
502
+ }
503
+ let instance = this.modal.open(dialog, {
504
+ panelClass: panelClass,
505
+ autoFocus: false,
506
+ width: size,
507
+ disableClose: true,
508
+ data: {
509
+ data: this.empty(),
510
+ title: conf.title,
511
+ message: conf.message,
512
+ resolve: this.resolve(),
513
+ },
514
+ });
515
+ instance.afterClosed().subscribe((result) => {
516
+ if (result) {
517
+ this.refresh();
518
+ }
519
+ this._lock = false;
520
+ });
521
+ }
522
+ async update(model) {
523
+ const conf = _.get(this.config, 'update');
524
+ const dialog = _.get(conf, 'dialog');
525
+ const size = _.get(conf, 'size');
526
+ if (_.isNil(dialog) || _.isNil(conf)) {
527
+ return;
528
+ }
529
+ if (this._lock) {
530
+ return;
531
+ }
532
+ this._lock = true;
533
+ let panelClass = 'fx-dialog';
534
+ if (size == '100%') {
535
+ panelClass = 'fx-fullsize-dialog';
536
+ }
537
+ let instance = this.modal.open(dialog, {
538
+ panelClass: panelClass,
539
+ autoFocus: false,
540
+ width: size,
541
+ disableClose: true,
542
+ data: {
543
+ data: model,
544
+ title: conf.title,
545
+ message: conf.message,
546
+ resolve: this.resolve(),
547
+ },
548
+ });
549
+ instance.afterClosed().subscribe((result) => {
550
+ if (result) {
551
+ this.refresh();
552
+ }
553
+ this._lock = false;
554
+ });
555
+ }
556
+ async view(model) {
557
+ const conf = _.get(this.config, 'view');
558
+ const dialog = _.get(conf, 'dialog');
559
+ const size = _.get(conf, 'size');
560
+ if (_.isNil(dialog) || _.isNil(conf)) {
561
+ return;
562
+ }
563
+ if (this._lock) {
564
+ return;
565
+ }
566
+ this._lock = true;
567
+ let panelClass = 'fx-dialog';
568
+ if (size == '100%') {
569
+ panelClass = 'fx-fullsize-dialog';
570
+ }
571
+ let instance = this.modal.open(dialog, {
572
+ panelClass: panelClass,
573
+ autoFocus: false,
574
+ width: size,
575
+ disableClose: true,
576
+ data: {
577
+ data: model,
578
+ title: conf.title,
579
+ message: conf.message,
580
+ resolve: this.resolve(),
581
+ disabled: true,
582
+ },
583
+ });
584
+ instance.afterClosed().subscribe(() => {
585
+ this._lock = false;
586
+ });
587
+ }
588
+ async delete(model) {
589
+ if (this._lock) {
590
+ return;
591
+ }
592
+ this._lock = true;
593
+ const conf = _.get(this.config, 'delete');
594
+ const dialog = _.get(conf, 'dialog');
595
+ const dialogRef = this.modal.open(dialog, {
596
+ panelClass: 'fx-dialog',
597
+ autoFocus: false,
598
+ width: '400px',
599
+ data: {
600
+ title: _.get(conf, 'title'),
601
+ message: _.get(conf, 'message'),
602
+ cancelTitle: _.get(conf, 'cancelTitle'),
603
+ confirmTitle: _.get(conf, 'confirmTitle'),
604
+ },
605
+ });
606
+ dialogRef.afterClosed().subscribe(async (state) => {
607
+ if (state) {
608
+ try {
609
+ await this.remove(model);
610
+ this.refresh();
611
+ }
612
+ catch (err) {
613
+ this.toastr.error(FxUtils.parseError(err), 'Error');
614
+ }
615
+ return;
616
+ }
617
+ this._lock = false;
618
+ });
619
+ }
620
+ async remove(model) {
621
+ try {
622
+ return await this.api.remove({ ...model });
623
+ }
624
+ catch (err) {
625
+ throw err;
626
+ }
627
+ }
628
+ value(model, key) {
629
+ return _.get(model, key);
630
+ }
631
+ toggleExpand(element) {
632
+ this.expandedElement = this.expandedElement === element ? null : element;
633
+ }
634
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseTableComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
635
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: BaseTableComponent, isStandalone: true, viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "table", first: true, predicate: MatTable, descendants: true }], usesInheritance: true, ngImport: i0 });
636
+ }
637
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseTableComponent, decorators: [{
638
+ type: Directive
639
+ }], ctorParameters: () => [{ type: i0.Injector }, { type: HttpWrapper }, { type: undefined }, { type: i0.ChangeDetectorRef }], propDecorators: { paginator: [{
640
+ type: ViewChild,
641
+ args: [MatPaginator]
642
+ }], table: [{
643
+ type: ViewChild,
644
+ args: [MatTable]
645
+ }] } });
646
+
647
+ class BaseDialogComponent extends BaseComponent {
648
+ ref;
649
+ bindings;
650
+ toastr;
651
+ api;
652
+ dialog;
653
+ ngForm;
654
+ title;
655
+ model;
656
+ disabled;
657
+ loading;
658
+ message;
659
+ resolve;
660
+ formChangesSubscription;
661
+ onSubmit = true;
662
+ constructor(ref, bindings, toastr, api, dialog) {
663
+ super(bindings);
664
+ this.ref = ref;
665
+ this.bindings = bindings;
666
+ this.toastr = toastr;
667
+ this.api = api;
668
+ this.dialog = dialog;
669
+ this.model = _.clone(_.get(bindings, 'data'));
670
+ this.title = _.get(bindings, 'title');
671
+ this.disabled = _.get(bindings, 'disabled');
672
+ this.message = _.get(bindings, 'message');
673
+ this.resolve = _.get(bindings, 'resolve');
674
+ }
675
+ ngAfterViewInit() { }
676
+ ngOnInit() { }
677
+ accept(form, params = null) {
678
+ if (form.invalid) {
679
+ return;
680
+ }
681
+ if (!this.disabled) {
682
+ if (!this.validate())
683
+ return;
684
+ if (_.isEmpty(this.model.id)) {
685
+ this.create(params);
686
+ return;
687
+ }
688
+ else {
689
+ this.update(params);
690
+ return;
691
+ }
692
+ }
693
+ this.cancel();
694
+ }
695
+ create(params = null) {
696
+ if (this.loading) {
697
+ return;
698
+ }
699
+ this.loading = true;
700
+ this.api
701
+ .create({ ...this.model, ...params })
702
+ .then(() => {
703
+ this.toastr.success(this.message);
704
+ this.ref.close(true);
705
+ }, (error) => {
706
+ this.toastr.error(error);
707
+ })
708
+ .then(() => {
709
+ this.loading = false;
710
+ });
711
+ }
712
+ update(params = null) {
713
+ if (this.loading) {
714
+ return;
715
+ }
716
+ this.loading = true;
717
+ let code = _.get(this.model, 'code');
718
+ this.api
719
+ .update(code, { ...this.model, ...params })
720
+ .then(() => {
721
+ this.toastr.success(this.message);
722
+ this.ref.close(true);
723
+ }, (error) => {
724
+ this.toastr.error(error);
725
+ })
726
+ .then(() => {
727
+ this.loading = false;
728
+ });
729
+ }
730
+ updateData(params = null) {
731
+ if (this.loading) {
732
+ return;
733
+ }
734
+ this.loading = true;
735
+ this.api
736
+ .update({ ...this.model, ...params })
737
+ .then(() => {
738
+ this.toastr.success(this.message);
739
+ this.ref.close(true);
740
+ }, (error) => {
741
+ this.toastr.error(error);
742
+ })
743
+ .then(() => {
744
+ this.loading = false;
745
+ });
746
+ }
747
+ updateInfo(params = null) {
748
+ if (this.loading) {
749
+ return;
750
+ }
751
+ this.loading = true;
752
+ this.api
753
+ .updateInfo({ ...this.model, ...params })
754
+ .then(() => {
755
+ this.toastr.success(this.message);
756
+ this.ref.close(true);
757
+ }, (error) => {
758
+ this.toastr.error(error);
759
+ })
760
+ .then(() => {
761
+ this.loading = false;
762
+ });
763
+ }
764
+ cancel() {
765
+ this.ref.close(false);
766
+ }
767
+ validate() {
768
+ return true;
769
+ }
770
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseDialogComponent, deps: [{ token: i1$1.MatDialogRef }, { token: MAT_DIALOG_DATA }, { token: FxToastrService }, { token: HttpWrapper }, { token: i1$1.MatDialog }], target: i0.ɵɵFactoryTarget.Directive });
771
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: BaseDialogComponent, isStandalone: true, viewQueries: [{ propertyName: "ngForm", first: true, predicate: ["f"], descendants: true, static: true }], usesInheritance: true, ngImport: i0 });
772
+ }
773
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseDialogComponent, decorators: [{
774
+ type: Directive
775
+ }], ctorParameters: () => [{ type: i1$1.MatDialogRef }, { type: undefined, decorators: [{
776
+ type: Inject,
777
+ args: [MAT_DIALOG_DATA]
778
+ }] }, { type: FxToastrService }, { type: HttpWrapper }, { type: i1$1.MatDialog }], propDecorators: { ngForm: [{
779
+ type: ViewChild,
780
+ args: ['f', { static: true }]
781
+ }] } });
782
+
783
+ class FxLoadingService {
784
+ listener = new EventEmitter();
785
+ listenerAction = new EventEmitter();
786
+ start() {
787
+ this.listener.emit(true);
788
+ }
789
+ stop() {
790
+ this.listener.emit(false);
791
+ }
792
+ startAction() {
793
+ this.listenerAction.emit(true);
794
+ }
795
+ stopAction() {
796
+ this.listenerAction.emit(false);
797
+ }
798
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxLoadingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
799
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxLoadingService, providedIn: 'root' });
800
+ }
801
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxLoadingService, decorators: [{
802
+ type: Injectable,
803
+ args: [{
804
+ providedIn: 'root'
805
+ }]
806
+ }] });
807
+
808
+ class BaseResolver {
809
+ loadingService;
810
+ injector;
811
+ constructor(loadingService, injector) {
812
+ this.loadingService = loadingService;
813
+ this.injector = injector;
814
+ }
815
+ baseResolverInit() {
816
+ this.loadingService.start();
817
+ }
818
+ }
819
+
820
+ function HttpLoaderFactory(http) {
821
+ return new TranslateHttpLoader(http, '/assets/i18n/', '.json');
822
+ }
823
+ class TranslationModule {
824
+ static forRoot() {
825
+ return {
826
+ ngModule: TranslationModule,
827
+ providers: [
828
+ {
829
+ provide: TranslateLoader,
830
+ useFactory: HttpLoaderFactory,
831
+ deps: [HttpClient]
832
+ }
833
+ ]
834
+ };
835
+ }
836
+ static forChild() {
837
+ return {
838
+ ngModule: TranslationModule,
839
+ providers: []
840
+ };
841
+ }
842
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
843
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: TranslationModule, imports: [TranslateModule], exports: [TranslateModule] });
844
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationModule, imports: [TranslateModule, TranslateModule] });
845
+ }
846
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationModule, decorators: [{
847
+ type: NgModule,
848
+ args: [{
849
+ imports: [TranslateModule],
850
+ exports: [TranslateModule]
851
+ }]
852
+ }] });
853
+
854
+ class TranslationService {
855
+ translate;
856
+ http;
857
+ currentLangSubject = new BehaviorSubject('en');
858
+ currentLang$ = this.currentLangSubject.asObservable();
859
+ constructor(translate, http) {
860
+ this.translate = translate;
861
+ this.http = http;
862
+ // Default fallback
863
+ this.translate.addLangs(['en', 'vi']);
864
+ this.translate.setDefaultLang('en');
865
+ }
866
+ init(lang) {
867
+ this.setLanguage(lang);
868
+ }
869
+ currentLang() {
870
+ return this.translate.currentLang || this.translate.defaultLang;
871
+ }
872
+ setLanguage(lang) {
873
+ this.translate.use(lang);
874
+ this.currentLangSubject.next(lang);
875
+ }
876
+ loadTranslations(lang, path) {
877
+ const url = `${path}${lang}.json`;
878
+ this.http.get(url).subscribe({
879
+ next: (translations) => {
880
+ this.translate.setTranslation(lang, translations, true);
881
+ },
882
+ error: (err) => {
883
+ console.warn(`[TranslationService] Failed to load ${url}`, err);
884
+ }
885
+ });
886
+ }
887
+ onLanguageChange(callback) {
888
+ this.currentLang$.subscribe(callback);
889
+ }
890
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, deps: [{ token: i1$2.TranslateService }, { token: i2$1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
891
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, providedIn: 'root' });
892
+ }
893
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, decorators: [{
894
+ type: Injectable,
895
+ args: [{ providedIn: 'root' }]
896
+ }], ctorParameters: () => [{ type: i1$2.TranslateService }, { type: i2$1.HttpClient }] });
897
+
898
+ class PermissionService {
899
+ permissions = [];
900
+ setPermissions(perms) {
901
+ this.permissions = perms;
902
+ }
903
+ hasPermission(requiredPermissions) {
904
+ return _.some(requiredPermissions, permission => this.permissions.includes(permission));
905
+ }
906
+ getPermissions() {
907
+ return [...this.permissions];
908
+ }
909
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
910
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionService, providedIn: 'root' });
911
+ }
912
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionService, decorators: [{
913
+ type: Injectable,
914
+ args: [{
915
+ providedIn: 'root'
916
+ }]
917
+ }] });
918
+
919
+ class HasPermissionDirective {
920
+ templateRef;
921
+ viewContainerRef;
922
+ permissionService;
923
+ constructor(templateRef, viewContainerRef, permissionService) {
924
+ this.templateRef = templateRef;
925
+ this.viewContainerRef = viewContainerRef;
926
+ this.permissionService = permissionService;
927
+ }
928
+ set hasPermission(required) {
929
+ const requiredPermissions = _.isArray(required) ? required : [required];
930
+ this.viewContainerRef.clear();
931
+ if (this.permissionService.hasPermission(requiredPermissions)) {
932
+ this.viewContainerRef.createEmbeddedView(this.templateRef);
933
+ }
934
+ }
935
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HasPermissionDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: PermissionService }], target: i0.ɵɵFactoryTarget.Directive });
936
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: HasPermissionDirective, isStandalone: true, selector: "[hasPermission]", inputs: { hasPermission: "hasPermission" }, ngImport: i0 });
937
+ }
938
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HasPermissionDirective, decorators: [{
939
+ type: Directive,
940
+ args: [{
941
+ selector: '[hasPermission]'
942
+ }]
943
+ }], ctorParameters: () => [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: PermissionService }], propDecorators: { hasPermission: [{
944
+ type: Input
945
+ }] } });
946
+
947
+ class PermissionGuard {
948
+ permissionService;
949
+ router;
950
+ constructor(permissionService, router) {
951
+ this.permissionService = permissionService;
952
+ this.router = router;
953
+ }
954
+ canActivate(route) {
955
+ const requiredPermissions = route.data?.['permissions'];
956
+ if (!requiredPermissions || this.permissionService.hasPermission(requiredPermissions)) {
957
+ return true;
958
+ }
959
+ this.router.navigate(['/unauthorized']);
960
+ return false;
961
+ }
962
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionGuard, deps: [{ token: PermissionService }, { token: i2$2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
963
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionGuard, providedIn: 'root' });
964
+ }
965
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionGuard, decorators: [{
966
+ type: Injectable,
967
+ args: [{
968
+ providedIn: 'root',
969
+ }]
970
+ }], ctorParameters: () => [{ type: PermissionService }, { type: i2$2.Router }] });
971
+
972
+ class FxStorageService {
973
+ resolve(key, value) {
974
+ if (FxUtils.isNotNull(value)) {
975
+ localStorage.setItem(key, JSON.stringify(value));
976
+ }
977
+ const loc = localStorage.getItem(key);
978
+ return loc ? JSON.parse(loc) : undefined;
979
+ }
980
+ remove(key) {
981
+ localStorage.removeItem(key);
982
+ }
983
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
984
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, providedIn: 'root' });
985
+ }
986
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, decorators: [{
987
+ type: Injectable,
988
+ args: [{
989
+ providedIn: 'root',
990
+ }]
991
+ }] });
992
+
993
+ class AuthStateService {
994
+ _isLoggedIn$ = new BehaviorSubject(false);
995
+ isLoggedIn$ = this._isLoggedIn$.asObservable();
996
+ unauthorized$ = new Subject();
997
+ constructor() {
998
+ const saved = localStorage.getItem('isLoggedIn') === 'true';
999
+ this._isLoggedIn$.next(saved);
1000
+ }
1001
+ setLoggedIn(value) {
1002
+ this._isLoggedIn$.next(value);
1003
+ localStorage.setItem('isLoggedIn', String(value));
1004
+ }
1005
+ get isLoggedIn() {
1006
+ return this._isLoggedIn$.value;
1007
+ }
1008
+ handleUnauthorized() {
1009
+ this.setLoggedIn(false);
1010
+ this.unauthorized$.next();
1011
+ }
1012
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1013
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthStateService, providedIn: 'root' });
1014
+ }
1015
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthStateService, decorators: [{
1016
+ type: Injectable,
1017
+ args: [{ providedIn: 'root' }]
1018
+ }], ctorParameters: () => [] });
1019
+
1020
+ class AuthInterceptor {
1021
+ authState;
1022
+ constructor(authState) {
1023
+ this.authState = authState;
1024
+ }
1025
+ intercept(req, next) {
1026
+ const cloned = req.clone({ withCredentials: true });
1027
+ return next.handle(cloned).pipe(catchError((error) => {
1028
+ if (error.status === 401) {
1029
+ this.authState.handleUnauthorized();
1030
+ }
1031
+ return throwError(() => error);
1032
+ }));
1033
+ }
1034
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthInterceptor, deps: [{ token: AuthStateService }], target: i0.ɵɵFactoryTarget.Injectable });
1035
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthInterceptor });
1036
+ }
1037
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthInterceptor, decorators: [{
1038
+ type: Injectable
1039
+ }], ctorParameters: () => [{ type: AuthStateService }] });
1040
+
1041
+ class BreadcrumbService {
1042
+ breadcrumbs$ = new BehaviorSubject([]);
1043
+ set(breadcrumbs) {
1044
+ this.breadcrumbs$.next(breadcrumbs);
1045
+ }
1046
+ get() {
1047
+ return this.breadcrumbs$.asObservable();
1048
+ }
1049
+ clear() {
1050
+ this.breadcrumbs$.next([]);
1051
+ }
1052
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BreadcrumbService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1053
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BreadcrumbService, providedIn: 'root' });
1054
+ }
1055
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BreadcrumbService, decorators: [{
1056
+ type: Injectable,
1057
+ args: [{
1058
+ providedIn: 'root'
1059
+ }]
1060
+ }] });
1061
+
1062
+ const MATERIAL_MODULE = [
1063
+ MatSelectModule,
1064
+ MatRadioModule,
1065
+ MatButtonModule,
1066
+ MatIconModule,
1067
+ MatPaginatorModule,
1068
+ MatTableModule,
1069
+ MatSnackBarModule,
1070
+ MatDialogModule,
1071
+ MatCheckboxModule,
1072
+ MatCardModule,
1073
+ MatDatepickerModule,
1074
+ MatTimepickerModule,
1075
+ MatBadgeModule,
1076
+ MatExpansionModule,
1077
+ MatFormFieldModule
1078
+ ];
1079
+
1080
+ class ButtonComponent {
1081
+ label;
1082
+ disabled = false;
1083
+ buttonVariant = 'alternative';
1084
+ icon;
1085
+ class;
1086
+ loading = false;
1087
+ clicked = new EventEmitter();
1088
+ onClick() {
1089
+ if (!this.disabled)
1090
+ this.clicked.emit();
1091
+ }
1092
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1093
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ButtonComponent, isStandalone: false, selector: "fx-ui-button", inputs: { label: "label", disabled: "disabled", buttonVariant: "buttonVariant", icon: "icon", class: "class", loading: "loading" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n [class]=\"class\"\n [ngClass]=\"{\n 'btn-default': buttonVariant === 'default',\n 'btn-primary': buttonVariant === 'primary',\n 'btn-alternative': buttonVariant === 'alternative',\n }\"\n [disabled]=\"disabled || loading\"\n (click)=\"onClick()\"\n>\n @if (loading) {\n <div class=\"flex w-full items-center justify-center\">\n <svg\n [attr.fill]=\"\n buttonVariant !== 'alternative' ? 'rgb(var(--text-primary))' : 'rgb(var(--primary))'\n \"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle cx=\"4\" cy=\"12\" r=\"0\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_lo66\"\n begin=\"spinner_Aguh.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_z0Or\"\n begin=\"spinner_lo66.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"4\" cy=\"12\" r=\"3\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_JsnR\"\n begin=\"spinner_UHR2.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_Aguh\"\n begin=\"spinner_JsnR.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"12\" cy=\"12\" r=\"3\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_hSjk\"\n begin=\"spinner_OLMs.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_UHR2\"\n begin=\"spinner_hSjk.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"20\" cy=\"12\" r=\"3\">\n <animate\n id=\"spinner_4v5M\"\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_OLMs\"\n begin=\"spinner_4v5M.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n </circle>\n </svg>\n </div>\n } @else {\n <ng-container>\n <div class=\"flex items-center justify-center gap-small\">\n @if(icon) {<fx-ui-hero-icon [icon]=\"icon\" [size]=\"20\" class=\"flex\" [ngClass]=\"{\n 'text-text-inverse': buttonVariant !== 'default',\n 'text-text-primary': buttonVariant === 'alternative'\n }\"></fx-ui-hero-icon>}\n <div>{{ label }}</div>\n </div>\n </ng-container>\n }\n</button>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["icon", "solid", "outline", "size", "color", "class"] }] });
1094
+ }
1095
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ButtonComponent, decorators: [{
1096
+ type: Component,
1097
+ args: [{ selector: 'fx-ui-button', standalone: false, template: "<button\n [class]=\"class\"\n [ngClass]=\"{\n 'btn-default': buttonVariant === 'default',\n 'btn-primary': buttonVariant === 'primary',\n 'btn-alternative': buttonVariant === 'alternative',\n }\"\n [disabled]=\"disabled || loading\"\n (click)=\"onClick()\"\n>\n @if (loading) {\n <div class=\"flex w-full items-center justify-center\">\n <svg\n [attr.fill]=\"\n buttonVariant !== 'alternative' ? 'rgb(var(--text-primary))' : 'rgb(var(--primary))'\n \"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle cx=\"4\" cy=\"12\" r=\"0\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_lo66\"\n begin=\"spinner_Aguh.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_z0Or\"\n begin=\"spinner_lo66.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"4\" cy=\"12\" r=\"3\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_JsnR\"\n begin=\"spinner_UHR2.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_Aguh\"\n begin=\"spinner_JsnR.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"12\" cy=\"12\" r=\"3\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_hSjk\"\n begin=\"spinner_OLMs.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_UHR2\"\n begin=\"spinner_hSjk.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"20\" cy=\"12\" r=\"3\">\n <animate\n id=\"spinner_4v5M\"\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_OLMs\"\n begin=\"spinner_4v5M.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n </circle>\n </svg>\n </div>\n } @else {\n <ng-container>\n <div class=\"flex items-center justify-center gap-small\">\n @if(icon) {<fx-ui-hero-icon [icon]=\"icon\" [size]=\"20\" class=\"flex\" [ngClass]=\"{\n 'text-text-inverse': buttonVariant !== 'default',\n 'text-text-primary': buttonVariant === 'alternative'\n }\"></fx-ui-hero-icon>}\n <div>{{ label }}</div>\n </div>\n </ng-container>\n }\n</button>\n" }]
1098
+ }], propDecorators: { label: [{
1099
+ type: Input
1100
+ }], disabled: [{
1101
+ type: Input
1102
+ }], buttonVariant: [{
1103
+ type: Input
1104
+ }], icon: [{
1105
+ type: Input
1106
+ }], class: [{
1107
+ type: Input
1108
+ }], loading: [{
1109
+ type: Input
1110
+ }], clicked: [{
1111
+ type: Output
1112
+ }] } });
1113
+
1114
+ class ChartComponent {
1115
+ ref;
1116
+ cdr;
1117
+ type = 'auto';
1118
+ data;
1119
+ options;
1120
+ palette;
1121
+ height = '400px';
1122
+ loading = false;
1123
+ chartClick = new EventEmitter();
1124
+ chartInit = new EventEmitter();
1125
+ labelFontSize = 12;
1126
+ labelFontFamily = 'BeVietnamProRegular';
1127
+ chartOptions = {};
1128
+ chartInstance;
1129
+ resizeObserver;
1130
+ constructor(ref, cdr) {
1131
+ this.ref = ref;
1132
+ this.cdr = cdr;
1133
+ }
1134
+ ngAfterViewInit() {
1135
+ this.resizeObserver = new ResizeObserver(() => {
1136
+ if (this.chartInstance)
1137
+ this.chartInstance.resize();
1138
+ });
1139
+ this.resizeObserver.observe(this.ref.nativeElement);
1140
+ }
1141
+ ngOnDestroy() {
1142
+ if (this.resizeObserver)
1143
+ this.resizeObserver.disconnect();
1144
+ }
1145
+ ngOnChanges() {
1146
+ this.rebuildChart();
1147
+ }
1148
+ onThemeChange() {
1149
+ requestAnimationFrame(() => {
1150
+ this.rebuildChart();
1151
+ });
1152
+ }
1153
+ onChartClick(event) {
1154
+ this.chartClick.emit(event);
1155
+ }
1156
+ onChartInit(chart) {
1157
+ this.chartInstance = chart;
1158
+ this.chartInit.emit(chart);
1159
+ requestAnimationFrame(() => this.chartInstance?.resize());
1160
+ setTimeout(() => this.chartInstance?.resize(), 100);
1161
+ }
1162
+ rebuildChart() {
1163
+ this.chartOptions = this.buildOptions();
1164
+ if (this.chartInstance) {
1165
+ this.chartInstance.clear();
1166
+ this.chartInstance.setOption(this.chartOptions, true);
1167
+ }
1168
+ this.cdr.detectChanges();
1169
+ }
1170
+ registry = {
1171
+ bar: (data, colors) => ({
1172
+ color: colors,
1173
+ tooltip: { trigger: 'axis' },
1174
+ grid: {
1175
+ left: '5%',
1176
+ right: '5%',
1177
+ bottom: '10%',
1178
+ containLabel: true,
1179
+ },
1180
+ xAxis: {
1181
+ type: 'category',
1182
+ data: data?.categories || [],
1183
+ axisLabel: {
1184
+ fontFamily: this.labelFontFamily,
1185
+ fontSize: this.labelFontSize,
1186
+ color: FxUtils.convertColorFromVariable('--text-secondary'),
1187
+ },
1188
+ axisLine: {
1189
+ lineStyle: { color: FxUtils.convertColorFromVariable('--border-strong') },
1190
+ },
1191
+ splitLine: { show: false },
1192
+ },
1193
+ yAxis: {
1194
+ type: 'value',
1195
+ axisLabel: {
1196
+ fontFamily: this.labelFontFamily,
1197
+ fontSize: this.labelFontSize,
1198
+ color: FxUtils.convertColorFromVariable('--text-secondary'),
1199
+ },
1200
+ axisLine: {
1201
+ lineStyle: { color: FxUtils.convertColorFromVariable('--border-strong') },
1202
+ },
1203
+ splitLine: {
1204
+ lineStyle: { color: FxUtils.convertColorFromVariable('--border-default') },
1205
+ },
1206
+ },
1207
+ series: [
1208
+ {
1209
+ type: 'bar',
1210
+ data: data?.values || [],
1211
+ label: {
1212
+ show: true,
1213
+ position: 'top',
1214
+ fontFamily: this.labelFontFamily,
1215
+ fontSize: this.labelFontSize,
1216
+ color: FxUtils.convertColorFromVariable('--text-primary'),
1217
+ textBorderWidth: 0,
1218
+ textBorderColor: 'transparent',
1219
+ },
1220
+ emphasis: { itemStyle: { opacity: 0.8 } },
1221
+ },
1222
+ ],
1223
+ }),
1224
+ pie: (data, colors) => ({
1225
+ color: colors,
1226
+ tooltip: { trigger: 'item' },
1227
+ legend: {
1228
+ orient: 'vertical',
1229
+ top: 'bottom',
1230
+ right: 10,
1231
+ textStyle: {
1232
+ fontFamily: "BeVietnamProRegular",
1233
+ color: FxUtils.convertColorFromVariable('--text-primary'),
1234
+ fontSize: 12,
1235
+ fontWeight: 500,
1236
+ },
1237
+ icon: 'circle',
1238
+ itemGap: 8,
1239
+ padding: 0,
1240
+ },
1241
+ series: [
1242
+ {
1243
+ type: 'pie',
1244
+ radius: ['40%', '70%'],
1245
+ avoidLabelOverlap: true,
1246
+ data,
1247
+ label: {
1248
+ //{a} Series name
1249
+ //{b} Data name (slice label)
1250
+ //{c} Data value
1251
+ //{d} Percentage
1252
+ formatter: '{b}: {c}',
1253
+ fontSize: this.labelFontSize,
1254
+ fontFamily: this.labelFontFamily,
1255
+ color: FxUtils.convertColorFromVariable('--text-primary'),
1256
+ textBorderWidth: 0,
1257
+ textBorderColor: 'transparent',
1258
+ },
1259
+ labelLine: {
1260
+ show: true,
1261
+ length: 15,
1262
+ length2: 15,
1263
+ },
1264
+ itemStyle: {
1265
+ borderWidth: 0,
1266
+ },
1267
+ emphasis: {
1268
+ scale: true,
1269
+ scaleSize: 10,
1270
+ itemStyle: { borderWidth: 0 },
1271
+ label: { textBorderWidth: 0 },
1272
+ },
1273
+ },
1274
+ ],
1275
+ }),
1276
+ sunburst: (data, colors) => ({
1277
+ color: colors,
1278
+ series: [
1279
+ {
1280
+ type: 'sunburst',
1281
+ data,
1282
+ radius: ['15%', '90%'],
1283
+ itemStyle: {
1284
+ borderWidth: 1,
1285
+ borderColor: FxUtils.convertColorFromVariable('--border-default'),
1286
+ },
1287
+ label: {
1288
+ rotate: 'tangential',
1289
+ fontSize: this.labelFontSize,
1290
+ fontFamily: this.labelFontFamily,
1291
+ color: FxUtils.convertColorFromVariable('--text-primary'),
1292
+ textBorderWidth: 0,
1293
+ textBorderColor: 'transparent',
1294
+ },
1295
+ },
1296
+ ],
1297
+ }),
1298
+ };
1299
+ detectType() {
1300
+ if (this.type !== 'auto')
1301
+ return this.type;
1302
+ if (this.data?.children)
1303
+ return 'sunburst';
1304
+ if (this.data?.categories && this.data?.values)
1305
+ return 'bar';
1306
+ if (Array.isArray(this.data) && this.data[0]?.value && this.data[0]?.name)
1307
+ return 'pie';
1308
+ return 'bar';
1309
+ }
1310
+ buildOptions() {
1311
+ const chartType = this.detectType();
1312
+ const palette = this.resolvePalette();
1313
+ const baseBuilder = this.registry[chartType];
1314
+ const baseOptions = baseBuilder ? baseBuilder(this.data, palette) : {};
1315
+ const textColor = FxUtils.convertColorFromVariable('--text-primary');
1316
+ const mergedOptions = {
1317
+ legend: {
1318
+ textStyle: {
1319
+ fontFamily: this.labelFontFamily,
1320
+ color: textColor,
1321
+ fontSize: this.labelFontSize,
1322
+ fontWeight: 500,
1323
+ },
1324
+ icon: 'circle',
1325
+ itemGap: 16,
1326
+ },
1327
+ ...baseOptions,
1328
+ ...this.options,
1329
+ };
1330
+ return mergedOptions;
1331
+ }
1332
+ resolvePalette() {
1333
+ const defaultPalette = [
1334
+ 'rgba(var(--critical) / 1)',
1335
+ 'rgba(var(--danger) / 1)',
1336
+ 'rgba(var(--warning) / 1)',
1337
+ 'rgba(var(--success) / 1)',
1338
+ 'rgba(var(--information) / 1)',
1339
+ 'rgba(var(--discovery) / 1)',
1340
+ ];
1341
+ const palette = !this.palette || this.palette.length === 0 ? defaultPalette : this.palette;
1342
+ return palette.map((raw) => {
1343
+ if (raw.includes('var(')) {
1344
+ const cssVar = raw.match(/var\((.*?)\)/)?.[1];
1345
+ const opacityMatch = raw.match(/\/\s*([\d.]+)/);
1346
+ const opacity = opacityMatch ? parseFloat(opacityMatch[1]) : 1;
1347
+ const rgb = getComputedStyle(document.body)
1348
+ .getPropertyValue(cssVar || '')
1349
+ .trim()
1350
+ .replace(/\s+/g, ',');
1351
+ return `rgba(${rgb}, ${opacity})`;
1352
+ }
1353
+ return raw;
1354
+ });
1355
+ }
1356
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChartComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1357
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: ChartComponent, isStandalone: false, selector: "fx-ui-chart", inputs: { type: "type", data: "data", options: "options", palette: "palette", height: "height", loading: "loading" }, outputs: { chartClick: "chartClick", chartInit: "chartInit" }, host: { listeners: { "window:theme-changed": "onThemeChange()" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"chart-wrapper\" [style.height]=\"height\" [class.loading]=\"loading\">\n <div\n echarts\n [options]=\"chartOptions\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"w-full h-full\">\n </div>\n\n <div class=\"chart-loader\" *ngIf=\"loading\">\n <span class=\"txt-default\">Loading...</span>\n </div>\n</div>", styles: [".chart-wrapper{position:relative;width:100%}.chart-container{width:100%;height:100%}.chart-loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--bg-primary-hover)/.6);font-weight:500;font-size:1.1rem;z-index:2;border-radius:4px}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$3.NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
1358
+ }
1359
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChartComponent, decorators: [{
1360
+ type: Component,
1361
+ args: [{ selector: 'fx-ui-chart', standalone: false, template: "<div class=\"chart-wrapper\" [style.height]=\"height\" [class.loading]=\"loading\">\n <div\n echarts\n [options]=\"chartOptions\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"w-full h-full\">\n </div>\n\n <div class=\"chart-loader\" *ngIf=\"loading\">\n <span class=\"txt-default\">Loading...</span>\n </div>\n</div>", styles: [".chart-wrapper{position:relative;width:100%}.chart-container{width:100%;height:100%}.chart-loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--bg-primary-hover)/.6);font-weight:500;font-size:1.1rem;z-index:2;border-radius:4px}\n"] }]
1362
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { type: [{
1363
+ type: Input
1364
+ }], data: [{
1365
+ type: Input
1366
+ }], options: [{
1367
+ type: Input
1368
+ }], palette: [{
1369
+ type: Input
1370
+ }], height: [{
1371
+ type: Input
1372
+ }], loading: [{
1373
+ type: Input
1374
+ }], chartClick: [{
1375
+ type: Output
1376
+ }], chartInit: [{
1377
+ type: Output
1378
+ }], onThemeChange: [{
1379
+ type: HostListener,
1380
+ args: ['window:theme-changed']
1381
+ }] } });
1382
+
1383
+ let FxComponent = class FxComponent {
1384
+ ngControl;
1385
+ value;
1386
+ onChange = (value) => { };
1387
+ onTouched = () => { };
1388
+ validationError;
1389
+ errorMessages;
1390
+ constructor(ngControl) {
1391
+ this.ngControl = ngControl;
1392
+ if (ngControl)
1393
+ ngControl.valueAccessor = this;
1394
+ }
1395
+ setValue(value) {
1396
+ if (this.onChange) {
1397
+ this.onChange(value);
1398
+ }
1399
+ }
1400
+ onEnter(value) {
1401
+ if (this.onChange) {
1402
+ this.onChange(value);
1403
+ }
1404
+ }
1405
+ writeValue(value) {
1406
+ this.value = value ?? '';
1407
+ }
1408
+ registerOnChange(fn) {
1409
+ this.onChange = fn;
1410
+ }
1411
+ registerOnTouched(fn) {
1412
+ this.onTouched = fn;
1413
+ }
1414
+ get invalid() {
1415
+ return !!(this.ngControl?.invalid && this.ngControl?.touched);
1416
+ }
1417
+ get errors() {
1418
+ return this.ngControl?.errors || {};
1419
+ }
1420
+ validate(validateFn) {
1421
+ if (this.invalid)
1422
+ return;
1423
+ if (validateFn) {
1424
+ const error = validateFn(this.value);
1425
+ if (FxUtils.isNotNull(error)) {
1426
+ this.setErrors(error ?? {});
1427
+ }
1428
+ }
1429
+ }
1430
+ setErrors(error) {
1431
+ this.validationError = error;
1432
+ const control = this.ngControl?.control;
1433
+ if (!control)
1434
+ return;
1435
+ control.setErrors(error);
1436
+ }
1437
+ clearErrors() {
1438
+ const control = this.ngControl?.control;
1439
+ if (!control)
1440
+ return;
1441
+ control.setErrors(null);
1442
+ }
1443
+ getErrorMessage(label) {
1444
+ if (!this.errors)
1445
+ return null;
1446
+ const displayLabel = FxUtils.isStringEmpty(label ?? '') ? 'This field' : label;
1447
+ const defaultMessages = {
1448
+ required: `${displayLabel} is required`,
1449
+ minlength: `${displayLabel} minimum length is ${this.errors['minlength']?.requiredLength}`,
1450
+ };
1451
+ const messages = { ...defaultMessages, ...this.validationError, ...this.errorMessages };
1452
+ const firstKey = Object.keys(this.errors)[0];
1453
+ return messages[firstKey] || `Invalid ${label ?? 'value'}`;
1454
+ }
1455
+ };
1456
+ FxComponent = __decorate([
1457
+ __param(0, Optional()),
1458
+ __param(0, Self())
1459
+ ], FxComponent);
1460
+
1461
+ class CheckboxComponent extends FxComponent {
1462
+ ref;
1463
+ label = '';
1464
+ disabled = false;
1465
+ rounded = true;
1466
+ size = 'normal';
1467
+ valueChange = new EventEmitter();
1468
+ constructor(ngControl, ref) {
1469
+ super(ngControl);
1470
+ this.ref = ref;
1471
+ }
1472
+ ngAfterViewInit() {
1473
+ this.ref.detectChanges();
1474
+ }
1475
+ setDisabledState(isDisabled) {
1476
+ this.disabled = isDisabled;
1477
+ }
1478
+ onInputChange(event) {
1479
+ const checked = event.target.checked;
1480
+ this.value = checked;
1481
+ this.onChange(checked);
1482
+ this.valueChange.emit(checked);
1483
+ }
1484
+ markTouched() {
1485
+ this.onTouched();
1486
+ }
1487
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CheckboxComponent, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1488
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: CheckboxComponent, isStandalone: false, selector: "fx-ui-checkbox", inputs: { label: "label", disabled: "disabled", rounded: "rounded", size: "size" }, outputs: { valueChange: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<label\n class=\"inline-flex items-center gap-normal cursor-pointer select-none\"\n [class.opacity-50]=\"disabled\"\n [class.cursor-not-allowed]=\"disabled\"\n>\n <input\n type=\"checkbox\"\n class=\"hidden\"\n [checked]=\"value\"\n [disabled]=\"disabled\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onTouched()\"\n />\n <span\n class=\"relative flex items-center justify-center border rounded-full transition-colors duration-150 shrink-0\"\n [class]=\"rounded ? 'rounded-full' : 'rounded-sm'\"\n [class]=\"size === 'large' ? 'w-6 h-6' : 'w-4 h-4'\"\n [ngClass]=\"{\n 'border-border-strong bg-transparent': !value,\n 'border-border-selected bg-border-selected': value\n }\"\n >\n <!-- Keep SVG space reserved always -->\n <span class=\"absolute inset-0 flex items-center justify-center\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"text-bg-primary transition-opacity duration-150\"\n [class]=\"size === 'large' ? 'w-4.5 h-4.5' : 'w-3 h-3'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n [style.opacity]=\"value ? 1 : 0\"\n >\n <path d=\"M5 13l4 4L19 7\" />\n </svg>\n </span>\n </span>\n\n <span class=\"mb-0 txt-field-label\">{{ label }}</span>\n</label>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1489
+ }
1490
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CheckboxComponent, decorators: [{
1491
+ type: Component,
1492
+ args: [{ selector: 'fx-ui-checkbox', standalone: false, template: "<label\n class=\"inline-flex items-center gap-normal cursor-pointer select-none\"\n [class.opacity-50]=\"disabled\"\n [class.cursor-not-allowed]=\"disabled\"\n>\n <input\n type=\"checkbox\"\n class=\"hidden\"\n [checked]=\"value\"\n [disabled]=\"disabled\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onTouched()\"\n />\n <span\n class=\"relative flex items-center justify-center border rounded-full transition-colors duration-150 shrink-0\"\n [class]=\"rounded ? 'rounded-full' : 'rounded-sm'\"\n [class]=\"size === 'large' ? 'w-6 h-6' : 'w-4 h-4'\"\n [ngClass]=\"{\n 'border-border-strong bg-transparent': !value,\n 'border-border-selected bg-border-selected': value\n }\"\n >\n <!-- Keep SVG space reserved always -->\n <span class=\"absolute inset-0 flex items-center justify-center\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"text-bg-primary transition-opacity duration-150\"\n [class]=\"size === 'large' ? 'w-4.5 h-4.5' : 'w-3 h-3'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n [style.opacity]=\"value ? 1 : 0\"\n >\n <path d=\"M5 13l4 4L19 7\" />\n </svg>\n </span>\n </span>\n\n <span class=\"mb-0 txt-field-label\">{{ label }}</span>\n</label>\n" }]
1493
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { label: [{
1494
+ type: Input
1495
+ }], disabled: [{
1496
+ type: Input
1497
+ }], rounded: [{
1498
+ type: Input
1499
+ }], size: [{
1500
+ type: Input
1501
+ }], valueChange: [{
1502
+ type: Output
1503
+ }] } });
1504
+
1505
+ class DatetimePicker extends FxComponent {
1506
+ ref;
1507
+ label;
1508
+ placeholder = 'Select date and time';
1509
+ required = false;
1510
+ showTime = true;
1511
+ format = 'YYYY-MM-DD HH:mm:ss';
1512
+ disabled = false;
1513
+ errorMessages = {};
1514
+ validateFn;
1515
+ constructor(ngControl, ref) {
1516
+ super(ngControl);
1517
+ this.ref = ref;
1518
+ }
1519
+ ngAfterViewInit() {
1520
+ setTimeout(() => {
1521
+ this.ref.detectChanges();
1522
+ });
1523
+ }
1524
+ setDisabledState(isDisabled) {
1525
+ this.disabled = isDisabled;
1526
+ }
1527
+ onBlur() {
1528
+ this.onTouched();
1529
+ this.validate(this.validateFn);
1530
+ }
1531
+ writeValue(value) {
1532
+ this.value = value ?? '';
1533
+ this.ref.markForCheck();
1534
+ }
1535
+ onValueChange(date) {
1536
+ if (this.disabled)
1537
+ return;
1538
+ this.value = date;
1539
+ this.onChange(date);
1540
+ this.onTouched();
1541
+ }
1542
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DatetimePicker, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1543
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: DatetimePicker, isStandalone: false, selector: "fx-ui-datetime-picker", inputs: { label: "label", placeholder: "placeholder", required: "required", showTime: "showTime", format: "format", disabled: "disabled", errorMessages: "errorMessages", validateFn: "validateFn" }, usesInheritance: true, ngImport: i0, template: "<div class=\"flex flex-col mb-4 w-full text-left\">\n <label *ngIf=\"label\" class=\"txt-field-label\">\n {{ label }}\n <span *ngIf=\"required\" class=\"txt-required\">*</span>\n </label>\n\n <div class=\"relative\">\n <input\n [owlDateTimeTrigger]=\"picker\"\n [owlDateTime]=\"picker\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n (blur)=\"onBlur()\"\n [value]=\"value\"\n readonly\n class=\"input-default\"\n />\n </div>\n <owl-date-time\n #picker\n [pickerType]=\"showTime ? 'both' : 'calendar'\"\n (afterPickerClosed)=\"onValueChange($event)\"\n ></owl-date-time>\n <div *ngIf=\"invalid\" class=\"txt-invalid\">{{ getErrorMessage(label) }}</div>\n</div>\n", styles: ["::ng-deep .owl-dt-container{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(var(--shadow-color) / .1), 0 10px 10px -5px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 10px 10px -5px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);width:320px!important}::ng-deep .owl-dt-calendar-table{width:100%;border-collapse:collapse}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell{border-radius:.375rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(var(--text-secondary) / var(--tw-text-opacity, 1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell:hover{background-color:#ef444433}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-selected{--tw-bg-opacity: 1;background-color:rgb(var(--border-selected) / var(--tw-bg-opacity, 1));font-weight:400;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-cell-today:not(.owl-dt-calendar-cell-selected){border-radius:.375rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-selected) / var(--tw-border-opacity, 1))}::ng-deep .owl-dt-timer-content .owl-dt-timer-input{border-radius:.5rem;--tw-border-opacity: 1;border-color:rgb(var(--border-strong) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-control-period-button .owl-dt-control-button-arrow{display:none}:ng-deep .owl-dt-container-buttons button{height:2.25rem;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));padding-top:1rem;padding-bottom:1rem}::ng-deep .owl-dt-container-control-button .owl-dt-control-button-content{margin-bottom:1rem;--tw-text-opacity: 1;color:rgb(var(--primary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-control-content .owl-dt-control-button-content{--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-control-arrow-button .owl-dt-control-button-content{--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-header{margin-bottom:.5rem;text-align:center;font-size:.875rem;line-height:1.25rem;font-weight:600;--tw-text-opacity: 1;color:rgb(var(--text-secondary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-table th{font-size:.75rem;line-height:1rem;font-weight:500;--tw-text-opacity: 1;color:rgb(var(--text-secondary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-inline-container,::ng-deep .owl-dt-popup-container{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-strong) / var(--tw-border-opacity, 1));--tw-shadow: 0 10px 15px -3px rgb(var(--shadow-color) / .1), 0 4px 6px -4px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.OwlDateTimeTriggerDirective, selector: "[owlDateTimeTrigger]", inputs: ["owlDateTimeTrigger", "disabled"] }, { kind: "directive", type: i3.OwlDateTimeInputDirective, selector: "input[owlDateTime]", inputs: ["required", "owlDateTime", "owlDateTimeFilter", "_disabled", "min", "max", "selectMode", "rangeSeparator", "value", "values"], outputs: ["dateTimeChange", "dateTimeInput"], exportAs: ["owlDateTimeInput"] }, { kind: "component", type: i3.OwlDateTimeComponent, selector: "owl-date-time", inputs: ["backdropClass", "panelClass", "startAt", "endAt", "pickerType", "pickerMode", "disabled", "opened", "scrollStrategy"], outputs: ["afterPickerClosed", "beforePickerOpen", "afterPickerOpen", "yearSelected", "monthSelected", "dateSelected"], exportAs: ["owlDateTime"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1544
+ }
1545
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DatetimePicker, decorators: [{
1546
+ type: Component,
1547
+ args: [{ selector: 'fx-ui-datetime-picker', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col mb-4 w-full text-left\">\n <label *ngIf=\"label\" class=\"txt-field-label\">\n {{ label }}\n <span *ngIf=\"required\" class=\"txt-required\">*</span>\n </label>\n\n <div class=\"relative\">\n <input\n [owlDateTimeTrigger]=\"picker\"\n [owlDateTime]=\"picker\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n (blur)=\"onBlur()\"\n [value]=\"value\"\n readonly\n class=\"input-default\"\n />\n </div>\n <owl-date-time\n #picker\n [pickerType]=\"showTime ? 'both' : 'calendar'\"\n (afterPickerClosed)=\"onValueChange($event)\"\n ></owl-date-time>\n <div *ngIf=\"invalid\" class=\"txt-invalid\">{{ getErrorMessage(label) }}</div>\n</div>\n", styles: ["::ng-deep .owl-dt-container{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(var(--shadow-color) / .1), 0 10px 10px -5px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 10px 10px -5px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);width:320px!important}::ng-deep .owl-dt-calendar-table{width:100%;border-collapse:collapse}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell{border-radius:.375rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(var(--text-secondary) / var(--tw-text-opacity, 1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell:hover{background-color:#ef444433}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-selected{--tw-bg-opacity: 1;background-color:rgb(var(--border-selected) / var(--tw-bg-opacity, 1));font-weight:400;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-cell-today:not(.owl-dt-calendar-cell-selected){border-radius:.375rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-selected) / var(--tw-border-opacity, 1))}::ng-deep .owl-dt-timer-content .owl-dt-timer-input{border-radius:.5rem;--tw-border-opacity: 1;border-color:rgb(var(--border-strong) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-control-period-button .owl-dt-control-button-arrow{display:none}:ng-deep .owl-dt-container-buttons button{height:2.25rem;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));padding-top:1rem;padding-bottom:1rem}::ng-deep .owl-dt-container-control-button .owl-dt-control-button-content{margin-bottom:1rem;--tw-text-opacity: 1;color:rgb(var(--primary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-control-content .owl-dt-control-button-content{--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-control-arrow-button .owl-dt-control-button-content{--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-header{margin-bottom:.5rem;text-align:center;font-size:.875rem;line-height:1.25rem;font-weight:600;--tw-text-opacity: 1;color:rgb(var(--text-secondary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-table th{font-size:.75rem;line-height:1rem;font-weight:500;--tw-text-opacity: 1;color:rgb(var(--text-secondary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-inline-container,::ng-deep .owl-dt-popup-container{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-strong) / var(--tw-border-opacity, 1));--tw-shadow: 0 10px 15px -3px rgb(var(--shadow-color) / .1), 0 4px 6px -4px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}\n"] }]
1548
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { label: [{
1549
+ type: Input
1550
+ }], placeholder: [{
1551
+ type: Input
1552
+ }], required: [{
1553
+ type: Input
1554
+ }], showTime: [{
1555
+ type: Input
1556
+ }], format: [{
1557
+ type: Input
1558
+ }], disabled: [{
1559
+ type: Input
1560
+ }], errorMessages: [{
1561
+ type: Input
1562
+ }], validateFn: [{
1563
+ type: Input
1564
+ }] } });
1565
+
1566
+ class DndUploadComponent {
1567
+ multiple = false;
1568
+ accept = '';
1569
+ maxSizeMB = 10;
1570
+ strictSize = true;
1571
+ fileDrop = new EventEmitter();
1572
+ fileClick = new EventEmitter();
1573
+ uploadComplete = new EventEmitter();
1574
+ uploadError = new EventEmitter();
1575
+ isDragOver = false;
1576
+ isOpening = false;
1577
+ onDragOver(event) {
1578
+ event.preventDefault();
1579
+ this.isDragOver = true;
1580
+ }
1581
+ onDragLeave(event) {
1582
+ event.preventDefault();
1583
+ this.isDragOver = false;
1584
+ }
1585
+ onDrop(event) {
1586
+ event.preventDefault();
1587
+ this.isDragOver = false;
1588
+ if (!event.dataTransfer?.files?.length)
1589
+ return;
1590
+ const files = Array.from(event.dataTransfer.files);
1591
+ this.processFiles(files);
1592
+ }
1593
+ onAreaClick(inputEl, event) {
1594
+ if (this.isOpening)
1595
+ return;
1596
+ this.isOpening = true;
1597
+ this.fileClick.emit();
1598
+ event?.currentTarget?.blur?.();
1599
+ setTimeout(() => {
1600
+ inputEl?.click();
1601
+ this.isOpening = false;
1602
+ }, 0);
1603
+ }
1604
+ onFileSelected(event) {
1605
+ const input = event.target;
1606
+ if (!input.files?.length)
1607
+ return;
1608
+ const files = Array.from(input.files);
1609
+ this.processFiles(files);
1610
+ input.value = ''; // allow reselect same file
1611
+ }
1612
+ processFiles(files) {
1613
+ const valid = [];
1614
+ for (const file of files) {
1615
+ const sizeMB = file.size / 1024 / 1024;
1616
+ if (this.strictSize && sizeMB > this.maxSizeMB) {
1617
+ this.uploadError.emit({
1618
+ file,
1619
+ reason: `File too large: ${(sizeMB).toFixed(2)} MB > ${this.maxSizeMB} MB`,
1620
+ });
1621
+ continue;
1622
+ }
1623
+ valid.push(file);
1624
+ }
1625
+ if (valid.length) {
1626
+ this.fileDrop.emit(valid);
1627
+ this.onUpload(valid);
1628
+ }
1629
+ }
1630
+ onUpload(files) {
1631
+ console.log('Uploading files:', files);
1632
+ this.uploadComplete.emit(files);
1633
+ }
1634
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DndUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1635
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: DndUploadComponent, isStandalone: false, selector: "fx-ui-dnd-upload", inputs: { multiple: "multiple", accept: "accept", maxSizeMB: "maxSizeMB", strictSize: "strictSize" }, outputs: { fileDrop: "fileDrop", fileClick: "fileClick", uploadComplete: "uploadComplete", uploadError: "uploadError" }, ngImport: i0, template: "<div\n class=\"block w-full\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"flex flex-col items-center justify-center gap-1 border-2 border-dashed rounded-md p-4 cursor-pointer select-none outline-none focus:ring-2 focus:ring-primary\"\n [ngClass]=\"{\n 'border-border-default bg-bg-hover': !isDragOver,\n 'border-border-interactive bg-secondary': isDragOver\n }\"\n (click)=\"onAreaClick(fileInput, $event)\"\n (keydown.enter)=\"onAreaClick(fileInput, $event)\"\n >\n <div class=\"text-sm text-text-link font-medium\">\n Click to upload <span class=\"text-text-secondary opacity-50\">or drag and drop</span>\n </div>\n <div class=\"text-xs text-text-secondary\">\n Allowed: {{ accept || 'any file type' }} (max {{ maxSizeMB }} MB)\n </div>\n\n <input\n #fileInput\n type=\"file\"\n class=\"hidden\"\n [attr.multiple]=\"multiple ? '' : null\"\n [attr.accept]=\"accept\"\n (change)=\"onFileSelected($event)\"\n />\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1636
+ }
1637
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DndUploadComponent, decorators: [{
1638
+ type: Component,
1639
+ args: [{ selector: 'fx-ui-dnd-upload', standalone: false, template: "<div\n class=\"block w-full\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"flex flex-col items-center justify-center gap-1 border-2 border-dashed rounded-md p-4 cursor-pointer select-none outline-none focus:ring-2 focus:ring-primary\"\n [ngClass]=\"{\n 'border-border-default bg-bg-hover': !isDragOver,\n 'border-border-interactive bg-secondary': isDragOver\n }\"\n (click)=\"onAreaClick(fileInput, $event)\"\n (keydown.enter)=\"onAreaClick(fileInput, $event)\"\n >\n <div class=\"text-sm text-text-link font-medium\">\n Click to upload <span class=\"text-text-secondary opacity-50\">or drag and drop</span>\n </div>\n <div class=\"text-xs text-text-secondary\">\n Allowed: {{ accept || 'any file type' }} (max {{ maxSizeMB }} MB)\n </div>\n\n <input\n #fileInput\n type=\"file\"\n class=\"hidden\"\n [attr.multiple]=\"multiple ? '' : null\"\n [attr.accept]=\"accept\"\n (change)=\"onFileSelected($event)\"\n />\n </div>\n</div>\n" }]
1640
+ }], propDecorators: { multiple: [{
1641
+ type: Input
1642
+ }], accept: [{
1643
+ type: Input
1644
+ }], maxSizeMB: [{
1645
+ type: Input
1646
+ }], strictSize: [{
1647
+ type: Input
1648
+ }], fileDrop: [{
1649
+ type: Output
1650
+ }], fileClick: [{
1651
+ type: Output
1652
+ }], uploadComplete: [{
1653
+ type: Output
1654
+ }], uploadError: [{
1655
+ type: Output
1656
+ }] } });
1657
+
1658
+ class InputComponent extends FxComponent {
1659
+ ref;
1660
+ label = '';
1661
+ type = 'text';
1662
+ placeholder = '';
1663
+ errorMessages = {};
1664
+ required = false;
1665
+ disabled = false;
1666
+ iconClass = 'material-symbols-outlined';
1667
+ suffixIcon;
1668
+ class;
1669
+ maxlength;
1670
+ validateFn;
1671
+ blurred = new EventEmitter();
1672
+ focused = new EventEmitter();
1673
+ suffixClick = new EventEmitter();
1674
+ showPassword = false;
1675
+ validateError = null;
1676
+ constructor(ngControl, ref) {
1677
+ super(ngControl);
1678
+ this.ref = ref;
1679
+ }
1680
+ ngAfterViewInit() {
1681
+ this.ref.detectChanges();
1682
+ }
1683
+ setDisabledState(isDisabled) {
1684
+ this.disabled = isDisabled;
1685
+ }
1686
+ onInput(event) {
1687
+ const input = event.target;
1688
+ let newValue = input.value;
1689
+ if (this.maxlength && newValue.length > this.maxlength) {
1690
+ newValue = newValue.slice(0, this.maxlength);
1691
+ input.value = newValue;
1692
+ }
1693
+ this.value = newValue;
1694
+ this.onChange(this.value);
1695
+ }
1696
+ onFocus() {
1697
+ this.clearErrors();
1698
+ this.focused.emit();
1699
+ }
1700
+ onBlur() {
1701
+ this.onTouched();
1702
+ this.blurred.emit();
1703
+ if (this.validateFn) {
1704
+ this.validateError = this.validateFn(this.value);
1705
+ this.validate(this.validateFn);
1706
+ }
1707
+ }
1708
+ togglePassword() {
1709
+ this.showPassword = !this.showPassword;
1710
+ }
1711
+ onSuffixClick() {
1712
+ if (this.type === 'password') {
1713
+ this.togglePassword();
1714
+ }
1715
+ else {
1716
+ this.suffixClick.emit();
1717
+ }
1718
+ }
1719
+ get displayType() {
1720
+ if (this.type === 'password' && this.showPassword)
1721
+ return 'text';
1722
+ if (this.type === 'otp')
1723
+ return 'number';
1724
+ return this.type;
1725
+ }
1726
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InputComponent, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1727
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: InputComponent, isStandalone: false, selector: "fx-ui-input", inputs: { label: "label", type: "type", placeholder: "placeholder", errorMessages: "errorMessages", required: "required", disabled: "disabled", iconClass: "iconClass", suffixIcon: "suffixIcon", class: "class", maxlength: "maxlength", validateFn: "validateFn" }, outputs: { blurred: "blurred", focused: "focused", suffixClick: "suffixClick" }, usesInheritance: true, ngImport: i0, template: "<div class=\"mb-4 text-left w-full text-text-primary\" [class]=\"class\">\n @if(label){<label class=\"block txt-field-label\">\n {{ label }}\n @if (required) {<span class=\"txt-required\">*</span>}\n </label>\n }\n\n <div class=\"relative\">\n <input\n [type]=\"displayType\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n [attr.maxlength]=\"maxlength\"\n [class]=\"type === 'otp' ? 'input-otp' : 'input-default'\"\n [ngClass]=\"{\n 'input-invalid': invalid,\n 'pr-8': type === 'password' || suffixIcon,\n 'txt-otp-input': type === 'otp'\n }\"\n />\n <button\n type=\"button\"\n class=\"absolute inset-y-0 right-2 flex items-center text-text-primary hover:text-text-secondary\"\n (click)=\"onSuffixClick()\"\n [disabled]=\"disabled\"\n >\n @if (type === 'password') {\n <i class=\"material-symbols-outlined text-lg select-none\">{{\n showPassword ? 'visibility_off' : 'visibility'\n }}</i>\n } @else if (suffixIcon) {\n <i [class]=\"iconClass\" class=\"text-lg select-none\">{{ suffixIcon }}</i>\n }\n </button>\n </div>\n\n @if (invalid){\n <div class=\"txt-invalid\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1728
+ }
1729
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InputComponent, decorators: [{
1730
+ type: Component,
1731
+ args: [{ selector: 'fx-ui-input', standalone: false, template: "<div class=\"mb-4 text-left w-full text-text-primary\" [class]=\"class\">\n @if(label){<label class=\"block txt-field-label\">\n {{ label }}\n @if (required) {<span class=\"txt-required\">*</span>}\n </label>\n }\n\n <div class=\"relative\">\n <input\n [type]=\"displayType\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n [attr.maxlength]=\"maxlength\"\n [class]=\"type === 'otp' ? 'input-otp' : 'input-default'\"\n [ngClass]=\"{\n 'input-invalid': invalid,\n 'pr-8': type === 'password' || suffixIcon,\n 'txt-otp-input': type === 'otp'\n }\"\n />\n <button\n type=\"button\"\n class=\"absolute inset-y-0 right-2 flex items-center text-text-primary hover:text-text-secondary\"\n (click)=\"onSuffixClick()\"\n [disabled]=\"disabled\"\n >\n @if (type === 'password') {\n <i class=\"material-symbols-outlined text-lg select-none\">{{\n showPassword ? 'visibility_off' : 'visibility'\n }}</i>\n } @else if (suffixIcon) {\n <i [class]=\"iconClass\" class=\"text-lg select-none\">{{ suffixIcon }}</i>\n }\n </button>\n </div>\n\n @if (invalid){\n <div class=\"txt-invalid\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n" }]
1732
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { label: [{
1733
+ type: Input
1734
+ }], type: [{
1735
+ type: Input
1736
+ }], placeholder: [{
1737
+ type: Input
1738
+ }], errorMessages: [{
1739
+ type: Input
1740
+ }], required: [{
1741
+ type: Input
1742
+ }], disabled: [{
1743
+ type: Input
1744
+ }], iconClass: [{
1745
+ type: Input
1746
+ }], suffixIcon: [{
1747
+ type: Input
1748
+ }], class: [{
1749
+ type: Input
1750
+ }], maxlength: [{
1751
+ type: Input
1752
+ }], validateFn: [{
1753
+ type: Input
1754
+ }], blurred: [{
1755
+ type: Output
1756
+ }], focused: [{
1757
+ type: Output
1758
+ }], suffixClick: [{
1759
+ type: Output
1760
+ }] } });
1761
+
1762
+ class LoadingPanel {
1763
+ show = false;
1764
+ message = "Loading";
1765
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LoadingPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
1766
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: LoadingPanel, isStandalone: false, selector: "fx-ui-loading-panel", inputs: { show: "show", message: "message" }, ngImport: i0, template: "<!-- Full-screen glass overlay -->\n<div\n *ngIf=\"show\"\n class=\"fixed inset-0 z-50 flex items-center justify-center\"\n aria-hidden=\"false\"\n role=\"alert\"\n aria-busy=\"true\"\n>\n <div class=\"absolute inset-0 bg-bg-primary/30 backdrop-blur-xl\" aria-hidden=\"true\"></div>\n\n <div\n class=\"relative z-10 flex flex-col items-center gap-4 p-6 rounded-2xl shadow-xl bg-bg-primary/70 border border-border-strong backdrop-bg-primary/70\"\n style=\"min-width: 220px; max-width: 90%\"\n >\n <svg fill=\"rgb(var(--primary))\" width=\"50\" height=\"50\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"4\" cy=\"12\" r=\"0\">\n <animate begin=\"0;spinner_z0Or.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"0;3\" fill=\"freeze\"/>\n <animate begin=\"spinner_OLMs.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"4;12\" fill=\"freeze\"/>\n <animate begin=\"spinner_UHR2.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"12;20\" fill=\"freeze\"/>\n <animate id=\"spinner_lo66\" begin=\"spinner_Aguh.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"3;0\" fill=\"freeze\"/>\n <animate id=\"spinner_z0Or\" begin=\"spinner_lo66.end\" attributeName=\"cx\" dur=\"0.001s\" values=\"20;4\" fill=\"freeze\"/>\n </circle>\n <circle cx=\"4\" cy=\"12\" r=\"3\">\n <animate begin=\"0;spinner_z0Or.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"4;12\" fill=\"freeze\"/>\n <animate begin=\"spinner_OLMs.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"12;20\" fill=\"freeze\"/>\n <animate id=\"spinner_JsnR\" begin=\"spinner_UHR2.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"3;0\" fill=\"freeze\"/>\n <animate id=\"spinner_Aguh\" begin=\"spinner_JsnR.end\" attributeName=\"cx\" dur=\"0.001s\" values=\"20;4\" fill=\"freeze\"/>\n <animate begin=\"spinner_Aguh.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"0;3\" fill=\"freeze\"/>\n </circle>\n <circle cx=\"12\" cy=\"12\" r=\"3\">\n <animate begin=\"0;spinner_z0Or.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"12;20\" fill=\"freeze\"/>\n <animate id=\"spinner_hSjk\" begin=\"spinner_OLMs.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"3;0\" fill=\"freeze\"/>\n <animate id=\"spinner_UHR2\" begin=\"spinner_hSjk.end\" attributeName=\"cx\" dur=\"0.001s\" values=\"20;4\" fill=\"freeze\"/>\n <animate begin=\"spinner_UHR2.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"0;3\" fill=\"freeze\"/>\n <animate begin=\"spinner_Aguh.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"4;12\" fill=\"freeze\"/>\n </circle>\n <circle cx=\"20\" cy=\"12\" r=\"3\">\n <animate id=\"spinner_4v5M\" begin=\"0;spinner_z0Or.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"3;0\" fill=\"freeze\"/>\n <animate id=\"spinner_OLMs\" begin=\"spinner_4v5M.end\" attributeName=\"cx\" dur=\"0.001s\" values=\"20;4\" fill=\"freeze\"/>\n <animate begin=\"spinner_OLMs.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"0;3\" fill=\"freeze\"/>\n <animate begin=\"spinner_UHR2.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"4;12\" fill=\"freeze\"/>\n <animate begin=\"spinner_Aguh.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"12;20\" fill=\"freeze\"/>\n </circle>\n </svg>\n \n\n <div *ngIf=\"message\" class=\"text-sm text-text-primary text-center\">\n {{ message }}\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
1767
+ }
1768
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LoadingPanel, decorators: [{
1769
+ type: Component,
1770
+ args: [{ selector: 'fx-ui-loading-panel', standalone: false, template: "<!-- Full-screen glass overlay -->\n<div\n *ngIf=\"show\"\n class=\"fixed inset-0 z-50 flex items-center justify-center\"\n aria-hidden=\"false\"\n role=\"alert\"\n aria-busy=\"true\"\n>\n <div class=\"absolute inset-0 bg-bg-primary/30 backdrop-blur-xl\" aria-hidden=\"true\"></div>\n\n <div\n class=\"relative z-10 flex flex-col items-center gap-4 p-6 rounded-2xl shadow-xl bg-bg-primary/70 border border-border-strong backdrop-bg-primary/70\"\n style=\"min-width: 220px; max-width: 90%\"\n >\n <svg fill=\"rgb(var(--primary))\" width=\"50\" height=\"50\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"4\" cy=\"12\" r=\"0\">\n <animate begin=\"0;spinner_z0Or.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"0;3\" fill=\"freeze\"/>\n <animate begin=\"spinner_OLMs.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"4;12\" fill=\"freeze\"/>\n <animate begin=\"spinner_UHR2.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"12;20\" fill=\"freeze\"/>\n <animate id=\"spinner_lo66\" begin=\"spinner_Aguh.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"3;0\" fill=\"freeze\"/>\n <animate id=\"spinner_z0Or\" begin=\"spinner_lo66.end\" attributeName=\"cx\" dur=\"0.001s\" values=\"20;4\" fill=\"freeze\"/>\n </circle>\n <circle cx=\"4\" cy=\"12\" r=\"3\">\n <animate begin=\"0;spinner_z0Or.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"4;12\" fill=\"freeze\"/>\n <animate begin=\"spinner_OLMs.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"12;20\" fill=\"freeze\"/>\n <animate id=\"spinner_JsnR\" begin=\"spinner_UHR2.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"3;0\" fill=\"freeze\"/>\n <animate id=\"spinner_Aguh\" begin=\"spinner_JsnR.end\" attributeName=\"cx\" dur=\"0.001s\" values=\"20;4\" fill=\"freeze\"/>\n <animate begin=\"spinner_Aguh.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"0;3\" fill=\"freeze\"/>\n </circle>\n <circle cx=\"12\" cy=\"12\" r=\"3\">\n <animate begin=\"0;spinner_z0Or.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"12;20\" fill=\"freeze\"/>\n <animate id=\"spinner_hSjk\" begin=\"spinner_OLMs.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"3;0\" fill=\"freeze\"/>\n <animate id=\"spinner_UHR2\" begin=\"spinner_hSjk.end\" attributeName=\"cx\" dur=\"0.001s\" values=\"20;4\" fill=\"freeze\"/>\n <animate begin=\"spinner_UHR2.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"0;3\" fill=\"freeze\"/>\n <animate begin=\"spinner_Aguh.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"4;12\" fill=\"freeze\"/>\n </circle>\n <circle cx=\"20\" cy=\"12\" r=\"3\">\n <animate id=\"spinner_4v5M\" begin=\"0;spinner_z0Or.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"3;0\" fill=\"freeze\"/>\n <animate id=\"spinner_OLMs\" begin=\"spinner_4v5M.end\" attributeName=\"cx\" dur=\"0.001s\" values=\"20;4\" fill=\"freeze\"/>\n <animate begin=\"spinner_OLMs.end\" attributeName=\"r\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"0;3\" fill=\"freeze\"/>\n <animate begin=\"spinner_UHR2.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"4;12\" fill=\"freeze\"/>\n <animate begin=\"spinner_Aguh.end\" attributeName=\"cx\" calcMode=\"spline\" dur=\"0.5s\" keySplines=\".36,.6,.31,1\" values=\"12;20\" fill=\"freeze\"/>\n </circle>\n </svg>\n \n\n <div *ngIf=\"message\" class=\"text-sm text-text-primary text-center\">\n {{ message }}\n </div>\n </div>\n</div>\n" }]
1771
+ }], propDecorators: { show: [{
1772
+ type: Input
1773
+ }], message: [{
1774
+ type: Input
1775
+ }] } });
1776
+
1777
+ class RadioButtonToggleComponent extends FxComponent {
1778
+ ref;
1779
+ label;
1780
+ required = false;
1781
+ options = [];
1782
+ disabled = false;
1783
+ errorMessages = {};
1784
+ class;
1785
+ constructor(ngControl, ref) {
1786
+ super(ngControl);
1787
+ this.ref = ref;
1788
+ }
1789
+ ngAfterViewInit() {
1790
+ this.ref.detectChanges();
1791
+ }
1792
+ setDisabledState(isDisabled) {
1793
+ this.disabled = isDisabled;
1794
+ }
1795
+ onSelectValue(value) {
1796
+ if (this.disabled)
1797
+ return;
1798
+ this.value = value;
1799
+ this.onChange(value);
1800
+ this.onTouched();
1801
+ }
1802
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonToggleComponent, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1803
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RadioButtonToggleComponent, isStandalone: false, selector: "fx-ui-radio-toggle, [fx-ui-radio-toggle]", inputs: { label: "label", required: "required", options: "options", disabled: "disabled", errorMessages: "errorMessages", class: "class" }, usesInheritance: true, ngImport: i0, template: "<div class=\"flex flex-col text-left mb-4 w-full\" [class]=\"class\">\n @if(label){<label class=\"txt-field-label\">\n {{ label }}\n @if(required) {<span class=\"txt-required\">*</span>} </label\n >}\n\n <div class=\"inline-flex w-full rounded-lg overflow-hidden\" role=\"radiogroup\">\n @for(opt of options; track opt){<button\n type=\"button\"\n role=\"radio\"\n [attr.aria-checked]=\"value === opt.value\"\n (click)=\"onSelectValue(opt.value)\"\n [disabled]=\"disabled\"\n [class.text-gray-900]=\"value !== opt.value\"\n class=\"flex-1 bg-bg-primary flex items-center pl-normal gap-normal h-10 rounded-md hover:bg-bg-hover transition-all duration-150 disabled:opacity-60 disabled:cursor-not-allowed\"\n >\n <span\n [ngClass]=\"{\n 'radio-checked': value === opt.value,\n 'radio-uncheck': value !== opt.value\n }\"\n class=\"radio-container\"\n >\n @if(value === opt.value) {<span class=\"radio-dot\"></span>}\n </span>\n\n <span class=\"txt-field-label mb-0\">{{ opt.label }}</span></button\n >}\n </div>\n\n @if(invalid){\n <div class=\"txt-invalid\">{{ getErrorMessage(label) }}</div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1804
+ }
1805
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonToggleComponent, decorators: [{
1806
+ type: Component,
1807
+ args: [{ selector: 'fx-ui-radio-toggle, [fx-ui-radio-toggle]', standalone: false, template: "<div class=\"flex flex-col text-left mb-4 w-full\" [class]=\"class\">\n @if(label){<label class=\"txt-field-label\">\n {{ label }}\n @if(required) {<span class=\"txt-required\">*</span>} </label\n >}\n\n <div class=\"inline-flex w-full rounded-lg overflow-hidden\" role=\"radiogroup\">\n @for(opt of options; track opt){<button\n type=\"button\"\n role=\"radio\"\n [attr.aria-checked]=\"value === opt.value\"\n (click)=\"onSelectValue(opt.value)\"\n [disabled]=\"disabled\"\n [class.text-gray-900]=\"value !== opt.value\"\n class=\"flex-1 bg-bg-primary flex items-center pl-normal gap-normal h-10 rounded-md hover:bg-bg-hover transition-all duration-150 disabled:opacity-60 disabled:cursor-not-allowed\"\n >\n <span\n [ngClass]=\"{\n 'radio-checked': value === opt.value,\n 'radio-uncheck': value !== opt.value\n }\"\n class=\"radio-container\"\n >\n @if(value === opt.value) {<span class=\"radio-dot\"></span>}\n </span>\n\n <span class=\"txt-field-label mb-0\">{{ opt.label }}</span></button\n >}\n </div>\n\n @if(invalid){\n <div class=\"txt-invalid\">{{ getErrorMessage(label) }}</div>\n }\n</div>\n" }]
1808
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { label: [{
1809
+ type: Input
1810
+ }], required: [{
1811
+ type: Input
1812
+ }], options: [{
1813
+ type: Input
1814
+ }], disabled: [{
1815
+ type: Input
1816
+ }], errorMessages: [{
1817
+ type: Input
1818
+ }], class: [{
1819
+ type: Input
1820
+ }] } });
1821
+
1822
+ class RadioButtonComponent extends FxComponent {
1823
+ ref;
1824
+ label;
1825
+ required = false;
1826
+ options = [];
1827
+ disabled = false;
1828
+ errorMessages = {};
1829
+ class;
1830
+ constructor(ngControl, ref) {
1831
+ super(ngControl);
1832
+ this.ref = ref;
1833
+ }
1834
+ ngAfterViewInit() {
1835
+ this.ref.detectChanges();
1836
+ }
1837
+ setDisabledState(isDisabled) {
1838
+ this.disabled = isDisabled;
1839
+ }
1840
+ onSelectValue(value) {
1841
+ if (this.disabled)
1842
+ return;
1843
+ this.value = value;
1844
+ this.onChange(value);
1845
+ this.onTouched();
1846
+ }
1847
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonComponent, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1848
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RadioButtonComponent, isStandalone: false, selector: "fx-ui-radio", inputs: { label: "label", required: "required", options: "options", disabled: "disabled", errorMessages: "errorMessages", class: "class" }, usesInheritance: true, ngImport: i0, template: "<div class=\"w-full rounded-lg overflow-hidden\" [class]=\"class\" role=\"radiogroup\">\n @if (label){\n <label class=\"txt-field-label\">\n {{ label }}\n @if(required){<span class=\"txt-required\">*</span>} </label\n >}\n\n <button\n *ngFor=\"let opt of options\"\n type=\"button\"\n role=\"radio\"\n [attr.aria-checked]=\"value === opt.value\"\n (click)=\"onSelectValue(opt.value)\"\n [disabled]=\"disabled\"\n [class.text-gray-900]=\"value !== opt.value\"\n class=\"flex-1 px-normal w-full flex items-center gap-normal h-10 rounded-md hover:bg-bg-hover transition-all duration-150 disabled:opacity-60 disabled:cursor-not-allowed\"\n >\n <span\n [ngClass]=\"{\n 'radio-checked': value === opt.value,\n 'radio-uncheck': value !== opt.value\n }\"\n class=\"radio-container\"\n >\n @if(value === opt.value) {<span class=\"radio-dot\"></span>}\n </span>\n\n <span class=\"txt-default mb-0\">{{ opt.label }}</span>\n </button>\n @if (invalid){\n <div class=\"txt-invalid\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
1849
+ }
1850
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonComponent, decorators: [{
1851
+ type: Component,
1852
+ args: [{ selector: 'fx-ui-radio', standalone: false, template: "<div class=\"w-full rounded-lg overflow-hidden\" [class]=\"class\" role=\"radiogroup\">\n @if (label){\n <label class=\"txt-field-label\">\n {{ label }}\n @if(required){<span class=\"txt-required\">*</span>} </label\n >}\n\n <button\n *ngFor=\"let opt of options\"\n type=\"button\"\n role=\"radio\"\n [attr.aria-checked]=\"value === opt.value\"\n (click)=\"onSelectValue(opt.value)\"\n [disabled]=\"disabled\"\n [class.text-gray-900]=\"value !== opt.value\"\n class=\"flex-1 px-normal w-full flex items-center gap-normal h-10 rounded-md hover:bg-bg-hover transition-all duration-150 disabled:opacity-60 disabled:cursor-not-allowed\"\n >\n <span\n [ngClass]=\"{\n 'radio-checked': value === opt.value,\n 'radio-uncheck': value !== opt.value\n }\"\n class=\"radio-container\"\n >\n @if(value === opt.value) {<span class=\"radio-dot\"></span>}\n </span>\n\n <span class=\"txt-default mb-0\">{{ opt.label }}</span>\n </button>\n @if (invalid){\n <div class=\"txt-invalid\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n" }]
1853
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { label: [{
1854
+ type: Input
1855
+ }], required: [{
1856
+ type: Input
1857
+ }], options: [{
1858
+ type: Input
1859
+ }], disabled: [{
1860
+ type: Input
1861
+ }], errorMessages: [{
1862
+ type: Input
1863
+ }], class: [{
1864
+ type: Input
1865
+ }] } });
1866
+
1867
+ class SearchBarComponent extends FxComponent {
1868
+ ref;
1869
+ placeholder = 'Search...';
1870
+ disabled = false;
1871
+ search = new EventEmitter();
1872
+ valueChange = new EventEmitter();
1873
+ constructor(ngControl, ref) {
1874
+ super(ngControl);
1875
+ this.ref = ref;
1876
+ }
1877
+ ngAfterViewInit() {
1878
+ this.ref.detectChanges();
1879
+ }
1880
+ onValueChange(value) {
1881
+ this.value = value;
1882
+ this.setValue(value);
1883
+ this.valueChange.emit(value);
1884
+ }
1885
+ onEnterKey() {
1886
+ this.onEnter(this.value);
1887
+ this.search.emit(this.value.trim());
1888
+ }
1889
+ clear() {
1890
+ this.value = '';
1891
+ this.setValue(this.value);
1892
+ this.valueChange.emit('');
1893
+ this.search.emit('');
1894
+ }
1895
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SearchBarComponent, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1896
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: SearchBarComponent, isStandalone: false, selector: "fx-ui-search-bar", inputs: { placeholder: "placeholder", disabled: "disabled" }, outputs: { search: "search", valueChange: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<div class=\"relative\">\n <fx-ui-hero-icon icon=\"magnifying-glass\" [size]=\"18\" class=\"absolute left-1 top-[3px] text-text-primary\"></fx-ui-hero-icon>\n <input\n type=\"text\"\n class=\"input-default px-9\"\n [attr.placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (keydown.enter)=\"onEnterKey()\"\n />\n\n <button\n *ngIf=\"value && !disabled\"\n type=\"button\"\n class=\"absolute inset-y-0 right-2 flex items-center text-text-primary hover:text-text-secondary\"\n (click)=\"clear()\"\n aria-label=\"Clear\"\n >\n <i class=\"material-symbols-outlined text-lg select-none\">close</i>\n </button>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["icon", "solid", "outline", "size", "color", "class"] }] });
1897
+ }
1898
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SearchBarComponent, decorators: [{
1899
+ type: Component,
1900
+ args: [{ selector: 'fx-ui-search-bar', standalone: false, template: "<div class=\"relative\">\n <fx-ui-hero-icon icon=\"magnifying-glass\" [size]=\"18\" class=\"absolute left-1 top-[3px] text-text-primary\"></fx-ui-hero-icon>\n <input\n type=\"text\"\n class=\"input-default px-9\"\n [attr.placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [value]=\"value\"\n (input)=\"onValueChange($any($event.target).value)\"\n (keydown.enter)=\"onEnterKey()\"\n />\n\n <button\n *ngIf=\"value && !disabled\"\n type=\"button\"\n class=\"absolute inset-y-0 right-2 flex items-center text-text-primary hover:text-text-secondary\"\n (click)=\"clear()\"\n aria-label=\"Clear\"\n >\n <i class=\"material-symbols-outlined text-lg select-none\">close</i>\n </button>\n</div>\n" }]
1901
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { placeholder: [{
1902
+ type: Input
1903
+ }], disabled: [{
1904
+ type: Input
1905
+ }], search: [{
1906
+ type: Output
1907
+ }], valueChange: [{
1908
+ type: Output
1909
+ }] } });
1910
+
1911
+ class SelectComponent extends FxComponent {
1912
+ ref;
1913
+ label = '';
1914
+ placeholder = '';
1915
+ options = [];
1916
+ multiple = false;
1917
+ disabled = false;
1918
+ errorMessages = {};
1919
+ required = false;
1920
+ class;
1921
+ constructor(ngControl, ref) {
1922
+ super(ngControl);
1923
+ this.ref = ref;
1924
+ }
1925
+ ngAfterViewInit() {
1926
+ this.ref.detectChanges();
1927
+ }
1928
+ onSelectionChange(value) {
1929
+ this.value = value;
1930
+ this.onChange(this.value);
1931
+ }
1932
+ isSelected(value) {
1933
+ if (Array.isArray(this.value)) {
1934
+ return this.value.includes(value);
1935
+ }
1936
+ return this.value === value;
1937
+ }
1938
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SelectComponent, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1939
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SelectComponent, isStandalone: false, selector: "fx-ui-select", inputs: { label: "label", placeholder: "placeholder", options: "options", multiple: "multiple", disabled: "disabled", errorMessages: "errorMessages", required: "required", class: "class" }, usesInheritance: true, ngImport: i0, template: "<div class=\"mb-4 text-left w-full\" [class]=\"class\">\n <label *ngIf=\"label\" class=\"block txt-field-label\">\n {{ label }}\n @if(required) {<span class=\"txt-required\">*</span>}\n </label>\n\n <mat-form-field class=\"fx-select-field w-full shadow-sm\" appearance=\"fill\">\n <mat-select\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event.value)\"\n (blur)=\"onTouched()\"\n >\n <mat-option *ngFor=\"let option of options\" [value]=\"option.value\">\n <span class=\"txt-default\">{{ option.label }}</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n <div *ngIf=\"invalid\" class=\"txt-invalid text-left\">\n {{ getErrorMessage(label) }}\n </div>\n</div>\n", styles: ["::ng-deep .fx-select-field{display:block!important;width:100%!important;margin:0!important;padding:0!important;border-radius:.75rem;box-shadow:0 1px 1px rgb(var(--border-default))}::ng-deep .fx-select-field .mat-mdc-form-field-wrapper,::ng-deep .fx-select-field .mat-mdc-text-field-wrapper{padding:0!important;margin:0!important;width:100%!important}::ng-deep .fx-select-field .mdc-text-field{width:100%!important;margin:0!important;padding:0!important;--mdc-shape-small: 0 !important}::ng-deep .fx-select-field .mat-mdc-form-field-flex{width:100%!important;margin:0!important;padding:0 .75rem!important;border:1px solid rgb(var(--border-default));border-radius:.5rem;height:36px!important;align-items:center;background-color:rgb(var(--bg-primary))}::ng-deep .fx-select-field .mdc-notched-outline,::ng-deep .fx-select-field .mat-mdc-form-field-subscript-wrapper{display:none!important}::ng-deep .fx-select-field.mat-focused .mat-mdc-form-field-flex{border:2px solid rgb(var(--border-interactive))!important;outline:none!important;border-radius:.5rem}::ng-deep .fx-select-field.mat-form-field-invalid .mat-mdc-form-field-flex{border-color:#ef4444!important;box-shadow:none!important}::ng-deep .fx-select-field .mat-mdc-select-trigger{padding:0!important;margin:0!important}::ng-deep .fx-select-field .mat-mdc-select-arrow-wrapper{margin-right:0!important}::ng-deep .fx-select-field .mat-mdc-select-arrow-wrapper{color:rgb(var(--text-primary))}::ng-deep .mat-mdc-select-panel{background-color:rgb(var(--bg-primary))!important;border:1px solid rgb(var(--border-default))!important;border-radius:.5rem!important;box-shadow:0 2px 4px #0000001a!important}::ng-deep .fx-select-field .mat-mdc-select-placeholder{color:rgb(var(--text-placeholder))!important;font-size:14px}::ng-deep .fx-select-field .mat-mdc-select-value{color:rgb(var(--text-primary))!important;font-size:14px;font-weight:400}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: i3$1.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: i3$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }] });
1940
+ }
1941
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SelectComponent, decorators: [{
1942
+ type: Component,
1943
+ args: [{ selector: 'fx-ui-select', standalone: false, template: "<div class=\"mb-4 text-left w-full\" [class]=\"class\">\n <label *ngIf=\"label\" class=\"block txt-field-label\">\n {{ label }}\n @if(required) {<span class=\"txt-required\">*</span>}\n </label>\n\n <mat-form-field class=\"fx-select-field w-full shadow-sm\" appearance=\"fill\">\n <mat-select\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event.value)\"\n (blur)=\"onTouched()\"\n >\n <mat-option *ngFor=\"let option of options\" [value]=\"option.value\">\n <span class=\"txt-default\">{{ option.label }}</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n <div *ngIf=\"invalid\" class=\"txt-invalid text-left\">\n {{ getErrorMessage(label) }}\n </div>\n</div>\n", styles: ["::ng-deep .fx-select-field{display:block!important;width:100%!important;margin:0!important;padding:0!important;border-radius:.75rem;box-shadow:0 1px 1px rgb(var(--border-default))}::ng-deep .fx-select-field .mat-mdc-form-field-wrapper,::ng-deep .fx-select-field .mat-mdc-text-field-wrapper{padding:0!important;margin:0!important;width:100%!important}::ng-deep .fx-select-field .mdc-text-field{width:100%!important;margin:0!important;padding:0!important;--mdc-shape-small: 0 !important}::ng-deep .fx-select-field .mat-mdc-form-field-flex{width:100%!important;margin:0!important;padding:0 .75rem!important;border:1px solid rgb(var(--border-default));border-radius:.5rem;height:36px!important;align-items:center;background-color:rgb(var(--bg-primary))}::ng-deep .fx-select-field .mdc-notched-outline,::ng-deep .fx-select-field .mat-mdc-form-field-subscript-wrapper{display:none!important}::ng-deep .fx-select-field.mat-focused .mat-mdc-form-field-flex{border:2px solid rgb(var(--border-interactive))!important;outline:none!important;border-radius:.5rem}::ng-deep .fx-select-field.mat-form-field-invalid .mat-mdc-form-field-flex{border-color:#ef4444!important;box-shadow:none!important}::ng-deep .fx-select-field .mat-mdc-select-trigger{padding:0!important;margin:0!important}::ng-deep .fx-select-field .mat-mdc-select-arrow-wrapper{margin-right:0!important}::ng-deep .fx-select-field .mat-mdc-select-arrow-wrapper{color:rgb(var(--text-primary))}::ng-deep .mat-mdc-select-panel{background-color:rgb(var(--bg-primary))!important;border:1px solid rgb(var(--border-default))!important;border-radius:.5rem!important;box-shadow:0 2px 4px #0000001a!important}::ng-deep .fx-select-field .mat-mdc-select-placeholder{color:rgb(var(--text-placeholder))!important;font-size:14px}::ng-deep .fx-select-field .mat-mdc-select-value{color:rgb(var(--text-primary))!important;font-size:14px;font-weight:400}\n"] }]
1944
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { label: [{
1945
+ type: Input
1946
+ }], placeholder: [{
1947
+ type: Input
1948
+ }], options: [{
1949
+ type: Input
1950
+ }], multiple: [{
1951
+ type: Input
1952
+ }], disabled: [{
1953
+ type: Input
1954
+ }], errorMessages: [{
1955
+ type: Input
1956
+ }], required: [{
1957
+ type: Input
1958
+ }], class: [{
1959
+ type: Input
1960
+ }] } });
1961
+
1962
+ class SliderComponent extends FxComponent {
1963
+ ref;
1964
+ trackRef;
1965
+ thumbRef;
1966
+ min = 0;
1967
+ max = 100;
1968
+ step = 1;
1969
+ vertical = false;
1970
+ disabled = false;
1971
+ valueChange = new EventEmitter();
1972
+ dragging = false;
1973
+ constructor(ngControl, ref) {
1974
+ super(ngControl);
1975
+ this.ref = ref;
1976
+ }
1977
+ ngAfterViewInit() {
1978
+ this._normalizeValue(this.value);
1979
+ this.ref.markForCheck();
1980
+ }
1981
+ setDisabledState(isDisabled) {
1982
+ this.disabled = isDisabled;
1983
+ this.ref.markForCheck();
1984
+ }
1985
+ writeValue(value) {
1986
+ this.value = this._normalizeValue(value ?? this.min);
1987
+ this.ref.markForCheck();
1988
+ }
1989
+ _normalizeValue(v) {
1990
+ if (!Number.isFinite(v))
1991
+ v = this.min;
1992
+ const clamped = clamp(v, this.min, this.max);
1993
+ const stepped = Math.round((clamped - this.min) / this.step) * this.step + this.min;
1994
+ const precision = Math.max(0, this._decimalPlaces(this.step));
1995
+ return parseFloat(stepped.toFixed(precision));
1996
+ }
1997
+ _decimalPlaces(n) {
1998
+ const s = String(n);
1999
+ if (s.indexOf('.') === -1)
2000
+ return 0;
2001
+ return s.length - s.indexOf('.') - 1;
2002
+ }
2003
+ /** Pointer events */
2004
+ onPointerDown(event) {
2005
+ if (this.disabled)
2006
+ return;
2007
+ event.target.setPointerCapture(event.pointerId);
2008
+ this.dragging = true;
2009
+ this._setFromPointer(event);
2010
+ }
2011
+ onPointerMove(event) {
2012
+ if (!this.dragging || this.disabled)
2013
+ return;
2014
+ this._setFromPointer(event);
2015
+ }
2016
+ onPointerUp(event) {
2017
+ if (this.disabled)
2018
+ return;
2019
+ try {
2020
+ event.target.releasePointerCapture(event.pointerId);
2021
+ }
2022
+ catch { }
2023
+ this.dragging = false;
2024
+ this.onTouched();
2025
+ }
2026
+ _setFromPointer(event) {
2027
+ const newVal = this._coordToValue(event.clientX, event.clientY);
2028
+ this._applyValue(newVal);
2029
+ }
2030
+ _coordToValue(clientX, clientY) {
2031
+ const rect = this.trackRef.nativeElement.getBoundingClientRect();
2032
+ let ratio = this.vertical
2033
+ ? 1 - (clientY - rect.top) / rect.height
2034
+ : (clientX - rect.left) / rect.width;
2035
+ ratio = clamp(ratio, 0, 1);
2036
+ const raw = this.min + ratio * (this.max - this.min);
2037
+ return this._normalizeValue(raw);
2038
+ }
2039
+ onTrackClick(event) {
2040
+ if (this.disabled)
2041
+ return;
2042
+ const newVal = this._coordToValue(event.clientX, event.clientY);
2043
+ this._applyValue(newVal);
2044
+ this.onTouched();
2045
+ }
2046
+ onKeydown(ev) {
2047
+ if (this.disabled)
2048
+ return;
2049
+ const key = ev.key;
2050
+ const largeStep = (this.max - this.min) / 10;
2051
+ let delta = 0;
2052
+ if (key === 'ArrowLeft' || key === 'ArrowDown')
2053
+ delta = -this.step;
2054
+ else if (key === 'ArrowRight' || key === 'ArrowUp')
2055
+ delta = this.step;
2056
+ else if (key === 'PageDown')
2057
+ delta = -largeStep;
2058
+ else if (key === 'PageUp')
2059
+ delta = largeStep;
2060
+ else if (key === 'Home')
2061
+ return this._applyValue(this.min);
2062
+ else if (key === 'End')
2063
+ return this._applyValue(this.max);
2064
+ if (delta !== 0) {
2065
+ this._applyValue(this.value + delta);
2066
+ ev.preventDefault();
2067
+ }
2068
+ }
2069
+ _applyValue(newVal) {
2070
+ const v = this._normalizeValue(newVal);
2071
+ if (v !== this.value) {
2072
+ this.value = v;
2073
+ this.ref.markForCheck();
2074
+ this.valueChange.emit(v);
2075
+ this.onChange(v);
2076
+ }
2077
+ }
2078
+ get percent() {
2079
+ if (this.max === this.min)
2080
+ return 0;
2081
+ return ((this.value - this.min) / (this.max - this.min)) * 100;
2082
+ }
2083
+ thumbStyle() {
2084
+ return this.vertical
2085
+ ? { bottom: `${this.percent}%`, transform: 'translateY(50%)' }
2086
+ : { left: `${this.percent}%`, transform: 'translateX(-50%)' };
2087
+ }
2088
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SliderComponent, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2089
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: SliderComponent, isStandalone: false, selector: "fx-ui-slider", inputs: { min: "min", max: "max", step: "step", vertical: "vertical", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "keydown": "onKeydown($event)" } }, viewQueries: [{ propertyName: "trackRef", first: true, predicate: ["track"], descendants: true, static: true }, { propertyName: "thumbRef", first: true, predicate: ["thumb"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"w-full select-none\"\n [class.cursor-not-allowed]=\"disabled\"\n [class.opacity-60]=\"disabled\"\n role=\"group\"\n>\n <div\n #track\n class=\"relative touch-none py-4\"\n (click)=\"onTrackClick($event)\"\n [attr.aria-disabled]=\"disabled\"\n [attr.aria-orientation]=\"vertical ? 'vertical' : 'horizontal'\"\n >\n <div\n class=\"relative flex items-center\"\n [ngClass]=\"{ 'flex-col h-48': vertical }\"\n >\n <div\n class=\"relative flex-1 rounded-full bg-gray-600 h-2\"\n [ngClass]=\"{ 'w-1 rotate-0 h-full w-auto bg-border-gray-700': vertical }\"\n >\n <div\n class=\"absolute left-0 top-0 h-full rounded-full bg-primary\"\n *ngIf=\"!vertical\"\n [style.width.%]=\"percent\"\n ></div>\n\n <div\n class=\"absolute bottom-0 left-0 w-full rounded-full bg-primary\"\n *ngIf=\"vertical\"\n [style.height.%]=\"percent\"\n style=\"transform-origin: bottom;\"\n ></div>\n\n <button\n #thumb\n type=\"button\"\n class=\"absolute -mt-1 -ml-1.5 w-4 h-4 rounded-full shadow focus:ring-primary bg-primary border-2 border-text-primary\"\n [ngStyle]=\"thumbStyle()\"\n role=\"slider\"\n [attr.aria-valuemin]=\"min\"\n [attr.aria-valuemax]=\"max\"\n [attr.aria-valuenow]=\"value\"\n [attr.aria-disabled]=\"disabled\"\n tabindex=\"0\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n [disabled]=\"disabled\"\n ></button>\n </div>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
2090
+ }
2091
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SliderComponent, decorators: [{
2092
+ type: Component,
2093
+ args: [{ selector: 'fx-ui-slider', standalone: false, template: "<div\n class=\"w-full select-none\"\n [class.cursor-not-allowed]=\"disabled\"\n [class.opacity-60]=\"disabled\"\n role=\"group\"\n>\n <div\n #track\n class=\"relative touch-none py-4\"\n (click)=\"onTrackClick($event)\"\n [attr.aria-disabled]=\"disabled\"\n [attr.aria-orientation]=\"vertical ? 'vertical' : 'horizontal'\"\n >\n <div\n class=\"relative flex items-center\"\n [ngClass]=\"{ 'flex-col h-48': vertical }\"\n >\n <div\n class=\"relative flex-1 rounded-full bg-gray-600 h-2\"\n [ngClass]=\"{ 'w-1 rotate-0 h-full w-auto bg-border-gray-700': vertical }\"\n >\n <div\n class=\"absolute left-0 top-0 h-full rounded-full bg-primary\"\n *ngIf=\"!vertical\"\n [style.width.%]=\"percent\"\n ></div>\n\n <div\n class=\"absolute bottom-0 left-0 w-full rounded-full bg-primary\"\n *ngIf=\"vertical\"\n [style.height.%]=\"percent\"\n style=\"transform-origin: bottom;\"\n ></div>\n\n <button\n #thumb\n type=\"button\"\n class=\"absolute -mt-1 -ml-1.5 w-4 h-4 rounded-full shadow focus:ring-primary bg-primary border-2 border-text-primary\"\n [ngStyle]=\"thumbStyle()\"\n role=\"slider\"\n [attr.aria-valuemin]=\"min\"\n [attr.aria-valuemax]=\"max\"\n [attr.aria-valuenow]=\"value\"\n [attr.aria-disabled]=\"disabled\"\n tabindex=\"0\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n [disabled]=\"disabled\"\n ></button>\n </div>\n </div>\n </div>\n</div>\n" }]
2094
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { trackRef: [{
2095
+ type: ViewChild,
2096
+ args: ['track', { static: true }]
2097
+ }], thumbRef: [{
2098
+ type: ViewChild,
2099
+ args: ['thumb', { static: true }]
2100
+ }], min: [{
2101
+ type: Input
2102
+ }], max: [{
2103
+ type: Input
2104
+ }], step: [{
2105
+ type: Input
2106
+ }], vertical: [{
2107
+ type: Input
2108
+ }], disabled: [{
2109
+ type: Input
2110
+ }], valueChange: [{
2111
+ type: Output
2112
+ }], onKeydown: [{
2113
+ type: HostListener,
2114
+ args: ['keydown', ['$event']]
2115
+ }] } });
2116
+
2117
+ class SwitchComponent extends FxComponent {
2118
+ cdr;
2119
+ disabled = false;
2120
+ onSwitch = new EventEmitter();
2121
+ ngAfterViewInit() {
2122
+ this.cdr.detectChanges();
2123
+ }
2124
+ constructor(ngControl, cdr) {
2125
+ super(ngControl);
2126
+ this.cdr = cdr;
2127
+ }
2128
+ setDisabledState(isDisabled) {
2129
+ this.disabled = isDisabled;
2130
+ }
2131
+ toggle() {
2132
+ if (this.disabled)
2133
+ return;
2134
+ this.value = !this.value;
2135
+ this.onSwitch.emit(this.value);
2136
+ this.onChange(this.value);
2137
+ this.onTouched();
2138
+ }
2139
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SwitchComponent, deps: [{ token: i1$3.NgControl }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2140
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SwitchComponent, isStandalone: false, selector: "fx-ui-switch", inputs: { disabled: "disabled" }, outputs: { onSwitch: "onSwitch" }, usesInheritance: true, ngImport: i0, template: "<div\n class=\"relative inline-flex items-center w-10 h-5 rounded-full transition-colors duration-300 cursor-pointer\"\n [ngClass]=\"{\n 'bg-success': value && !disabled,\n 'bg-button-default': !value && !disabled,\n 'bg-bg-hover': disabled\n }\"\n (click)=\"toggle()\"\n>\n @if(value) {\n <i style=\"font-size: 20px;\" class=\"material-symbols-outlined absolute left-0.5 top-0 text-text-inverse\">check</i>\n \n }\n @if(!value) {\n <i style=\"font-size: 20px;\" class=\"material-symbols-outlined absolute right-0.5 top-0 text-text-inverse\">close</i>\n }\n <div\n class=\"absolute top-0.5 left-0.5 w-4 h-4 bg-text-inverse rounded-full shadow-md transform transition-transform duration-300\"\n [ngClass]=\"{ 'translate-x-5': value }\"\n ></div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
2141
+ }
2142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SwitchComponent, decorators: [{
2143
+ type: Component,
2144
+ args: [{ selector: 'fx-ui-switch', standalone: false, template: "<div\n class=\"relative inline-flex items-center w-10 h-5 rounded-full transition-colors duration-300 cursor-pointer\"\n [ngClass]=\"{\n 'bg-success': value && !disabled,\n 'bg-button-default': !value && !disabled,\n 'bg-bg-hover': disabled\n }\"\n (click)=\"toggle()\"\n>\n @if(value) {\n <i style=\"font-size: 20px;\" class=\"material-symbols-outlined absolute left-0.5 top-0 text-text-inverse\">check</i>\n \n }\n @if(!value) {\n <i style=\"font-size: 20px;\" class=\"material-symbols-outlined absolute right-0.5 top-0 text-text-inverse\">close</i>\n }\n <div\n class=\"absolute top-0.5 left-0.5 w-4 h-4 bg-text-inverse rounded-full shadow-md transform transition-transform duration-300\"\n [ngClass]=\"{ 'translate-x-5': value }\"\n ></div>\n</div>\n" }]
2145
+ }], ctorParameters: () => [{ type: i1$3.NgControl }, { type: i0.ChangeDetectorRef }], propDecorators: { disabled: [{
2146
+ type: Input
2147
+ }], onSwitch: [{
2148
+ type: Output
2149
+ }] } });
2150
+
2151
+ class TabComponent {
2152
+ label;
2153
+ icon;
2154
+ content;
2155
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2156
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: TabComponent, isStandalone: false, selector: "fx-ui-tab", inputs: { label: "label", icon: "icon" }, viewQueries: [{ propertyName: "content", first: true, predicate: TemplateRef, descendants: true, static: true }], ngImport: i0, template: "<ng-template><ng-content></ng-content></ng-template>\n" });
2157
+ }
2158
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabComponent, decorators: [{
2159
+ type: Component,
2160
+ args: [{ selector: 'fx-ui-tab', standalone: false, template: "<ng-template><ng-content></ng-content></ng-template>\n" }]
2161
+ }], propDecorators: { label: [{
2162
+ type: Input
2163
+ }], icon: [{
2164
+ type: Input
2165
+ }], content: [{
2166
+ type: ViewChild,
2167
+ args: [TemplateRef, { static: true }]
2168
+ }] } });
2169
+
2170
+ class TabGroupComponent {
2171
+ renderer;
2172
+ tabs;
2173
+ activeIndex = 0;
2174
+ tabListRef;
2175
+ underlineRef;
2176
+ canScrollLeft = false;
2177
+ canScrollRight = false;
2178
+ animateDelay = 50;
2179
+ scrollAmount = 160;
2180
+ sidePadding = 32; // same as button width space
2181
+ constructor(renderer) {
2182
+ this.renderer = renderer;
2183
+ }
2184
+ ngAfterContentInit() {
2185
+ setTimeout(() => {
2186
+ this.updateScrollButtons();
2187
+ this.updateUnderlinePosition();
2188
+ this.scrollToActiveTab(false);
2189
+ }, 0);
2190
+ }
2191
+ selectTab(index) {
2192
+ this.activeIndex = index;
2193
+ this.scrollToActiveTab(true);
2194
+ }
2195
+ updateUnderlinePosition() {
2196
+ const tabListEl = this.tabListRef.nativeElement;
2197
+ const underlineEl = this.underlineRef.nativeElement;
2198
+ const tabButtons = tabListEl.querySelectorAll('.tab-btn');
2199
+ const activeTab = tabButtons[this.activeIndex];
2200
+ if (!activeTab || !underlineEl)
2201
+ return;
2202
+ const tabRect = activeTab.getBoundingClientRect();
2203
+ const containerRect = tabListEl.getBoundingClientRect();
2204
+ // Calculate X position relative to scrollable area (not viewport)
2205
+ const translateX = tabRect.left - containerRect.left + tabListEl.scrollLeft - this.sidePadding;
2206
+ this.renderer.setStyle(underlineEl, 'width', `${activeTab.offsetWidth}px`);
2207
+ this.renderer.setStyle(underlineEl, 'transform', `translateX(${translateX}px)`);
2208
+ }
2209
+ scrollToActiveTab(updateUnderlineAfter = true) {
2210
+ const tabListEl = this.tabListRef.nativeElement;
2211
+ const tabButtons = tabListEl.querySelectorAll('.tab-btn');
2212
+ const activeTab = tabButtons[this.activeIndex];
2213
+ if (!activeTab)
2214
+ return;
2215
+ const elLeft = activeTab.offsetLeft;
2216
+ const elRight = elLeft + activeTab.offsetWidth;
2217
+ const containerLeft = tabListEl.scrollLeft;
2218
+ const containerRight = containerLeft + tabListEl.clientWidth;
2219
+ if (elLeft < containerLeft) {
2220
+ tabListEl.scrollTo({ left: Math.max(elLeft - 32, 0), behavior: 'smooth' });
2221
+ }
2222
+ else if (elRight > containerRight) {
2223
+ const target = elRight - tabListEl.clientWidth + 32;
2224
+ tabListEl.scrollTo({ left: target, behavior: 'smooth' });
2225
+ }
2226
+ setTimeout(() => {
2227
+ this.updateScrollButtons();
2228
+ this.updateUnderlinePosition();
2229
+ }, updateUnderlineAfter ? this.animateDelay : 0);
2230
+ }
2231
+ scroll(direction) {
2232
+ const tabListEl = this.tabListRef.nativeElement;
2233
+ const delta = direction === 'left' ? -this.scrollAmount : this.scrollAmount;
2234
+ tabListEl.scrollBy({ left: delta, behavior: 'smooth' });
2235
+ setTimeout(() => {
2236
+ this.updateScrollButtons();
2237
+ this.updateUnderlinePosition();
2238
+ }, this.animateDelay);
2239
+ }
2240
+ onScroll() {
2241
+ this.updateScrollButtons();
2242
+ this.updateUnderlinePosition();
2243
+ }
2244
+ updateScrollButtons() {
2245
+ const el = this.tabListRef.nativeElement;
2246
+ const scrollLeft = el.scrollLeft;
2247
+ const maxScrollLeft = el.scrollWidth - el.clientWidth;
2248
+ this.canScrollLeft = scrollLeft > 2;
2249
+ this.canScrollRight = scrollLeft < maxScrollLeft - 2;
2250
+ }
2251
+ onResize() {
2252
+ this.updateUnderlinePosition();
2253
+ }
2254
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabGroupComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
2255
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: TabGroupComponent, isStandalone: false, selector: "fx-ui-tab-group", inputs: { activeIndex: "activeIndex" }, host: { listeners: { "window:resize": "onResize()" } }, queries: [{ propertyName: "tabs", predicate: TabComponent }], viewQueries: [{ propertyName: "tabListRef", first: true, predicate: ["tabList"], descendants: true, static: true }, { propertyName: "underlineRef", first: true, predicate: ["underline"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"relative\">\n <!-- Left scroll button -->\n <button\n class=\"left-scroll-button\"\n type=\"button\"\n (click)=\"scroll('left')\"\n [style.opacity]=\"canScrollLeft ? 1 : 0\"\n [style.pointerEvents]=\"canScrollLeft ? 'auto' : 'none'\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-5 w-5 text-text-primary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n\n <div\n #tabList\n class=\"relative flex overflow-x-auto no-scrollbar scroll-smooth\"\n (scroll)=\"onScroll()\"\n >\n <button\n *ngFor=\"let tab of tabs.toArray(); let i = index\"\n (click)=\"selectTab(i)\"\n class=\"tab-btn tab-bar-btn\"\n >\n <div class=\"flex flex-row items-center justify-center\">\n @if(tab.icon) {<fx-ui-hero-icon\n [icon]=\"tab.icon\"\n [size]=\"20\"\n class=\"flex mr-[2px]\"\n [ngClass]=\"{\n 'text-primary mb-small': i === activeIndex,\n 'text-text-placeholder': i !== activeIndex\n }\"\n ></fx-ui-hero-icon\n >}\n <div [ngClass]=\"i === activeIndex ? 'txt-field-label text-primary' : 'txt-placeholder'\">{{ tab.label }}</div>\n </div>\n </button>\n\n <span #underline class=\"underline\" style=\"width: 0; transform: translateX(0)\"></span>\n </div>\n\n <button\n class=\"right-scroll-button\"\n type=\"button\"\n (click)=\"scroll('right')\"\n [style.opacity]=\"canScrollRight ? 1 : 0\"\n [style.pointerEvents]=\"canScrollRight ? 'auto' : 'none'\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-5 w-5 text-text-primary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n</div>\n\n<!-- Tab content -->\n<div class=\"transition-all duration-300 ease-in-out mt-4\">\n <ng-container *ngFor=\"let tab of tabs.toArray(); let i = index\">\n <div *ngIf=\"i === activeIndex\" class=\"animate-fadeIn\">\n <ng-container *ngTemplateOutlet=\"tab.content\"></ng-container>\n </div>\n </ng-container>\n</div>\n", styles: ["@keyframes fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-fadeIn{animation:fadeIn .28s ease-in-out}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}.underline{position:absolute;bottom:0;height:2px;background-color:rgb(var(--primary));transition:transform .25s cubic-bezier(.2,.9,.2,1),width .25s cubic-bezier(.2,.9,.2,1);will-change:transform,width;transform:translate(0);width:0;margin-left:32px;margin-right:32px}.left-scroll-button{position:absolute;left:0;top:0;z-index:10;display:flex;height:100%;align-items:center;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));padding-left:.5rem;padding-right:.5rem;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.right-scroll-button{position:absolute;right:0;top:0;z-index:10;display:flex;height:100%;align-items:center;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));padding-left:.5rem;padding-right:.5rem;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.tab-bar-btn{position:relative;white-space:nowrap;padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["icon", "solid", "outline", "size", "color", "class"] }] });
2256
+ }
2257
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabGroupComponent, decorators: [{
2258
+ type: Component,
2259
+ args: [{ selector: 'fx-ui-tab-group', standalone: false, template: "<div class=\"relative\">\n <!-- Left scroll button -->\n <button\n class=\"left-scroll-button\"\n type=\"button\"\n (click)=\"scroll('left')\"\n [style.opacity]=\"canScrollLeft ? 1 : 0\"\n [style.pointerEvents]=\"canScrollLeft ? 'auto' : 'none'\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-5 w-5 text-text-primary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n\n <div\n #tabList\n class=\"relative flex overflow-x-auto no-scrollbar scroll-smooth\"\n (scroll)=\"onScroll()\"\n >\n <button\n *ngFor=\"let tab of tabs.toArray(); let i = index\"\n (click)=\"selectTab(i)\"\n class=\"tab-btn tab-bar-btn\"\n >\n <div class=\"flex flex-row items-center justify-center\">\n @if(tab.icon) {<fx-ui-hero-icon\n [icon]=\"tab.icon\"\n [size]=\"20\"\n class=\"flex mr-[2px]\"\n [ngClass]=\"{\n 'text-primary mb-small': i === activeIndex,\n 'text-text-placeholder': i !== activeIndex\n }\"\n ></fx-ui-hero-icon\n >}\n <div [ngClass]=\"i === activeIndex ? 'txt-field-label text-primary' : 'txt-placeholder'\">{{ tab.label }}</div>\n </div>\n </button>\n\n <span #underline class=\"underline\" style=\"width: 0; transform: translateX(0)\"></span>\n </div>\n\n <button\n class=\"right-scroll-button\"\n type=\"button\"\n (click)=\"scroll('right')\"\n [style.opacity]=\"canScrollRight ? 1 : 0\"\n [style.pointerEvents]=\"canScrollRight ? 'auto' : 'none'\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-5 w-5 text-text-primary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n</div>\n\n<!-- Tab content -->\n<div class=\"transition-all duration-300 ease-in-out mt-4\">\n <ng-container *ngFor=\"let tab of tabs.toArray(); let i = index\">\n <div *ngIf=\"i === activeIndex\" class=\"animate-fadeIn\">\n <ng-container *ngTemplateOutlet=\"tab.content\"></ng-container>\n </div>\n </ng-container>\n</div>\n", styles: ["@keyframes fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-fadeIn{animation:fadeIn .28s ease-in-out}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}.underline{position:absolute;bottom:0;height:2px;background-color:rgb(var(--primary));transition:transform .25s cubic-bezier(.2,.9,.2,1),width .25s cubic-bezier(.2,.9,.2,1);will-change:transform,width;transform:translate(0);width:0;margin-left:32px;margin-right:32px}.left-scroll-button{position:absolute;left:0;top:0;z-index:10;display:flex;height:100%;align-items:center;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));padding-left:.5rem;padding-right:.5rem;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.right-scroll-button{position:absolute;right:0;top:0;z-index:10;display:flex;height:100%;align-items:center;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));padding-left:.5rem;padding-right:.5rem;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.tab-bar-btn{position:relative;white-space:nowrap;padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}\n"] }]
2260
+ }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { tabs: [{
2261
+ type: ContentChildren,
2262
+ args: [TabComponent]
2263
+ }], activeIndex: [{
2264
+ type: Input
2265
+ }], tabListRef: [{
2266
+ type: ViewChild,
2267
+ args: ['tabList', { static: true }]
2268
+ }], underlineRef: [{
2269
+ type: ViewChild,
2270
+ args: ['underline', { static: true }]
2271
+ }], onResize: [{
2272
+ type: HostListener,
2273
+ args: ['window:resize']
2274
+ }] } });
2275
+
2276
+ class TagComponent {
2277
+ label;
2278
+ type = 'default';
2279
+ rounded = true;
2280
+ icon;
2281
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2282
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: TagComponent, isStandalone: false, selector: "fx-ui-tag", inputs: { label: "label", type: "type", rounded: "rounded", icon: "icon" }, ngImport: i0, template: "<div\n class=\"flex flex-row gap-1\"\n [class]=\"rounded ? 'tag-round' : 'tag-square'\"\n [ngClass]=\"{\n 'tag-critical': type === 'critical',\n 'tag-success': type === 'success',\n 'tag-warning': type === 'warning',\n 'tag-information': type === 'information',\n 'tag-discovery': type === 'discovery',\n 'tag-danger': type === 'danger',\n 'tag-default': type === 'default'\n }\"\n>\n @if(icon){<fx-ui-hero-icon\n class=\"flex\"\n [icon]=\"icon\"\n [size]=\"18\"\n [ngClass]=\"{\n 'text-critical': type === 'critical',\n 'text-success': type === 'success',\n 'text-warning': type === 'warning',\n 'text-information': type === 'information',\n 'text-discovery': type === 'discovery',\n 'text-danger': type === 'danger',\n 'text-text-primary': type === 'default',\n }\"\n ></fx-ui-hero-icon\n >}\n\n <div\n [ngClass]=\"{\n 'txt-tag-critical': type === 'critical',\n 'txt-tag-success': type === 'success',\n 'txt-tag-warning': type === 'warning',\n 'txt-tag-information': type === 'information',\n 'txt-tag-discovery': type === 'discovery',\n 'txt-tag-danger': type === 'danger',\n 'txt-tag-default': type === 'default',\n }\"\n >\n {{ label }}\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["icon", "solid", "outline", "size", "color", "class"] }] });
2283
+ }
2284
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TagComponent, decorators: [{
2285
+ type: Component,
2286
+ args: [{ selector: 'fx-ui-tag', standalone: false, template: "<div\n class=\"flex flex-row gap-1\"\n [class]=\"rounded ? 'tag-round' : 'tag-square'\"\n [ngClass]=\"{\n 'tag-critical': type === 'critical',\n 'tag-success': type === 'success',\n 'tag-warning': type === 'warning',\n 'tag-information': type === 'information',\n 'tag-discovery': type === 'discovery',\n 'tag-danger': type === 'danger',\n 'tag-default': type === 'default'\n }\"\n>\n @if(icon){<fx-ui-hero-icon\n class=\"flex\"\n [icon]=\"icon\"\n [size]=\"18\"\n [ngClass]=\"{\n 'text-critical': type === 'critical',\n 'text-success': type === 'success',\n 'text-warning': type === 'warning',\n 'text-information': type === 'information',\n 'text-discovery': type === 'discovery',\n 'text-danger': type === 'danger',\n 'text-text-primary': type === 'default',\n }\"\n ></fx-ui-hero-icon\n >}\n\n <div\n [ngClass]=\"{\n 'txt-tag-critical': type === 'critical',\n 'txt-tag-success': type === 'success',\n 'txt-tag-warning': type === 'warning',\n 'txt-tag-information': type === 'information',\n 'txt-tag-discovery': type === 'discovery',\n 'txt-tag-danger': type === 'danger',\n 'txt-tag-default': type === 'default',\n }\"\n >\n {{ label }}\n </div>\n</div>\n" }]
2287
+ }], propDecorators: { label: [{
2288
+ type: Input
2289
+ }], type: [{
2290
+ type: Input
2291
+ }], rounded: [{
2292
+ type: Input
2293
+ }], icon: [{
2294
+ type: Input
2295
+ }] } });
2296
+
2297
+ const FX_COMPONENTS = [
2298
+ InputComponent,
2299
+ SelectComponent,
2300
+ RadioButtonComponent,
2301
+ CheckboxComponent,
2302
+ DndUploadComponent,
2303
+ ButtonComponent,
2304
+ RadioButtonToggleComponent,
2305
+ DatetimePicker,
2306
+ LoadingPanel,
2307
+ SearchBarComponent,
2308
+ TabGroupComponent,
2309
+ TabComponent,
2310
+ HeroIconComponent,
2311
+ ToastComponent,
2312
+ ToastContainerComponent,
2313
+ TagComponent,
2314
+ ChartComponent,
2315
+ SliderComponent,
2316
+ SwitchComponent
2317
+ ];
2318
+
2319
+ class ConfirmationDialogComponent {
2320
+ ref;
2321
+ title = '';
2322
+ message = '';
2323
+ cancelLabel = 'Cancel';
2324
+ confirmLabel = 'Submit';
2325
+ constructor(ref, bindings) {
2326
+ this.ref = ref;
2327
+ this.title = _.get(bindings, 'title');
2328
+ this.message = _.get(bindings, 'message');
2329
+ this.cancelLabel = _.get(bindings, 'cancelLabel');
2330
+ this.confirmLabel = _.get(bindings, 'confirmLabel');
2331
+ }
2332
+ accept() {
2333
+ this.ref.close(true);
2334
+ }
2335
+ cancel() {
2336
+ this.ref.close(false);
2337
+ }
2338
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ConfirmationDialogComponent, deps: [{ token: i1$1.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
2339
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: ConfirmationDialogComponent, isStandalone: false, selector: "ui-confirmation", ngImport: i0, template: "<div animate.enter=\"fade-in-animation\">\n <div class=\"txt-section-header px-2xl py-semi\">{{title}}</div>\n <mat-dialog-content>\n <div class=\"txt-default\">{{message}}</div>\n </mat-dialog-content>\n <mat-dialog-actions align=\"end\">\n <fx-ui-button class=\"mr-1\" [label]=\"cancelLabel\" (clicked)=\"cancel()\"></fx-ui-button>\n <fx-ui-button buttonVariant=\"primary\" class=\"mr-1\" [label]=\"confirmLabel\" (clicked)=\"accept()\"></fx-ui-button>\n </mat-dialog-actions>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: ButtonComponent, selector: "fx-ui-button", inputs: ["label", "disabled", "buttonVariant", "icon", "class", "loading"], outputs: ["clicked"] }] });
2340
+ }
2341
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ConfirmationDialogComponent, decorators: [{
2342
+ type: Component,
2343
+ args: [{ selector: 'ui-confirmation', standalone: false, template: "<div animate.enter=\"fade-in-animation\">\n <div class=\"txt-section-header px-2xl py-semi\">{{title}}</div>\n <mat-dialog-content>\n <div class=\"txt-default\">{{message}}</div>\n </mat-dialog-content>\n <mat-dialog-actions align=\"end\">\n <fx-ui-button class=\"mr-1\" [label]=\"cancelLabel\" (clicked)=\"cancel()\"></fx-ui-button>\n <fx-ui-button buttonVariant=\"primary\" class=\"mr-1\" [label]=\"confirmLabel\" (clicked)=\"accept()\"></fx-ui-button>\n </mat-dialog-actions>\n</div>\n" }]
2344
+ }], ctorParameters: () => [{ type: i1$1.MatDialogRef }, { type: undefined, decorators: [{
2345
+ type: Inject,
2346
+ args: [MAT_DIALOG_DATA]
2347
+ }] }] });
2348
+
2349
+ const DIALOGS_COMPONENT = [
2350
+ ConfirmationDialogComponent
2351
+ ];
2352
+
2353
+ const MY_FORMATS = {
2354
+ parseInput: 'YYYY-MM-DD HH:mm:ss',
2355
+ fullPickerInput: 'YYYY-MM-DD HH:mm:ss',
2356
+ datePickerInput: 'YYYY-MM-DD HH:mm:ss',
2357
+ timePickerInput: 'HH:mm:ss',
2358
+ monthYearLabel: 'MMM YYYY',
2359
+ dateA11yLabel: 'YYYY-MM-DD HH:mm:ss',
2360
+ monthYearA11yLabel: 'MMMM YYYY',
2361
+ };
2362
+ class UiModule {
2363
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2364
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: UiModule, declarations: [InputComponent, SelectComponent, RadioButtonComponent, CheckboxComponent, DndUploadComponent, ButtonComponent, RadioButtonToggleComponent, DatetimePicker, LoadingPanel, SearchBarComponent, TabGroupComponent, TabComponent, HeroIconComponent, ToastComponent, ToastContainerComponent, TagComponent, ChartComponent, SliderComponent, SwitchComponent, ConfirmationDialogComponent], imports: [CommonModule,
2365
+ FormsModule,
2366
+ ReactiveFormsModule,
2367
+ OwlDateTimeModule,
2368
+ OwlNativeDateTimeModule,
2369
+ HasPermissionDirective,
2370
+ NgHeroiconsModule, i2$3.NgxEchartsModule, i3$1.MatSelectModule, i23.MatRadioModule, i24.MatButtonModule, i25.MatIconModule, i26.MatPaginatorModule, i27.MatTableModule, i28.MatSnackBarModule, i1$1.MatDialogModule, i30.MatCheckboxModule, i31.MatCardModule, i32.MatDatepickerModule, i33.MatTimepickerModule, i34.MatBadgeModule, i35.MatExpansionModule, i36.MatFormFieldModule], exports: [InputComponent, SelectComponent, RadioButtonComponent, CheckboxComponent, DndUploadComponent, ButtonComponent, RadioButtonToggleComponent, DatetimePicker, LoadingPanel, SearchBarComponent, TabGroupComponent, TabComponent, HeroIconComponent, ToastComponent, ToastContainerComponent, TagComponent, ChartComponent, SliderComponent, SwitchComponent, ConfirmationDialogComponent,
2371
+ // Module
2372
+ FormsModule,
2373
+ ReactiveFormsModule,
2374
+ OwlDateTimeModule,
2375
+ OwlNativeDateTimeModule,
2376
+ HasPermissionDirective,
2377
+ NgHeroiconsModule, i3$1.MatSelectModule, i23.MatRadioModule, i24.MatButtonModule, i25.MatIconModule, i26.MatPaginatorModule, i27.MatTableModule, i28.MatSnackBarModule, i1$1.MatDialogModule, i30.MatCheckboxModule, i31.MatCardModule, i32.MatDatepickerModule, i33.MatTimepickerModule, i34.MatBadgeModule, i35.MatExpansionModule, i36.MatFormFieldModule] });
2378
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, providers: [
2379
+ importProvidersFrom(NgHeroiconsModule.forRoot()),
2380
+ // { provide: OWL_DATE_TIME_FORMATS, useValue: MY_FORMATS },
2381
+ ], imports: [CommonModule,
2382
+ FormsModule,
2383
+ ReactiveFormsModule,
2384
+ OwlDateTimeModule,
2385
+ OwlNativeDateTimeModule,
2386
+ NgHeroiconsModule,
2387
+ NgxEchartsModule.forRoot({ echarts: () => import('echarts') }), MATERIAL_MODULE,
2388
+ // Module
2389
+ FormsModule,
2390
+ ReactiveFormsModule,
2391
+ OwlDateTimeModule,
2392
+ OwlNativeDateTimeModule,
2393
+ NgHeroiconsModule, i3$1.MatSelectModule, i23.MatRadioModule, i24.MatButtonModule, i25.MatIconModule, i26.MatPaginatorModule, i27.MatTableModule, i28.MatSnackBarModule, i1$1.MatDialogModule, i30.MatCheckboxModule, i31.MatCardModule, i32.MatDatepickerModule, i33.MatTimepickerModule, i34.MatBadgeModule, i35.MatExpansionModule, i36.MatFormFieldModule] });
2394
+ }
2395
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, decorators: [{
2396
+ type: NgModule,
2397
+ args: [{
2398
+ declarations: [...FX_COMPONENTS, ...DIALOGS_COMPONENT],
2399
+ imports: [
2400
+ CommonModule,
2401
+ FormsModule,
2402
+ ReactiveFormsModule,
2403
+ OwlDateTimeModule,
2404
+ OwlNativeDateTimeModule,
2405
+ HasPermissionDirective,
2406
+ NgHeroiconsModule,
2407
+ NgxEchartsModule.forRoot({ echarts: () => import('echarts') }),
2408
+ ...MATERIAL_MODULE,
2409
+ ],
2410
+ exports: [
2411
+ // Component
2412
+ ...FX_COMPONENTS,
2413
+ ...DIALOGS_COMPONENT,
2414
+ // Module
2415
+ FormsModule,
2416
+ ReactiveFormsModule,
2417
+ OwlDateTimeModule,
2418
+ OwlNativeDateTimeModule,
2419
+ HasPermissionDirective,
2420
+ NgHeroiconsModule,
2421
+ ...MATERIAL_MODULE,
2422
+ ],
2423
+ providers: [
2424
+ importProvidersFrom(NgHeroiconsModule.forRoot()),
2425
+ // { provide: OWL_DATE_TIME_FORMATS, useValue: MY_FORMATS },
2426
+ ],
2427
+ }]
2428
+ }] });
2429
+
2430
+ /*
2431
+ * Public API Surface of ui
2432
+ */
2433
+
2434
+ /**
2435
+ * Generated bundle index. Do not edit.
2436
+ */
2437
+
2438
+ export { AuthInterceptor, AuthStateService, BaseComponent, BaseDialogComponent, BaseResolver, BaseTableComponent, BreadcrumbService, ButtonComponent, ChartComponent, CheckboxComponent, ConfirmationDialogComponent, DatetimePicker, DndUploadComponent, FxLoadingService, FxStorageService, FxToastrService, FxUtils, HasPermissionDirective, HeroIconComponent, HttpLoaderFactory, HttpWrapper, InputComponent, LoadingPanel, MY_FORMATS, PermissionGuard, PermissionService, RadioButtonComponent, RadioButtonToggleComponent, SearchBarComponent, SelectComponent, SliderComponent, SwitchComponent, TabComponent, TabGroupComponent, TagComponent, ToastComponent, ToastContainerComponent, TranslationModule, TranslationService, UiModule };
2439
+ //# sourceMappingURL=fxlt-common-ui.mjs.map