@foxeltech/angular-ui 0.0.13 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BeVietnamPro/BeVietnamPro-Bold.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-ExtraLight.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Light.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Medium.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Regular.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-SemiBold.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Thin.woff2 +0 -0
- package/SpaceMono-Regular.woff2 +0 -0
- package/components.css +5 -0
- package/dm-sans/DMSans-Bold.woff2 +0 -0
- package/dm-sans/DMSans-Light.woff2 +0 -0
- package/dm-sans/DMSans-Medium.woff2 +0 -0
- package/dm-sans/DMSans-Regular.woff2 +0 -0
- package/dm-sans/DMSans-SemiBold.woff2 +0 -0
- package/dm-sans/DMSans-Thin.woff2 +0 -0
- package/fesm2022/foxeltech-angular-ui.mjs +1070 -264
- package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
- package/fonts.css +68 -34
- package/index.d.ts +536 -139
- package/orbitron/Orbitron-Bold.woff2 +0 -0
- package/orbitron/Orbitron-Medium.woff2 +0 -0
- package/orbitron/Orbitron-Regular.woff2 +0 -0
- package/orbitron/Orbitron-SemiBold.woff2 +0 -0
- package/package.json +6 -6
- package/roboto/Roboto-Black.woff2 +0 -0
- package/roboto/Roboto-BlackItalic.woff2 +0 -0
- package/roboto/Roboto-Bold.woff2 +0 -0
- package/roboto/Roboto-BoldCondensed.woff2 +0 -0
- package/roboto/Roboto-BoldCondensedItalic.woff2 +0 -0
- package/roboto/Roboto-BoldItalic.woff2 +0 -0
- package/roboto/Roboto-Condensed.woff2 +0 -0
- package/roboto/Roboto-CondensedItalic.woff2 +0 -0
- package/roboto/Roboto-Italic.woff2 +0 -0
- package/roboto/Roboto-Light.woff2 +0 -0
- package/roboto/Roboto-LightItalic.woff2 +0 -0
- package/roboto/Roboto-Medium.woff2 +0 -0
- package/roboto/Roboto-MediumItalic.woff2 +0 -0
- package/roboto/Roboto-Regular.woff2 +0 -0
- package/roboto/Roboto-Thin.woff2 +0 -0
- package/roboto/Roboto-ThinItalic.woff2 +0 -0
- package/src/lib/styles/components.css +5 -0
- package/src/lib/styles/fonts.css +68 -34
- package/src/lib/styles/tailwind.css +1 -1
- package/src/lib/ui/components/button/button.component.scss +0 -0
- package/src/lib/ui/components/chart/chart.component.scss +49 -0
- package/src/lib/ui/components/checkbox/checkbox.component.scss +0 -0
- package/src/lib/ui/components/circle-progress-bar/circle-progress-bar.component.scss +0 -0
- package/src/lib/ui/components/datetime-picker/datetime-picker.component.scss +144 -0
- package/src/lib/ui/components/dnd-upload/dnd-upload.component.scss +87 -0
- package/src/lib/ui/components/drawer/drawer.component.scss +131 -0
- package/src/lib/ui/components/empty-state/empty-state.component.html +9 -0
- package/src/lib/ui/components/filter-chips/filter-chips.component.html +12 -0
- package/src/lib/ui/components/flow-connection/flow-connection.component.scss +0 -0
- package/src/lib/ui/components/hero-icon/hero-icon.component.scss +0 -0
- package/src/lib/ui/components/info-field/info-field.component.html +4 -0
- package/src/lib/ui/components/kanban-board/kanban-board.component.scss +67 -0
- package/src/lib/ui/components/loading-panel/loading-panel.component.scss +0 -0
- package/src/lib/ui/components/meter/meter.component.html +15 -0
- package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.scss +0 -0
- package/src/lib/ui/components/rich-text-area/rich-text-area.component.scss +15 -0
- package/src/lib/ui/components/search-bar/search-bar.component.scss +0 -0
- package/src/lib/ui/components/section-card/section-card.component.html +9 -0
- package/src/lib/ui/components/select/select.component.css +38 -3
- package/src/lib/ui/components/severity-badges/severity-badges.component.html +10 -0
- package/src/lib/ui/components/skeleton-detail/skeleton-detail.component.html +22 -0
- package/src/lib/ui/components/skeleton-list/skeleton-list.component.html +12 -0
- package/src/lib/ui/components/skeleton-table-loading/skeleton-table-loading.component.scss +0 -0
- package/src/lib/ui/components/slider/slider.component.scss +0 -0
- package/src/lib/ui/components/stat-cards/stat-cards.component.html +18 -0
- package/src/lib/ui/components/switch/switch.component.scss +0 -0
- package/src/lib/ui/components/tab-component/tab.component.scss +0 -0
- package/src/lib/ui/components/tab-group/tab-group.component.scss +48 -0
- package/src/lib/ui/components/table-cell/table-cell.component.scss +0 -0
- package/src/lib/ui/components/tag/tag.component.scss +0 -0
- package/src/lib/ui/components/toast/toast.component.scss +0 -0
- package/src/lib/ui/components/toast-container/toast-container.component.scss +0 -0
- package/src/lib/ui/components/tree-diagram/tree-diagram.component.scss +0 -0
- package/src/lib/ui/dialogs/confirmation/confirmation.component.scss +0 -0
- package/tailwind.config.js +18 -0
- package/tailwind.css +1 -1
- package/BeVietnamPro/BeVietnamPro-Bold.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-ExtraLight.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-Light.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-Medium.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-Regular.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-SemiBold.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-Thin.ttf +0 -0
- package/SpaceMono-Regular.ttf +0 -0
- package/dm-sans/DMSans-Bold.ttf +0 -0
- package/dm-sans/DMSans-Light.ttf +0 -0
- package/dm-sans/DMSans-Medium.ttf +0 -0
- package/dm-sans/DMSans-Regular.ttf +0 -0
- package/dm-sans/DMSans-SemiBold.ttf +0 -0
- package/dm-sans/DMSans-Thin.ttf +0 -0
- package/orbitron/Orbitron-Bold.ttf +0 -0
- package/orbitron/Orbitron-Medium.ttf +0 -0
- package/orbitron/Orbitron-Regular.ttf +0 -0
- package/orbitron/Orbitron-SemiBold.ttf +0 -0
- package/roboto/Roboto-Black.ttf +0 -0
- package/roboto/Roboto-BlackItalic.ttf +0 -0
- package/roboto/Roboto-Bold.ttf +0 -0
- package/roboto/Roboto-BoldCondensed.ttf +0 -0
- package/roboto/Roboto-BoldCondensedItalic.ttf +0 -0
- package/roboto/Roboto-BoldItalic.ttf +0 -0
- package/roboto/Roboto-Condensed.ttf +0 -0
- package/roboto/Roboto-CondensedItalic.ttf +0 -0
- package/roboto/Roboto-Italic.ttf +0 -0
- package/roboto/Roboto-Light.ttf +0 -0
- package/roboto/Roboto-LightItalic.ttf +0 -0
- package/roboto/Roboto-Medium.ttf +0 -0
- package/roboto/Roboto-MediumItalic.ttf +0 -0
- package/roboto/Roboto-Regular.ttf +0 -0
- package/roboto/Roboto-Thin.ttf +0 -0
- package/roboto/Roboto-ThinItalic.ttf +0 -0
|
@@ -1,76 +1,81 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Directive, Input, Component, createComponent, Injectable, ViewChild, Inject, EventEmitter, NgModule, HostListener, PLATFORM_ID, Output,
|
|
3
|
-
import * as
|
|
2
|
+
import { inject, DestroyRef, Injector, Directive, Input, Component, createComponent, Injectable, ViewChild, Inject, EventEmitter, NgModule, HostListener, PLATFORM_ID, Output, ChangeDetectionStrategy, TemplateRef, ContentChildren, ViewChildren, importProvidersFrom } from '@angular/core';
|
|
3
|
+
import * as i44 from '@angular/material/paginator';
|
|
4
4
|
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
|
5
|
-
import * as
|
|
5
|
+
import * as i45 from '@angular/material/table';
|
|
6
6
|
import { MatTableDataSource, MatTable, MatTableModule } from '@angular/material/table';
|
|
7
|
-
import * as
|
|
7
|
+
import * as i1$1 from '@angular/common';
|
|
8
8
|
import { isPlatformBrowser, CommonModule } from '@angular/common';
|
|
9
9
|
import * as i1 from '@dimaslz/ng-heroicons';
|
|
10
10
|
import { NgHeroiconsModule } from '@dimaslz/ng-heroicons';
|
|
11
11
|
import _, { clamp } from 'lodash';
|
|
12
|
-
import { Observable, firstValueFrom, Subject, debounceTime, BehaviorSubject, throwError,
|
|
13
|
-
import
|
|
12
|
+
import { Observable, firstValueFrom, Subject, debounceTime, distinctUntilChanged, BehaviorSubject, throwError, filter, takeUntil } from 'rxjs';
|
|
13
|
+
import moment from 'moment';
|
|
14
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
15
|
+
import * as i2 from '@angular/common/http';
|
|
14
16
|
import { HttpRequest, HttpClient } from '@angular/common/http';
|
|
15
|
-
import * as i1$
|
|
17
|
+
import * as i1$2 from '@angular/material/dialog';
|
|
16
18
|
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
17
|
-
import * as i1$
|
|
19
|
+
import * as i1$3 from '@ngx-translate/core';
|
|
18
20
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
|
19
21
|
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
|
20
|
-
import * as
|
|
21
|
-
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
22
|
+
import * as i2$1 from '@angular/forms';
|
|
23
|
+
import { NgControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
22
24
|
import * as i1$4 from '@angular/router';
|
|
23
25
|
import { NavigationEnd, RouterModule } from '@angular/router';
|
|
24
26
|
import { catchError } from 'rxjs/operators';
|
|
25
27
|
import * as signalR from '@microsoft/signalr';
|
|
26
|
-
import * as i3
|
|
28
|
+
import * as i3 from '@angular/material/select';
|
|
27
29
|
import { MatSelectModule } from '@angular/material/select';
|
|
28
|
-
import * as
|
|
30
|
+
import * as i41 from '@angular/material/radio';
|
|
29
31
|
import { MatRadioModule } from '@angular/material/radio';
|
|
30
|
-
import * as
|
|
32
|
+
import * as i42 from '@angular/material/button';
|
|
31
33
|
import { MatButtonModule } from '@angular/material/button';
|
|
32
|
-
import * as
|
|
34
|
+
import * as i43 from '@angular/material/icon';
|
|
33
35
|
import { MatIconModule } from '@angular/material/icon';
|
|
34
|
-
import * as
|
|
36
|
+
import * as i46 from '@angular/material/snack-bar';
|
|
35
37
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
36
|
-
import * as
|
|
38
|
+
import * as i48 from '@angular/material/checkbox';
|
|
37
39
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
38
|
-
import * as
|
|
40
|
+
import * as i49 from '@angular/material/card';
|
|
39
41
|
import { MatCardModule } from '@angular/material/card';
|
|
40
|
-
import * as
|
|
42
|
+
import * as i50 from '@angular/material/datepicker';
|
|
41
43
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
42
|
-
import * as
|
|
44
|
+
import * as i51 from '@angular/material/timepicker';
|
|
43
45
|
import { MatTimepickerModule } from '@angular/material/timepicker';
|
|
44
|
-
import * as
|
|
46
|
+
import * as i52 from '@angular/material/badge';
|
|
45
47
|
import { MatBadgeModule } from '@angular/material/badge';
|
|
46
|
-
import * as
|
|
48
|
+
import * as i53 from '@angular/material/expansion';
|
|
47
49
|
import { MatExpansionModule } from '@angular/material/expansion';
|
|
48
|
-
import * as
|
|
50
|
+
import * as i54 from '@angular/material/form-field';
|
|
49
51
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
50
|
-
import * as
|
|
52
|
+
import * as i55 from '@angular/material/menu';
|
|
51
53
|
import { MatMenuModule } from '@angular/material/menu';
|
|
52
|
-
import * as
|
|
54
|
+
import * as i56 from '@angular/material/tooltip';
|
|
53
55
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
54
|
-
import * as i2$
|
|
56
|
+
import * as i2$3 from '@angular/cdk/drag-drop';
|
|
55
57
|
import { DragDropModule, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
|
|
56
|
-
import * as
|
|
58
|
+
import * as i2$2 from '@danielmoncada/angular-datetime-picker';
|
|
57
59
|
import { OwlDateTimeModule, OwlNativeDateTimeModule, OWL_DATE_TIME_FORMATS } from '@danielmoncada/angular-datetime-picker';
|
|
58
60
|
import * as i1$5 from 'ngx-echarts';
|
|
59
61
|
import { NgxEchartsModule } from 'ngx-echarts';
|
|
60
|
-
import
|
|
61
|
-
import * as i29 from 'ngx-vflow';
|
|
62
|
+
import * as i38 from 'ngx-vflow';
|
|
62
63
|
import { Vflow } from 'ngx-vflow';
|
|
63
|
-
import { trigger, state,
|
|
64
|
+
import { trigger, state, transition, style, animate } from '@angular/animations';
|
|
64
65
|
import { OwlMomentDateTimeModule } from '@danielmoncada/angular-datetime-picker-moment-adapter';
|
|
65
66
|
|
|
66
67
|
class BaseComponent {
|
|
67
68
|
injector;
|
|
69
|
+
/** Teardown hook for subscriptions: takeUntilDestroyed(this.destroyRef). */
|
|
70
|
+
destroyRef = inject(DestroyRef);
|
|
68
71
|
constructor(injector) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
// Some subclasses historically passed non-injector values (e.g. dialog
|
|
73
|
+
// data) to super(); fall back to the component's own injector so
|
|
74
|
+
// this.injector.get(...) always works.
|
|
75
|
+
this.injector = injector instanceof Injector ? injector : inject(Injector);
|
|
73
76
|
}
|
|
77
|
+
// eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method -- subclasses across host apps call super.ngOnDestroy(); removing this breaks them at runtime
|
|
78
|
+
ngOnDestroy() { }
|
|
74
79
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseComponent, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive });
|
|
75
80
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: BaseComponent, isStandalone: true, ngImport: i0 });
|
|
76
81
|
}
|
|
@@ -114,7 +119,7 @@ class ToastComponent {
|
|
|
114
119
|
message = '';
|
|
115
120
|
type;
|
|
116
121
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
117
|
-
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-[400px] 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:
|
|
122
|
+
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-[400px] 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: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
118
123
|
}
|
|
119
124
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastComponent, decorators: [{
|
|
120
125
|
type: Component,
|
|
@@ -129,6 +134,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
129
134
|
type: Input
|
|
130
135
|
}] } });
|
|
131
136
|
|
|
137
|
+
// import { ToastData } from '../../../../public-api';
|
|
132
138
|
class ToastContainerComponent {
|
|
133
139
|
ref;
|
|
134
140
|
toasts = [];
|
|
@@ -240,7 +246,7 @@ class FxUtils {
|
|
|
240
246
|
const keys = [];
|
|
241
247
|
const promises = [];
|
|
242
248
|
for (const i in value) {
|
|
243
|
-
if (
|
|
249
|
+
if (Object.prototype.hasOwnProperty.call(value, i)) {
|
|
244
250
|
keys.push(i);
|
|
245
251
|
this.preresolve(promises, value[i], i);
|
|
246
252
|
}
|
|
@@ -348,11 +354,24 @@ class FxUtils {
|
|
|
348
354
|
}
|
|
349
355
|
return `${_.get(err, 'error.code')}: ${message}`;
|
|
350
356
|
}
|
|
351
|
-
|
|
357
|
+
/**
|
|
358
|
+
* Resolve a theme channel triple (`--danger: 255 122 0`) to a CSS colour.
|
|
359
|
+
* Pass `legacyCommaSyntax: true` for canvas/ECharts consumers: canvas paints
|
|
360
|
+
* both forms, but zrender's colour parser can't read the CSS4 space syntax
|
|
361
|
+
* and renders slices black on hover when given it.
|
|
362
|
+
*/
|
|
363
|
+
static convertColorFromVariable(name, alpha = 1, options) {
|
|
352
364
|
const value = getComputedStyle(document.body)
|
|
353
365
|
.getPropertyValue(name)
|
|
354
366
|
.trim()
|
|
355
367
|
.replace(/\s+/g, ' ');
|
|
368
|
+
if (options?.legacyCommaSyntax) {
|
|
369
|
+
const [r, g, b] = value.replace(/[/,]/g, ' ').split(/\s+/).filter(Boolean);
|
|
370
|
+
if (r === undefined || g === undefined || b === undefined) {
|
|
371
|
+
return `rgba(148, 163, 184, ${alpha})`;
|
|
372
|
+
}
|
|
373
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
374
|
+
}
|
|
356
375
|
return value ? `rgba(${value} / ${alpha})` : `rgba(255 255 255 / ${alpha})`;
|
|
357
376
|
}
|
|
358
377
|
static getTagClass(key, isCriticalExist = true) {
|
|
@@ -397,6 +416,90 @@ class FxUtils {
|
|
|
397
416
|
const isEmail = emailRegex.test(value);
|
|
398
417
|
return isEmail;
|
|
399
418
|
}
|
|
419
|
+
/** Safe deep accessor with the org-wide empty placeholder. */
|
|
420
|
+
static value(model, key, defaultValue = '---') {
|
|
421
|
+
return _.get(model, key, defaultValue);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Severity weight for ordering — kept next to getTagClass so ordering and
|
|
425
|
+
* colouring can never drift apart.
|
|
426
|
+
*/
|
|
427
|
+
static severityWeight(level) {
|
|
428
|
+
switch (String(level ?? '').toUpperCase()) {
|
|
429
|
+
case 'CRITICAL':
|
|
430
|
+
return 5;
|
|
431
|
+
case 'HIGH':
|
|
432
|
+
return 4;
|
|
433
|
+
case 'MEDIUM':
|
|
434
|
+
return 3;
|
|
435
|
+
case 'LOW':
|
|
436
|
+
return 2;
|
|
437
|
+
case 'INFO':
|
|
438
|
+
case 'INFORMATION':
|
|
439
|
+
return 1;
|
|
440
|
+
default:
|
|
441
|
+
return 0;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
/** Org-wide date-time rendering (DD/MM/YYYY HH:mm:ss, local time). */
|
|
445
|
+
static formatDateTime(time) {
|
|
446
|
+
if (FxUtils.isNull(time))
|
|
447
|
+
return '';
|
|
448
|
+
return moment.parseZone(time).local().format('DD/MM/YYYY HH:mm:ss');
|
|
449
|
+
}
|
|
450
|
+
/** Seconds → compact duration ("2d 4h", "3h 12m", "45s"). */
|
|
451
|
+
static formatDuration(totalSeconds) {
|
|
452
|
+
const sec = Number(totalSeconds);
|
|
453
|
+
if (!_.isFinite(sec) || sec < 0)
|
|
454
|
+
return '';
|
|
455
|
+
const d = Math.floor(sec / 86400);
|
|
456
|
+
const h = Math.floor((sec % 86400) / 3600);
|
|
457
|
+
const m = Math.floor((sec % 3600) / 60);
|
|
458
|
+
const s = Math.floor(sec % 60);
|
|
459
|
+
if (d > 0)
|
|
460
|
+
return h > 0 ? `${d}d ${h}h` : `${d}d`;
|
|
461
|
+
if (h > 0)
|
|
462
|
+
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
463
|
+
if (m > 0)
|
|
464
|
+
return s > 0 ? `${m}m ${s}s` : `${m}m`;
|
|
465
|
+
return `${s}s`;
|
|
466
|
+
}
|
|
467
|
+
/** Relative time within the last 24h ("3 hours ago"), else DD/MM/YYYY. */
|
|
468
|
+
static formatRelative(time) {
|
|
469
|
+
if (FxUtils.isNull(time))
|
|
470
|
+
return '';
|
|
471
|
+
const m = moment.parseZone(time).local();
|
|
472
|
+
return moment().diff(m, 'hours') < 24 ? m.fromNow() : m.format('DD/MM/YYYY');
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Normalize a snake_case + protobuf-Long API payload for camelCase binding:
|
|
476
|
+
* - genuine snake_case keys -> camelCase (data-as-key entries such as DLL
|
|
477
|
+
* names like "kernel32.dll" are left untouched by the strict regex);
|
|
478
|
+
* - Long-encoded numbers `{ high, low, unsigned }` -> plain number.
|
|
479
|
+
*/
|
|
480
|
+
static camelizeDeep(input) {
|
|
481
|
+
if (Array.isArray(input)) {
|
|
482
|
+
return input.map((v) => FxUtils.camelizeDeep(v));
|
|
483
|
+
}
|
|
484
|
+
if (input !== null && typeof input === 'object') {
|
|
485
|
+
const keys = Object.keys(input);
|
|
486
|
+
if (keys.length === 3 &&
|
|
487
|
+
keys.includes('high') &&
|
|
488
|
+
keys.includes('low') &&
|
|
489
|
+
keys.includes('unsigned')) {
|
|
490
|
+
const high = Number(input.high) || 0;
|
|
491
|
+
const low = Number(input.low) || 0;
|
|
492
|
+
return high * 4294967296 + (low >>> 0);
|
|
493
|
+
}
|
|
494
|
+
const out = {};
|
|
495
|
+
for (const k of keys) {
|
|
496
|
+
const nk = /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(k) ? _.camelCase(k) : k;
|
|
497
|
+
out[nk] = FxUtils.camelizeDeep(input[k]);
|
|
498
|
+
}
|
|
499
|
+
return out;
|
|
500
|
+
}
|
|
501
|
+
return input;
|
|
502
|
+
}
|
|
400
503
|
static formatSizeUnits(bytes) {
|
|
401
504
|
if (bytes >= 1073741824) {
|
|
402
505
|
return (bytes / 1073741824).toFixed(2) + ' GB';
|
|
@@ -424,6 +527,15 @@ class HttpWrapper {
|
|
|
424
527
|
this.http = http;
|
|
425
528
|
this.baseURL = baseURL;
|
|
426
529
|
}
|
|
530
|
+
/**
|
|
531
|
+
* Hook applied to every resolved response (get/post/put/delete and all verb
|
|
532
|
+
* helpers built on them). Default is identity; override to normalize a
|
|
533
|
+
* backend convention once (e.g. FxUtils.camelizeDeep for snake_case +
|
|
534
|
+
* protobuf-Long payloads) instead of wrapping each method.
|
|
535
|
+
*/
|
|
536
|
+
transformResponse(res) {
|
|
537
|
+
return res;
|
|
538
|
+
}
|
|
427
539
|
addCredentials(options = {}) {
|
|
428
540
|
return {
|
|
429
541
|
withCredentials: true,
|
|
@@ -437,16 +549,16 @@ class HttpWrapper {
|
|
|
437
549
|
...params,
|
|
438
550
|
},
|
|
439
551
|
};
|
|
440
|
-
return firstValueFrom(this.http.get(this.baseURL + url, options));
|
|
552
|
+
return this.transformResponse(await firstValueFrom(this.http.get(this.baseURL + url, options)));
|
|
441
553
|
}
|
|
442
554
|
async post(url, body = {}, options = {}) {
|
|
443
|
-
return firstValueFrom(this.http.post(this.baseURL + url, body, this.addCredentials(options)));
|
|
555
|
+
return this.transformResponse(await firstValueFrom(this.http.post(this.baseURL + url, body, this.addCredentials(options))));
|
|
444
556
|
}
|
|
445
557
|
async put(url, body, options = {}) {
|
|
446
|
-
return firstValueFrom(this.http.put(this.baseURL + url, body, this.addCredentials(options)));
|
|
558
|
+
return this.transformResponse(await firstValueFrom(this.http.put(this.baseURL + url, body, this.addCredentials(options))));
|
|
447
559
|
}
|
|
448
560
|
async delete(url, options = {}) {
|
|
449
|
-
return firstValueFrom(this.http.delete(this.baseURL + url, this.addCredentials(options)));
|
|
561
|
+
return this.transformResponse(await firstValueFrom(this.http.delete(this.baseURL + url, this.addCredentials(options))));
|
|
450
562
|
}
|
|
451
563
|
upload(url, body, options = {}) {
|
|
452
564
|
const req = new HttpRequest('POST', this.baseURL + url, body, {
|
|
@@ -526,7 +638,9 @@ class BaseTableComponent extends BaseComponent {
|
|
|
526
638
|
this.toastr = injector.get(FxToastrService);
|
|
527
639
|
}
|
|
528
640
|
ngOnInit() {
|
|
529
|
-
this.keywordChange
|
|
641
|
+
this.keywordChange$
|
|
642
|
+
.pipe(debounceTime(300), distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))
|
|
643
|
+
.subscribe(async () => {
|
|
530
644
|
await this.refresh();
|
|
531
645
|
});
|
|
532
646
|
this.dataSourcePlaceholder = Array(this.pageSize).fill({});
|
|
@@ -535,7 +649,7 @@ class BaseTableComponent extends BaseComponent {
|
|
|
535
649
|
init() { }
|
|
536
650
|
ngAfterViewInit() {
|
|
537
651
|
if (this.paginator && this.paginator.page) {
|
|
538
|
-
this.paginator.page.subscribe((event) => {
|
|
652
|
+
this.paginator.page.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
|
|
539
653
|
this.onPageChange(event);
|
|
540
654
|
});
|
|
541
655
|
}
|
|
@@ -548,23 +662,50 @@ class BaseTableComponent extends BaseComponent {
|
|
|
548
662
|
}
|
|
549
663
|
await this.fetch();
|
|
550
664
|
}
|
|
665
|
+
/**
|
|
666
|
+
* Where the list is fetched from. Default (null) keeps the legacy behavior
|
|
667
|
+
* of calling `api.search()` (GET /search) untouched. Subclasses whose list
|
|
668
|
+
* lives elsewhere override this instead of re-implementing fetch() — and
|
|
669
|
+
* keep the stale-response sequence guard for free.
|
|
670
|
+
*/
|
|
671
|
+
listRequest() {
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
/** Result keys the list/total are read from. Override alongside listRequest(). */
|
|
675
|
+
listKey = 'data';
|
|
676
|
+
totalKey = 'total';
|
|
551
677
|
setDataSource(result) {
|
|
552
|
-
this.dataSource.data = _.get(result,
|
|
553
|
-
this.total = _.get(result,
|
|
678
|
+
this.dataSource.data = _.get(result, this.listKey);
|
|
679
|
+
this.total = _.get(result, this.totalKey);
|
|
554
680
|
}
|
|
681
|
+
_fetchSeq = 0;
|
|
555
682
|
async fetch() {
|
|
683
|
+
// Sequence guard: without it a slow earlier request could resolve after
|
|
684
|
+
// a newer one and overwrite the table with stale data.
|
|
685
|
+
const seq = ++this._fetchSeq;
|
|
556
686
|
this.loading = true;
|
|
557
687
|
try {
|
|
558
688
|
const params = { page: (this.page ?? 0) + 1, pageSize: this.pageSize, ...this.filters };
|
|
559
|
-
const
|
|
689
|
+
const req = this.listRequest();
|
|
690
|
+
const result = req
|
|
691
|
+
? req.method === 'post'
|
|
692
|
+
? await this.api.post(req.url, params)
|
|
693
|
+
: await this.api.get(req.url, params)
|
|
694
|
+
: await this.api.search(params);
|
|
695
|
+
if (seq !== this._fetchSeq)
|
|
696
|
+
return;
|
|
560
697
|
this.setDataSource(result);
|
|
561
698
|
}
|
|
562
699
|
catch (err) {
|
|
700
|
+
if (seq !== this._fetchSeq)
|
|
701
|
+
return;
|
|
563
702
|
this.toastr.error(FxUtils.parseError(err));
|
|
564
703
|
}
|
|
565
704
|
finally {
|
|
566
|
-
this.
|
|
567
|
-
|
|
705
|
+
if (seq === this._fetchSeq) {
|
|
706
|
+
this.loading = false;
|
|
707
|
+
this.ref.detectChanges();
|
|
708
|
+
}
|
|
568
709
|
}
|
|
569
710
|
}
|
|
570
711
|
async onPageChange(event) {
|
|
@@ -596,7 +737,7 @@ class BaseTableComponent extends BaseComponent {
|
|
|
596
737
|
if (size == '100%') {
|
|
597
738
|
panelClass = 'fx-fullsize-dialog';
|
|
598
739
|
}
|
|
599
|
-
|
|
740
|
+
const instance = this.modal.open(dialog, {
|
|
600
741
|
panelClass: panelClass,
|
|
601
742
|
autoFocus: false,
|
|
602
743
|
width: size,
|
|
@@ -631,7 +772,7 @@ class BaseTableComponent extends BaseComponent {
|
|
|
631
772
|
if (size == '100%') {
|
|
632
773
|
panelClass = 'fx-fullsize-dialog';
|
|
633
774
|
}
|
|
634
|
-
|
|
775
|
+
const instance = this.modal.open(dialog, {
|
|
635
776
|
panelClass: panelClass,
|
|
636
777
|
autoFocus: false,
|
|
637
778
|
width: size,
|
|
@@ -666,7 +807,7 @@ class BaseTableComponent extends BaseComponent {
|
|
|
666
807
|
if (size == '100%') {
|
|
667
808
|
panelClass = 'fx-fullsize-dialog';
|
|
668
809
|
}
|
|
669
|
-
|
|
810
|
+
const instance = this.modal.open(dialog, {
|
|
670
811
|
panelClass: panelClass,
|
|
671
812
|
autoFocus: false,
|
|
672
813
|
width: size,
|
|
@@ -685,13 +826,16 @@ class BaseTableComponent extends BaseComponent {
|
|
|
685
826
|
});
|
|
686
827
|
}
|
|
687
828
|
async delete(model) {
|
|
829
|
+
const conf = _.get(this.config, 'delete');
|
|
830
|
+
const dialog = _.get(conf, 'dialog');
|
|
831
|
+
if (_.isNil(conf) || _.isNil(dialog)) {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
688
834
|
if (this._lock) {
|
|
689
835
|
return;
|
|
690
836
|
}
|
|
691
837
|
this._lock = true;
|
|
692
838
|
try {
|
|
693
|
-
const conf = _.get(this.config, 'delete');
|
|
694
|
-
const dialog = _.get(conf, 'dialog');
|
|
695
839
|
const dialogRef = this.modal.open(dialog, {
|
|
696
840
|
panelClass: 'fx-dialog',
|
|
697
841
|
autoFocus: false,
|
|
@@ -746,7 +890,7 @@ class BaseTableComponent extends BaseComponent {
|
|
|
746
890
|
this.toastr.success(_.get(this.config, 'updateStatus.message', 'Update Success'));
|
|
747
891
|
}
|
|
748
892
|
catch (err) {
|
|
749
|
-
this.toastr.
|
|
893
|
+
this.toastr.error(FxUtils.parseError(err));
|
|
750
894
|
}
|
|
751
895
|
finally {
|
|
752
896
|
await this.refresh();
|
|
@@ -782,20 +926,24 @@ class BaseDialogComponent extends BaseComponent {
|
|
|
782
926
|
formChangesSubscription;
|
|
783
927
|
onSubmit = true;
|
|
784
928
|
constructor(ref, bindings, toastr, api, dialog) {
|
|
785
|
-
super(
|
|
929
|
+
super();
|
|
786
930
|
this.ref = ref;
|
|
787
931
|
this.bindings = bindings;
|
|
788
932
|
this.toastr = toastr;
|
|
789
933
|
this.api = api;
|
|
790
934
|
this.dialog = dialog;
|
|
791
|
-
|
|
935
|
+
// Deep clone: a shallow clone let dialog edits mutate nested fields of
|
|
936
|
+
// the live table row even when the user cancelled.
|
|
937
|
+
this.model = _.cloneDeep(_.get(bindings, 'data'));
|
|
792
938
|
this.method = _.get(bindings, 'method');
|
|
793
939
|
this.title = _.get(bindings, 'title');
|
|
794
940
|
this.disabled = _.get(bindings, 'disabled');
|
|
795
941
|
this.message = _.get(bindings, 'message');
|
|
796
942
|
this.resolve = _.get(bindings, 'resolve');
|
|
797
943
|
}
|
|
944
|
+
// eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method -- subclasses across host apps call super lifecycle methods; removing these breaks them at runtime
|
|
798
945
|
ngAfterViewInit() { }
|
|
946
|
+
// eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method -- see ngAfterViewInit note
|
|
799
947
|
ngOnInit() { }
|
|
800
948
|
async accept(form, params = null) {
|
|
801
949
|
if (form.invalid) {
|
|
@@ -873,15 +1021,15 @@ class BaseDialogComponent extends BaseComponent {
|
|
|
873
1021
|
validate() {
|
|
874
1022
|
return true;
|
|
875
1023
|
}
|
|
876
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseDialogComponent, deps: [{ token: i1$
|
|
1024
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseDialogComponent, deps: [{ token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA }, { token: FxToastrService }, { token: HttpWrapper }, { token: i1$2.MatDialog }], target: i0.ɵɵFactoryTarget.Directive });
|
|
877
1025
|
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 });
|
|
878
1026
|
}
|
|
879
1027
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseDialogComponent, decorators: [{
|
|
880
1028
|
type: Directive
|
|
881
|
-
}], ctorParameters: () => [{ type: i1$
|
|
1029
|
+
}], ctorParameters: () => [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
|
|
882
1030
|
type: Inject,
|
|
883
1031
|
args: [MAT_DIALOG_DATA]
|
|
884
|
-
}] }, { type: FxToastrService }, { type: HttpWrapper }, { type: i1$
|
|
1032
|
+
}] }, { type: FxToastrService }, { type: HttpWrapper }, { type: i1$2.MatDialog }], propDecorators: { ngForm: [{
|
|
885
1033
|
type: ViewChild,
|
|
886
1034
|
args: ['f', { static: true }]
|
|
887
1035
|
}] } });
|
|
@@ -923,6 +1071,293 @@ class BaseResolver {
|
|
|
923
1071
|
}
|
|
924
1072
|
}
|
|
925
1073
|
|
|
1074
|
+
class FxStorageService {
|
|
1075
|
+
resolve(key, value) {
|
|
1076
|
+
if (FxUtils.isNotNull(value)) {
|
|
1077
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
1078
|
+
}
|
|
1079
|
+
const loc = localStorage.getItem(key);
|
|
1080
|
+
return loc ? JSON.parse(loc) : undefined;
|
|
1081
|
+
}
|
|
1082
|
+
remove(key) {
|
|
1083
|
+
localStorage.removeItem(key);
|
|
1084
|
+
}
|
|
1085
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1086
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, providedIn: 'root' });
|
|
1087
|
+
}
|
|
1088
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, decorators: [{
|
|
1089
|
+
type: Injectable,
|
|
1090
|
+
args: [{
|
|
1091
|
+
providedIn: 'root',
|
|
1092
|
+
}]
|
|
1093
|
+
}] });
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Functional replacement for the copy-pasted list-resolver class:
|
|
1097
|
+
* starts the loading overlay, runs one API request, and on failure stops the
|
|
1098
|
+
* overlay and shows a parsed error toast — the exact convention every
|
|
1099
|
+
* BaseResolver subclass hand-rolls today. BaseResolver stays for existing
|
|
1100
|
+
* classes; new routes should use this factory.
|
|
1101
|
+
*
|
|
1102
|
+
* Usage:
|
|
1103
|
+
* resolve: { histories: fxListResolver(ScanManagementApi, (route, state, ctx) =>
|
|
1104
|
+
* ({ url: `/${route.paramMap.get('id')}/history`, params: { page: 1, pageSize: ctx.pageSize } })) }
|
|
1105
|
+
*/
|
|
1106
|
+
function fxListResolver(apiType, request) {
|
|
1107
|
+
return async (route, state) => {
|
|
1108
|
+
const api = inject(apiType);
|
|
1109
|
+
const loading = inject(FxLoadingService);
|
|
1110
|
+
const toastr = inject(FxToastrService);
|
|
1111
|
+
const storage = inject(FxStorageService);
|
|
1112
|
+
try {
|
|
1113
|
+
loading.start();
|
|
1114
|
+
const ctx = { pageSize: storage.resolve(state.url) || 10 };
|
|
1115
|
+
const req = request(route, state, ctx);
|
|
1116
|
+
if ((req.method ?? 'get') === 'post') {
|
|
1117
|
+
return await api.post(req.url, req.body ?? req.params ?? {});
|
|
1118
|
+
}
|
|
1119
|
+
return await api.get(req.url, req.params);
|
|
1120
|
+
}
|
|
1121
|
+
catch (err) {
|
|
1122
|
+
loading.stop();
|
|
1123
|
+
toastr.error(FxUtils.parseError(err), 'Error');
|
|
1124
|
+
return null;
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
* Factory for the 11-line HttpWrapper subclasses copy-pasted per endpoint.
|
|
1131
|
+
* Returns a distinct injectable class per call (so constructor injection by
|
|
1132
|
+
* type keeps working) without needing a decorator:
|
|
1133
|
+
*
|
|
1134
|
+
* export const ScanManagementApi = createApi(() => `${environment.baseService}/scarf/scan`);
|
|
1135
|
+
* // module: providers: [ScanManagementApi.provider]
|
|
1136
|
+
* // usage: constructor(private api: InstanceType<typeof ScanManagementApi>)
|
|
1137
|
+
*
|
|
1138
|
+
* `baseURL` accepts a string or a lazy factory (for environment-derived URLs).
|
|
1139
|
+
* An optional `transform` plugs into HttpWrapper.transformResponse — e.g.
|
|
1140
|
+
* FxUtils.camelizeDeep for snake_case/Long-encoded backends.
|
|
1141
|
+
*
|
|
1142
|
+
* IMPORTANT — when subclassing (`@Injectable() class X extends createApi(...)`),
|
|
1143
|
+
* declare an explicit `constructor(http: HttpClient) { super(http); }`.
|
|
1144
|
+
* The generated base carries no Angular factory metadata, so an inherited
|
|
1145
|
+
* constructor makes Ivy fall back to `new X()` with NO arguments: the class
|
|
1146
|
+
* silently gets `http = undefined` and every call fails at runtime while the
|
|
1147
|
+
* build stays green.
|
|
1148
|
+
*/
|
|
1149
|
+
function createApi(baseURL, transform) {
|
|
1150
|
+
class GeneratedApi extends HttpWrapper {
|
|
1151
|
+
static provider = {
|
|
1152
|
+
provide: GeneratedApi,
|
|
1153
|
+
useFactory: (http) => new GeneratedApi(http),
|
|
1154
|
+
deps: [HttpClient],
|
|
1155
|
+
};
|
|
1156
|
+
constructor(http) {
|
|
1157
|
+
super(http, typeof baseURL === 'function' ? baseURL() : baseURL);
|
|
1158
|
+
}
|
|
1159
|
+
transformResponse(res) {
|
|
1160
|
+
return transform ? transform(res) : res;
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
return GeneratedApi;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/**
|
|
1167
|
+
* Live-progress plumbing for server-paginated tables fed by hub events:
|
|
1168
|
+
* events matching a visible row are merged in place; events for rows that
|
|
1169
|
+
* are not in the list yet (a just-created record whose list read lags) are
|
|
1170
|
+
* buffered by key and replayed after a debounced, idle-capped background
|
|
1171
|
+
* re-fetch that merges by stable identity.
|
|
1172
|
+
*
|
|
1173
|
+
* The domain contract (event name, payload parsing, terminal semantics) is
|
|
1174
|
+
* injected via options — nothing app-specific lives here.
|
|
1175
|
+
*/
|
|
1176
|
+
class RealtimeTableSync {
|
|
1177
|
+
notifications;
|
|
1178
|
+
options;
|
|
1179
|
+
pending = new Map();
|
|
1180
|
+
syncTimer = null;
|
|
1181
|
+
idleSyncs = 0;
|
|
1182
|
+
stopped = false;
|
|
1183
|
+
subscription = null;
|
|
1184
|
+
constructor(notifications, options) {
|
|
1185
|
+
this.notifications = notifications;
|
|
1186
|
+
this.options = options;
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Subscribe to the hub event. Pass a DestroyRef to tie teardown to a
|
|
1190
|
+
* component lifecycle; stop() is still available for manual control.
|
|
1191
|
+
*/
|
|
1192
|
+
start(destroyRef) {
|
|
1193
|
+
const source = this.notifications.on$(this.options.event);
|
|
1194
|
+
const piped = destroyRef ? source.pipe(takeUntilDestroyed(destroyRef)) : source;
|
|
1195
|
+
this.stopped = false;
|
|
1196
|
+
this.subscription = piped.subscribe((raw) => this.handleEvent(raw));
|
|
1197
|
+
if (destroyRef) {
|
|
1198
|
+
destroyRef.onDestroy(() => this.stop());
|
|
1199
|
+
}
|
|
1200
|
+
return this;
|
|
1201
|
+
}
|
|
1202
|
+
stop() {
|
|
1203
|
+
this.stopped = true;
|
|
1204
|
+
this.subscription?.unsubscribe();
|
|
1205
|
+
this.subscription = null;
|
|
1206
|
+
if (this.syncTimer) {
|
|
1207
|
+
clearTimeout(this.syncTimer);
|
|
1208
|
+
this.syncTimer = null;
|
|
1209
|
+
}
|
|
1210
|
+
this.pending.clear();
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Replay buffered events onto the current rows (call from setDataSource so
|
|
1214
|
+
* a regular refresh also applies buffered progress). Returns true if
|
|
1215
|
+
* anything was applied.
|
|
1216
|
+
*/
|
|
1217
|
+
applyPending() {
|
|
1218
|
+
if (!this.pending.size)
|
|
1219
|
+
return false;
|
|
1220
|
+
let changed = false;
|
|
1221
|
+
for (const row of this.options.getRows()) {
|
|
1222
|
+
const key = this.options.matchKey(row);
|
|
1223
|
+
const event = this.pending.get(key);
|
|
1224
|
+
if (!event)
|
|
1225
|
+
continue;
|
|
1226
|
+
Object.assign(row, event.patch);
|
|
1227
|
+
this.pending.delete(key);
|
|
1228
|
+
changed = true;
|
|
1229
|
+
this.options.onApplied?.(row, event);
|
|
1230
|
+
}
|
|
1231
|
+
if (changed) {
|
|
1232
|
+
this.options.setRows([...this.options.getRows()]);
|
|
1233
|
+
}
|
|
1234
|
+
return changed;
|
|
1235
|
+
}
|
|
1236
|
+
handleEvent(raw) {
|
|
1237
|
+
const event = this.options.parse(raw);
|
|
1238
|
+
if (!event)
|
|
1239
|
+
return;
|
|
1240
|
+
const row = this.options.getRows().find((r) => this.options.matchKey(r) === event.key);
|
|
1241
|
+
if (!row) {
|
|
1242
|
+
// Not in the list yet (e.g. just-created record whose list read lags):
|
|
1243
|
+
// keep only the latest state per key and schedule a background sync.
|
|
1244
|
+
this.pending.set(event.key, event);
|
|
1245
|
+
this.scheduleSync();
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
this.idleSyncs = 0;
|
|
1249
|
+
Object.assign(row, event.patch);
|
|
1250
|
+
this.options.setRows([...this.options.getRows()]);
|
|
1251
|
+
this.options.onApplied?.(row, event);
|
|
1252
|
+
}
|
|
1253
|
+
scheduleSync() {
|
|
1254
|
+
const idleCap = this.options.idleCap ?? 3;
|
|
1255
|
+
if (this.syncTimer || this.stopped || this.idleSyncs >= idleCap)
|
|
1256
|
+
return;
|
|
1257
|
+
this.syncTimer = setTimeout(async () => {
|
|
1258
|
+
this.syncTimer = null;
|
|
1259
|
+
await this.syncFromServer();
|
|
1260
|
+
}, this.options.debounceMs ?? 1200);
|
|
1261
|
+
}
|
|
1262
|
+
async syncFromServer() {
|
|
1263
|
+
try {
|
|
1264
|
+
const result = await this.options.fetchList();
|
|
1265
|
+
if (this.stopped || !result)
|
|
1266
|
+
return;
|
|
1267
|
+
const existingByIdentity = new Map(this.options.getRows().map((r) => [this.options.identityKey(r), r]));
|
|
1268
|
+
const merged = result.rows.map((item) => {
|
|
1269
|
+
const existing = existingByIdentity.get(this.options.identityKey(item));
|
|
1270
|
+
if (existing) {
|
|
1271
|
+
Object.assign(existing, item); // reuse the object → stable identity
|
|
1272
|
+
return existing;
|
|
1273
|
+
}
|
|
1274
|
+
return item;
|
|
1275
|
+
});
|
|
1276
|
+
this.options.setRows(merged);
|
|
1277
|
+
if (result.total !== undefined) {
|
|
1278
|
+
this.options.onTotal?.(result.total);
|
|
1279
|
+
}
|
|
1280
|
+
const applied = this.applyPending();
|
|
1281
|
+
this.idleSyncs = applied ? 0 : this.idleSyncs + 1;
|
|
1282
|
+
if (this.pending.size) {
|
|
1283
|
+
this.scheduleSync();
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
catch {
|
|
1287
|
+
// Background sync is best-effort; the next event retries.
|
|
1288
|
+
this.idleSyncs += 1;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
const NEUTRAL_TEXT = 'text-text-secondary';
|
|
1294
|
+
const NEUTRAL_BG = 'bg-bg-hover';
|
|
1295
|
+
function hasVal(v) {
|
|
1296
|
+
if (_.isNil(v))
|
|
1297
|
+
return false;
|
|
1298
|
+
const s = String(v).trim();
|
|
1299
|
+
return s !== '' && s !== '-' && s !== '--';
|
|
1300
|
+
}
|
|
1301
|
+
/** Severity / risk-level string → tone (Critical & High → danger, Medium → warning, Low → success). */
|
|
1302
|
+
function severityTone(value) {
|
|
1303
|
+
if (!hasVal(value))
|
|
1304
|
+
return null;
|
|
1305
|
+
const t = FxUtils.getTagClass(String(value), true);
|
|
1306
|
+
return t === 'default' || t === 'discovery' ? null : t;
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* CVSS-style 0–10 score → tone, following the CVSS v3 qualitative bands
|
|
1310
|
+
* (≥9 Critical, ≥7 High, ≥4 Medium, else Low). Backends occasionally send a
|
|
1311
|
+
* 0–100 scale, so values > 10 are normalised down by /10.
|
|
1312
|
+
*/
|
|
1313
|
+
function scoreTone(score) {
|
|
1314
|
+
let n = Number(score);
|
|
1315
|
+
if (!_.isFinite(n) || n <= 0)
|
|
1316
|
+
return null;
|
|
1317
|
+
if (n > 10)
|
|
1318
|
+
n = n / 10;
|
|
1319
|
+
if (n >= 9)
|
|
1320
|
+
return 'critical';
|
|
1321
|
+
if (n >= 7)
|
|
1322
|
+
return 'danger';
|
|
1323
|
+
if (n >= 4)
|
|
1324
|
+
return 'warning';
|
|
1325
|
+
return 'success';
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Count of "bad" things → tone: 0 is good (success), anything positive is bad.
|
|
1329
|
+
* `positiveTone` sets how severe a non-zero count reads (default `danger`;
|
|
1330
|
+
* pass `critical` for the worst metrics, `warning` for milder ones).
|
|
1331
|
+
* Non-numeric values (e.g. "--") return null → neutral.
|
|
1332
|
+
*/
|
|
1333
|
+
function countTone(count, positiveTone = 'danger') {
|
|
1334
|
+
const n = Number(count);
|
|
1335
|
+
if (!_.isFinite(n))
|
|
1336
|
+
return null;
|
|
1337
|
+
return n > 0 ? positiveTone : 'success';
|
|
1338
|
+
}
|
|
1339
|
+
/** Tone → text colour class, with a neutral fallback when there is no value. */
|
|
1340
|
+
function toneText(tone) {
|
|
1341
|
+
return tone ? `text-${tone}` : NEUTRAL_TEXT;
|
|
1342
|
+
}
|
|
1343
|
+
/** Tone → background colour class, with a neutral fallback when there is no value. */
|
|
1344
|
+
function toneBg(tone) {
|
|
1345
|
+
return tone ? `bg-${tone}` : NEUTRAL_BG;
|
|
1346
|
+
}
|
|
1347
|
+
/** Tone → soft pill/badge classes (tinted bg + matching text), neutral fallback. */
|
|
1348
|
+
function toneBadge(tone) {
|
|
1349
|
+
return tone ? `bg-${tone}/10 text-${tone}` : `${NEUTRAL_BG} text-text-secondary`;
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Tone → resolved CSS colour string for ECharts / canvas where a Tailwind
|
|
1353
|
+
* class can't be used (e.g. per-slice pie `itemStyle.color`). Emits the
|
|
1354
|
+
* legacy comma syntax — see FxUtils.convertColorFromVariable.
|
|
1355
|
+
*/
|
|
1356
|
+
function toneColor(tone, alpha = 1) {
|
|
1357
|
+
const name = tone ? `--${tone}` : '--text-secondary';
|
|
1358
|
+
return FxUtils.convertColorFromVariable(name, alpha, { legacyCommaSyntax: true });
|
|
1359
|
+
}
|
|
1360
|
+
|
|
926
1361
|
class FxValidators {
|
|
927
1362
|
/**
|
|
928
1363
|
* Name fields: firstName, lastName, groupName, projectName, displayName
|
|
@@ -974,7 +1409,7 @@ class FxValidators {
|
|
|
974
1409
|
static validateCode(value) {
|
|
975
1410
|
if (!value || value.trim() === '')
|
|
976
1411
|
return null;
|
|
977
|
-
const regex = /^[a-zA-Z0-9_
|
|
1412
|
+
const regex = /^[a-zA-Z0-9_-]{1,50}$/;
|
|
978
1413
|
return regex.test(value) ? null : { invalidCode: 'Only letters, numbers, hyphens, and underscores are allowed (max 50 characters)' };
|
|
979
1414
|
}
|
|
980
1415
|
/**
|
|
@@ -984,7 +1419,7 @@ class FxValidators {
|
|
|
984
1419
|
static validateDomain(value) {
|
|
985
1420
|
if (!value || value.trim() === '')
|
|
986
1421
|
return null;
|
|
987
|
-
const regex = /^([a-zA-Z0-9]([a-zA-Z0-9
|
|
1422
|
+
const regex = /^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(:\d{1,5})?$/;
|
|
988
1423
|
return regex.test(value) ? null : { invalidDomain: 'Please enter a valid domain (e.g., mail.example.com)' };
|
|
989
1424
|
}
|
|
990
1425
|
/**
|
|
@@ -1109,13 +1544,13 @@ class TranslationService {
|
|
|
1109
1544
|
onLanguageChange(callback) {
|
|
1110
1545
|
this.currentLang$.subscribe(callback);
|
|
1111
1546
|
}
|
|
1112
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, deps: [{ token: i1$
|
|
1547
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, deps: [{ token: i1$3.TranslateService }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1113
1548
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, providedIn: 'root' });
|
|
1114
1549
|
}
|
|
1115
1550
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, decorators: [{
|
|
1116
1551
|
type: Injectable,
|
|
1117
1552
|
args: [{ providedIn: 'root' }]
|
|
1118
|
-
}], ctorParameters: () => [{ type: i1$
|
|
1553
|
+
}], ctorParameters: () => [{ type: i1$3.TranslateService }, { type: i2.HttpClient }] });
|
|
1119
1554
|
|
|
1120
1555
|
class PermissionService {
|
|
1121
1556
|
permissions = [];
|
|
@@ -1160,6 +1595,7 @@ class HasPermissionDirective {
|
|
|
1160
1595
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HasPermissionDirective, decorators: [{
|
|
1161
1596
|
type: Directive,
|
|
1162
1597
|
args: [{
|
|
1598
|
+
// eslint-disable-next-line @angular-eslint/directive-selector -- renaming is a breaking change for all host-app templates
|
|
1163
1599
|
selector: '[hasPermission]'
|
|
1164
1600
|
}]
|
|
1165
1601
|
}], ctorParameters: () => [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: PermissionService }], propDecorators: { hasPermission: [{
|
|
@@ -1196,15 +1632,16 @@ class TrimOnBlurDirective {
|
|
|
1196
1632
|
native.dispatchEvent(ev);
|
|
1197
1633
|
}
|
|
1198
1634
|
}
|
|
1199
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TrimOnBlurDirective, deps: [{ token: i0.ElementRef }, { token:
|
|
1635
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TrimOnBlurDirective, deps: [{ token: i0.ElementRef }, { token: i2$1.NgControl }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1200
1636
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: TrimOnBlurDirective, isStandalone: true, selector: "[appTrimOnBlur]", inputs: { collapseWhitespace: ["appTrimOnBlurCollapse", "collapseWhitespace"] }, host: { listeners: { "blur": "onBlur()" } }, ngImport: i0 });
|
|
1201
1637
|
}
|
|
1202
1638
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TrimOnBlurDirective, decorators: [{
|
|
1203
1639
|
type: Directive,
|
|
1204
1640
|
args: [{
|
|
1641
|
+
// eslint-disable-next-line @angular-eslint/directive-selector -- renaming is a breaking change for all host-app templates
|
|
1205
1642
|
selector: '[appTrimOnBlur]'
|
|
1206
1643
|
}]
|
|
1207
|
-
}], ctorParameters: () => [{ type: i0.ElementRef }, { type:
|
|
1644
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i2$1.NgControl }], propDecorators: { collapseWhitespace: [{
|
|
1208
1645
|
type: Input,
|
|
1209
1646
|
args: ['appTrimOnBlurCollapse']
|
|
1210
1647
|
}], onBlur: [{
|
|
@@ -1237,27 +1674,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
1237
1674
|
}]
|
|
1238
1675
|
}], ctorParameters: () => [{ type: PermissionService }, { type: i1$4.Router }] });
|
|
1239
1676
|
|
|
1240
|
-
class FxStorageService {
|
|
1241
|
-
resolve(key, value) {
|
|
1242
|
-
if (FxUtils.isNotNull(value)) {
|
|
1243
|
-
localStorage.setItem(key, JSON.stringify(value));
|
|
1244
|
-
}
|
|
1245
|
-
const loc = localStorage.getItem(key);
|
|
1246
|
-
return loc ? JSON.parse(loc) : undefined;
|
|
1247
|
-
}
|
|
1248
|
-
remove(key) {
|
|
1249
|
-
localStorage.removeItem(key);
|
|
1250
|
-
}
|
|
1251
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1252
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, providedIn: 'root' });
|
|
1253
|
-
}
|
|
1254
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, decorators: [{
|
|
1255
|
-
type: Injectable,
|
|
1256
|
-
args: [{
|
|
1257
|
-
providedIn: 'root',
|
|
1258
|
-
}]
|
|
1259
|
-
}] });
|
|
1260
|
-
|
|
1261
1677
|
class AuthStateService {
|
|
1262
1678
|
_isLoggedIn$ = new BehaviorSubject(null);
|
|
1263
1679
|
isLoggedIn$ = this._isLoggedIn$.asObservable();
|
|
@@ -1288,7 +1704,13 @@ class AuthInterceptor {
|
|
|
1288
1704
|
this.authState = authState;
|
|
1289
1705
|
}
|
|
1290
1706
|
intercept(req, next) {
|
|
1291
|
-
|
|
1707
|
+
// Multi-tenant: all tenant domains hit one shared API endpoint, so the
|
|
1708
|
+
// backend can no longer resolve the tenant from the Host header. Send the
|
|
1709
|
+
// originating domain explicitly for tenant resolution.
|
|
1710
|
+
const cloned = req.clone({
|
|
1711
|
+
withCredentials: true,
|
|
1712
|
+
setHeaders: { 'X-Tenant-Domain': window.location.hostname },
|
|
1713
|
+
});
|
|
1292
1714
|
return next.handle(cloned).pipe(catchError((error) => {
|
|
1293
1715
|
if (error.status === 401 && !this.handlingUnauthorized) {
|
|
1294
1716
|
this.handlingUnauthorized = true;
|
|
@@ -1388,7 +1810,7 @@ class QuillStyleLoaderService {
|
|
|
1388
1810
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: QuillStyleLoaderService, decorators: [{
|
|
1389
1811
|
type: Injectable,
|
|
1390
1812
|
args: [{ providedIn: 'root' }]
|
|
1391
|
-
}], ctorParameters: () => [{ type:
|
|
1813
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1392
1814
|
type: Inject,
|
|
1393
1815
|
args: [PLATFORM_ID]
|
|
1394
1816
|
}] }] });
|
|
@@ -1448,20 +1870,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
1448
1870
|
class NotificationService {
|
|
1449
1871
|
hubConnection = null;
|
|
1450
1872
|
connectionStatus = 'disconnected';
|
|
1451
|
-
constructor() { }
|
|
1452
1873
|
/**
|
|
1453
|
-
*
|
|
1454
|
-
*
|
|
1455
|
-
*
|
|
1874
|
+
* Single source of truth for subscriptions. The hub connection gets exactly
|
|
1875
|
+
* one dispatcher per event, so:
|
|
1876
|
+
* - off(event, callback) can remove one subscriber without nuking the rest
|
|
1877
|
+
* (hubConnection.off(event) removes every handler for the event);
|
|
1878
|
+
* - handlers registered before connect() are attached once connected;
|
|
1879
|
+
* - handlers survive a re-connect that builds a new HubConnection.
|
|
1880
|
+
*/
|
|
1881
|
+
handlers = new Map();
|
|
1882
|
+
connectPromise = null;
|
|
1883
|
+
lastHubUrl = null;
|
|
1884
|
+
lastOptions;
|
|
1885
|
+
manualDisconnect = false;
|
|
1886
|
+
restartAttempts = 0;
|
|
1887
|
+
restartTimer = null;
|
|
1888
|
+
/**
|
|
1889
|
+
* Connect to SignalR Hub. Overlapping calls share the same in-flight
|
|
1890
|
+
* promise instead of building two competing connections.
|
|
1456
1891
|
*/
|
|
1457
1892
|
async connect(hubUrl, options) {
|
|
1458
1893
|
if (this.hubConnection && this.connectionStatus === 'connected') {
|
|
1459
|
-
console.log('Already connected to SignalR hub');
|
|
1460
1894
|
return;
|
|
1461
1895
|
}
|
|
1896
|
+
if (this.connectPromise) {
|
|
1897
|
+
return this.connectPromise;
|
|
1898
|
+
}
|
|
1899
|
+
this.connectPromise = this.doConnect(hubUrl, options).finally(() => {
|
|
1900
|
+
this.connectPromise = null;
|
|
1901
|
+
});
|
|
1902
|
+
return this.connectPromise;
|
|
1903
|
+
}
|
|
1904
|
+
async doConnect(hubUrl, options) {
|
|
1462
1905
|
try {
|
|
1463
1906
|
this.connectionStatus = 'connecting';
|
|
1464
|
-
|
|
1907
|
+
this.manualDisconnect = false;
|
|
1908
|
+
this.lastHubUrl = hubUrl;
|
|
1909
|
+
this.lastOptions = options;
|
|
1465
1910
|
const connectionOptions = {
|
|
1466
1911
|
skipNegotiation: true,
|
|
1467
1912
|
transport: signalR.HttpTransportType.WebSockets,
|
|
@@ -1473,29 +1918,33 @@ class NotificationService {
|
|
|
1473
1918
|
.withAutomaticReconnect()
|
|
1474
1919
|
.configureLogging(signalR.LogLevel.Information)
|
|
1475
1920
|
.build();
|
|
1476
|
-
//
|
|
1921
|
+
// A new HubConnection knows nothing about previous listeners:
|
|
1922
|
+
// re-attach one dispatcher per known event.
|
|
1923
|
+
for (const eventName of this.handlers.keys()) {
|
|
1924
|
+
this.attachDispatcher(eventName);
|
|
1925
|
+
}
|
|
1926
|
+
// Fires when the automatic-reconnect policy is exhausted (or the
|
|
1927
|
+
// server closes the socket). Restart with backoff unless the app
|
|
1928
|
+
// disconnected on purpose.
|
|
1477
1929
|
this.hubConnection.onclose((error) => {
|
|
1478
1930
|
this.connectionStatus = 'disconnected';
|
|
1479
1931
|
if (error) {
|
|
1480
1932
|
console.error('SignalR connection closed with error:', error);
|
|
1481
1933
|
}
|
|
1482
|
-
|
|
1483
|
-
|
|
1934
|
+
if (!this.manualDisconnect) {
|
|
1935
|
+
this.scheduleRestart();
|
|
1484
1936
|
}
|
|
1485
1937
|
});
|
|
1486
|
-
|
|
1487
|
-
this.hubConnection.onreconnecting((error) => {
|
|
1938
|
+
this.hubConnection.onreconnecting(() => {
|
|
1488
1939
|
this.connectionStatus = 'connecting';
|
|
1489
|
-
console.log('SignalR reconnecting...', error);
|
|
1490
1940
|
});
|
|
1491
|
-
|
|
1492
|
-
this.hubConnection.onreconnected((connectionId) => {
|
|
1941
|
+
this.hubConnection.onreconnected(() => {
|
|
1493
1942
|
this.connectionStatus = 'connected';
|
|
1494
|
-
|
|
1943
|
+
this.restartAttempts = 0;
|
|
1495
1944
|
});
|
|
1496
1945
|
await this.hubConnection.start();
|
|
1497
1946
|
this.connectionStatus = 'connected';
|
|
1498
|
-
|
|
1947
|
+
this.restartAttempts = 0;
|
|
1499
1948
|
}
|
|
1500
1949
|
catch (error) {
|
|
1501
1950
|
this.connectionStatus = 'disconnected';
|
|
@@ -1503,15 +1952,34 @@ class NotificationService {
|
|
|
1503
1952
|
throw error;
|
|
1504
1953
|
}
|
|
1505
1954
|
}
|
|
1955
|
+
scheduleRestart() {
|
|
1956
|
+
if (this.restartTimer || !this.lastHubUrl) {
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
const delay = Math.min(30_000, 1_000 * 2 ** this.restartAttempts++);
|
|
1960
|
+
this.restartTimer = setTimeout(async () => {
|
|
1961
|
+
this.restartTimer = null;
|
|
1962
|
+
try {
|
|
1963
|
+
await this.connect(this.lastHubUrl, this.lastOptions);
|
|
1964
|
+
}
|
|
1965
|
+
catch {
|
|
1966
|
+
this.scheduleRestart();
|
|
1967
|
+
}
|
|
1968
|
+
}, delay);
|
|
1969
|
+
}
|
|
1506
1970
|
/**
|
|
1507
|
-
* Disconnect from SignalR Hub
|
|
1971
|
+
* Disconnect from SignalR Hub. Stops any pending auto-restart.
|
|
1508
1972
|
*/
|
|
1509
1973
|
async disconnect() {
|
|
1974
|
+
this.manualDisconnect = true;
|
|
1975
|
+
if (this.restartTimer) {
|
|
1976
|
+
clearTimeout(this.restartTimer);
|
|
1977
|
+
this.restartTimer = null;
|
|
1978
|
+
}
|
|
1510
1979
|
if (this.hubConnection) {
|
|
1511
1980
|
try {
|
|
1512
1981
|
await this.hubConnection.stop();
|
|
1513
1982
|
this.connectionStatus = 'disconnected';
|
|
1514
|
-
console.log('SignalR disconnected successfully');
|
|
1515
1983
|
}
|
|
1516
1984
|
catch (error) {
|
|
1517
1985
|
console.error('Error disconnecting from SignalR hub:', error);
|
|
@@ -1519,28 +1987,73 @@ class NotificationService {
|
|
|
1519
1987
|
}
|
|
1520
1988
|
}
|
|
1521
1989
|
/**
|
|
1522
|
-
* Listen to a specific event from the server
|
|
1523
|
-
*
|
|
1524
|
-
* @param callback - Callback function to execute when event is received
|
|
1990
|
+
* Listen to a specific event from the server. Safe to call before
|
|
1991
|
+
* connect(): the handler is attached once the connection is up.
|
|
1525
1992
|
*/
|
|
1526
1993
|
on(eventName, callback) {
|
|
1527
|
-
|
|
1528
|
-
|
|
1994
|
+
let set = this.handlers.get(eventName);
|
|
1995
|
+
if (!set) {
|
|
1996
|
+
set = new Set();
|
|
1997
|
+
this.handlers.set(eventName, set);
|
|
1998
|
+
this.attachDispatcher(eventName);
|
|
1999
|
+
}
|
|
2000
|
+
set.add(callback);
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* Remove listener(s) for an event.
|
|
2004
|
+
* Prefer passing the callback (or using on$()): calling off(event) without
|
|
2005
|
+
* one removes EVERY handler for the event, including other features'.
|
|
2006
|
+
*/
|
|
2007
|
+
off(eventName, callback) {
|
|
2008
|
+
const set = this.handlers.get(eventName);
|
|
2009
|
+
if (!set) {
|
|
1529
2010
|
return;
|
|
1530
2011
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
2012
|
+
if (callback) {
|
|
2013
|
+
set.delete(callback);
|
|
2014
|
+
}
|
|
2015
|
+
else {
|
|
2016
|
+
console.warn(`NotificationService.off('${eventName}') without a callback removes ALL handlers for this event. ` +
|
|
2017
|
+
'Pass the callback registered with on(), or migrate to on$().');
|
|
2018
|
+
set.clear();
|
|
2019
|
+
}
|
|
2020
|
+
if (set.size === 0) {
|
|
2021
|
+
this.handlers.delete(eventName);
|
|
2022
|
+
this.hubConnection?.off(eventName);
|
|
2023
|
+
}
|
|
1533
2024
|
}
|
|
1534
2025
|
/**
|
|
1535
|
-
*
|
|
1536
|
-
*
|
|
2026
|
+
* Observable stream of an event. Teardown removes exactly this
|
|
2027
|
+
* subscriber — the safe replacement for manual on()/off().
|
|
2028
|
+
* Emits the event's first argument (SignalR payloads are single-arg here).
|
|
1537
2029
|
*/
|
|
1538
|
-
|
|
2030
|
+
on$(eventName) {
|
|
2031
|
+
return new Observable((subscriber) => {
|
|
2032
|
+
const callback = (payload) => subscriber.next(payload);
|
|
2033
|
+
this.on(eventName, callback);
|
|
2034
|
+
return () => this.off(eventName, callback);
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
attachDispatcher(eventName) {
|
|
1539
2038
|
if (!this.hubConnection) {
|
|
1540
2039
|
return;
|
|
1541
2040
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
2041
|
+
this.hubConnection.on(eventName, (...args) => this.dispatch(eventName, args));
|
|
2042
|
+
}
|
|
2043
|
+
dispatch(eventName, args) {
|
|
2044
|
+
const set = this.handlers.get(eventName);
|
|
2045
|
+
if (!set) {
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
// Copy: a callback may add/remove handlers while we iterate.
|
|
2049
|
+
for (const callback of [...set]) {
|
|
2050
|
+
try {
|
|
2051
|
+
callback(...args);
|
|
2052
|
+
}
|
|
2053
|
+
catch (error) {
|
|
2054
|
+
console.error(`Error in '${eventName}' notification handler:`, error);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
1544
2057
|
}
|
|
1545
2058
|
/**
|
|
1546
2059
|
* Invoke a method on the server
|
|
@@ -1552,7 +2065,6 @@ class NotificationService {
|
|
|
1552
2065
|
throw new Error('Not connected to SignalR hub');
|
|
1553
2066
|
}
|
|
1554
2067
|
try {
|
|
1555
|
-
console.log(`Invoking method: ${methodName}`, args);
|
|
1556
2068
|
return await this.hubConnection.invoke(methodName, ...args);
|
|
1557
2069
|
}
|
|
1558
2070
|
catch (error) {
|
|
@@ -1580,7 +2092,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
1580
2092
|
args: [{
|
|
1581
2093
|
providedIn: 'root'
|
|
1582
2094
|
}]
|
|
1583
|
-
}]
|
|
2095
|
+
}] });
|
|
1584
2096
|
|
|
1585
2097
|
const MATERIAL_MODULE = [
|
|
1586
2098
|
MatSelectModule,
|
|
@@ -1616,7 +2128,7 @@ class ButtonComponent {
|
|
|
1616
2128
|
this.clicked.emit();
|
|
1617
2129
|
}
|
|
1618
2130
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1619
|
-
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-success': buttonVariant === 'success',\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) {\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"20\"\n class=\"flex\"\n [ngClass]=\"{\n 'text-text-inverse': buttonVariant === 'default',\n 'text-text-primary': buttonVariant === 'alternative',\n 'text-white': buttonVariant === 'primary' || buttonVariant === 'success',\n }\"\n ></fx-ui-hero-icon>\n }\n @if (label) {\n <div>{{ label }}</div>\n }\n </div>\n </ng-container>\n }\n</button>\n", styles: [""], dependencies: [{ kind: "directive", type:
|
|
2131
|
+
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-success': buttonVariant === 'success',\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) {\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"20\"\n class=\"flex\"\n [ngClass]=\"{\n 'text-text-inverse': buttonVariant === 'default',\n 'text-text-primary': buttonVariant === 'alternative',\n 'text-white': buttonVariant === 'primary' || buttonVariant === 'success',\n }\"\n ></fx-ui-hero-icon>\n }\n @if (label) {\n <div>{{ label }}</div>\n }\n </div>\n </ng-container>\n }\n</button>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
1620
2132
|
}
|
|
1621
2133
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ButtonComponent, decorators: [{
|
|
1622
2134
|
type: Component,
|
|
@@ -2041,17 +2553,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2041
2553
|
args: ['window:theme-changed']
|
|
2042
2554
|
}] } });
|
|
2043
2555
|
|
|
2044
|
-
|
|
2045
|
-
|
|
2556
|
+
class FxComponent {
|
|
2557
|
+
/**
|
|
2558
|
+
* Injected via inject() rather than a constructor parameter: parameter
|
|
2559
|
+
* decorators (@Optional/@Self) are NOT inherited by subclasses, which used
|
|
2560
|
+
* to make every control crash when used without a form binding, or silently
|
|
2561
|
+
* bind to an ancestor's NgControl.
|
|
2562
|
+
*/
|
|
2563
|
+
ngControl = inject(NgControl, { optional: true, self: true });
|
|
2564
|
+
disabled = false;
|
|
2046
2565
|
value;
|
|
2047
|
-
onChange = (
|
|
2048
|
-
onTouched = () =>
|
|
2566
|
+
onChange = () => undefined;
|
|
2567
|
+
onTouched = () => undefined;
|
|
2049
2568
|
validationError;
|
|
2050
2569
|
errorMessages;
|
|
2051
|
-
constructor(
|
|
2052
|
-
this.ngControl
|
|
2053
|
-
|
|
2054
|
-
ngControl.valueAccessor = this;
|
|
2570
|
+
constructor() {
|
|
2571
|
+
if (this.ngControl)
|
|
2572
|
+
this.ngControl.valueAccessor = this;
|
|
2055
2573
|
}
|
|
2056
2574
|
setValue(value) {
|
|
2057
2575
|
if (this.onChange) {
|
|
@@ -2064,7 +2582,9 @@ let FxComponent = class FxComponent {
|
|
|
2064
2582
|
}
|
|
2065
2583
|
}
|
|
2066
2584
|
writeValue(value) {
|
|
2067
|
-
|
|
2585
|
+
// Pass through as-is. Coercing null to '' here broke boolean/number
|
|
2586
|
+
// controls; string controls that want '' as their empty value override.
|
|
2587
|
+
this.value = value;
|
|
2068
2588
|
}
|
|
2069
2589
|
registerOnChange(fn) {
|
|
2070
2590
|
this.onChange = fn;
|
|
@@ -2072,6 +2592,9 @@ let FxComponent = class FxComponent {
|
|
|
2072
2592
|
registerOnTouched(fn) {
|
|
2073
2593
|
this.onTouched = fn;
|
|
2074
2594
|
}
|
|
2595
|
+
setDisabledState(isDisabled) {
|
|
2596
|
+
this.disabled = isDisabled;
|
|
2597
|
+
}
|
|
2075
2598
|
get invalid() {
|
|
2076
2599
|
return !!(this.ngControl?.invalid && this.ngControl?.touched);
|
|
2077
2600
|
}
|
|
@@ -2093,20 +2616,22 @@ let FxComponent = class FxComponent {
|
|
|
2093
2616
|
const control = this.ngControl?.control;
|
|
2094
2617
|
if (!control)
|
|
2095
2618
|
return;
|
|
2096
|
-
control.setErrors(error);
|
|
2619
|
+
control.setErrors({ ...control.errors, ...error });
|
|
2097
2620
|
}
|
|
2621
|
+
/**
|
|
2622
|
+
* Removes only the errors this component set imperatively via setErrors().
|
|
2623
|
+
* Errors owned by the validator pipeline (built-in or custom validators)
|
|
2624
|
+
* are left untouched.
|
|
2625
|
+
*/
|
|
2098
2626
|
clearErrors() {
|
|
2099
2627
|
const control = this.ngControl?.control;
|
|
2100
|
-
if (!control)
|
|
2628
|
+
if (!control || !this.validationError)
|
|
2101
2629
|
return;
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
2104
|
-
|
|
2105
|
-
for (const key of builtInErrorKeys) {
|
|
2106
|
-
if (errors[key] !== undefined) {
|
|
2107
|
-
remaining[key] = errors[key];
|
|
2108
|
-
}
|
|
2630
|
+
const remaining = { ...(control.errors || {}) };
|
|
2631
|
+
for (const key of Object.keys(this.validationError)) {
|
|
2632
|
+
delete remaining[key];
|
|
2109
2633
|
}
|
|
2634
|
+
this.validationError = undefined;
|
|
2110
2635
|
control.setErrors(Object.keys(remaining).length ? remaining : null);
|
|
2111
2636
|
}
|
|
2112
2637
|
getErrorMessage(label) {
|
|
@@ -2116,33 +2641,35 @@ let FxComponent = class FxComponent {
|
|
|
2116
2641
|
const defaultMessages = {
|
|
2117
2642
|
required: `${displayLabel} is required`,
|
|
2118
2643
|
minlength: `${displayLabel} minimum length is ${this.errors['minlength']?.requiredLength}`,
|
|
2119
|
-
email:
|
|
2644
|
+
email: 'Please enter a valid email',
|
|
2120
2645
|
};
|
|
2121
2646
|
const messages = { ...defaultMessages, ...this.validationError, ...this.errorMessages };
|
|
2122
2647
|
const firstKey = Object.keys(this.errors)[0];
|
|
2123
2648
|
return messages[firstKey] || `Invalid ${label ?? 'value'}`;
|
|
2124
2649
|
}
|
|
2125
|
-
};
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2650
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2651
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: FxComponent, isStandalone: true, inputs: { disabled: "disabled" }, ngImport: i0 });
|
|
2652
|
+
}
|
|
2653
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxComponent, decorators: [{
|
|
2654
|
+
type: Directive
|
|
2655
|
+
}], ctorParameters: () => [], propDecorators: { disabled: [{
|
|
2656
|
+
type: Input
|
|
2657
|
+
}] } });
|
|
2130
2658
|
|
|
2131
2659
|
class CheckboxComponent extends FxComponent {
|
|
2132
2660
|
ref;
|
|
2133
2661
|
label = '';
|
|
2134
|
-
disabled = false;
|
|
2135
2662
|
rounded;
|
|
2136
2663
|
valueChange = new EventEmitter();
|
|
2137
|
-
constructor(
|
|
2138
|
-
super(
|
|
2664
|
+
constructor(ref) {
|
|
2665
|
+
super();
|
|
2139
2666
|
this.ref = ref;
|
|
2140
2667
|
}
|
|
2141
2668
|
ngAfterViewInit() {
|
|
2142
2669
|
this.ref.detectChanges();
|
|
2143
2670
|
}
|
|
2144
|
-
|
|
2145
|
-
this.
|
|
2671
|
+
writeValue(value) {
|
|
2672
|
+
this.value = value ?? false;
|
|
2146
2673
|
}
|
|
2147
2674
|
onInputChange(event) {
|
|
2148
2675
|
const checked = event.target.checked;
|
|
@@ -2153,15 +2680,13 @@ class CheckboxComponent extends FxComponent {
|
|
|
2153
2680
|
markTouched() {
|
|
2154
2681
|
this.onTouched();
|
|
2155
2682
|
}
|
|
2156
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CheckboxComponent, deps: [{ token:
|
|
2157
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: CheckboxComponent, isStandalone: false, selector: "fx-ui-checkbox", inputs: { label: "label",
|
|
2683
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CheckboxComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2684
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: CheckboxComponent, isStandalone: false, selector: "fx-ui-checkbox", inputs: { label: "label", rounded: "rounded" }, outputs: { valueChange: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<label\n class=\"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 w-4 h-4 border rounded-full transition-colors duration-150 shrink-0\"\n [ngClass]=\"{\n 'rounded-full': rounded,\n 'rounded-sm': !rounded,\n 'border-border-strong bg-transparent': !value,\n 'border-transparent bg-gradient-primary': 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-white w-4 h-4 transition-opacity duration-150\"\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 @if (label) {\n <span class=\"mb-0 txt-field-label\">{{ label }}</span>\n }\n</label>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
2158
2685
|
}
|
|
2159
2686
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CheckboxComponent, decorators: [{
|
|
2160
2687
|
type: Component,
|
|
2161
2688
|
args: [{ selector: 'fx-ui-checkbox', standalone: false, template: "<label\n class=\"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 w-4 h-4 border rounded-full transition-colors duration-150 shrink-0\"\n [ngClass]=\"{\n 'rounded-full': rounded,\n 'rounded-sm': !rounded,\n 'border-border-strong bg-transparent': !value,\n 'border-transparent bg-gradient-primary': 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-white w-4 h-4 transition-opacity duration-150\"\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 @if (label) {\n <span class=\"mb-0 txt-field-label\">{{ label }}</span>\n }\n</label>\n" }]
|
|
2162
|
-
}], ctorParameters: () => [{ type:
|
|
2163
|
-
type: Input
|
|
2164
|
-
}], disabled: [{
|
|
2689
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
|
|
2165
2690
|
type: Input
|
|
2166
2691
|
}], rounded: [{
|
|
2167
2692
|
type: Input
|
|
@@ -2201,25 +2726,20 @@ class DatetimePicker extends FxComponent {
|
|
|
2201
2726
|
placeholder = 'Select date and time';
|
|
2202
2727
|
required = false;
|
|
2203
2728
|
type = 'both';
|
|
2204
|
-
disabled = false;
|
|
2205
2729
|
minDate;
|
|
2206
2730
|
maxDate;
|
|
2207
2731
|
errorMessages = {};
|
|
2208
2732
|
validateFn;
|
|
2209
2733
|
startAt;
|
|
2210
|
-
constructor(
|
|
2211
|
-
super(
|
|
2734
|
+
constructor(ref) {
|
|
2735
|
+
super();
|
|
2212
2736
|
this.ref = ref;
|
|
2213
2737
|
}
|
|
2214
|
-
ngOnInit() { }
|
|
2215
2738
|
ngAfterViewInit() {
|
|
2216
2739
|
setTimeout(() => {
|
|
2217
2740
|
this.ref.detectChanges();
|
|
2218
2741
|
});
|
|
2219
2742
|
}
|
|
2220
|
-
setDisabledState(isDisabled) {
|
|
2221
|
-
this.disabled = isDisabled;
|
|
2222
|
-
}
|
|
2223
2743
|
onBlur() {
|
|
2224
2744
|
this.onTouched();
|
|
2225
2745
|
this.validate(this.validateFn);
|
|
@@ -2236,13 +2756,13 @@ class DatetimePicker extends FxComponent {
|
|
|
2236
2756
|
this.onChange(date);
|
|
2237
2757
|
this.onTouched();
|
|
2238
2758
|
}
|
|
2239
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DatetimePicker, deps: [{ token:
|
|
2240
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: DatetimePicker, isStandalone: false, selector: "fx-ui-datetime-picker", inputs: { label: "label", placeholder: "placeholder", required: "required", type: "type",
|
|
2759
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DatetimePicker, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2760
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: DatetimePicker, isStandalone: false, selector: "fx-ui-datetime-picker", inputs: { label: "label", placeholder: "placeholder", required: "required", type: "type", minDate: "minDate", maxDate: "maxDate", errorMessages: "errorMessages", validateFn: "validateFn" }, usesInheritance: true, ngImport: i0, template: "<div class=\"flex flex-col mb-4 w-full text-left\">\n @if (label) {\n <label class=\"txt-field-label\">\n {{ label }}\n <span *ngIf=\"required\" class=\"txt-required\">*</span>\n </label>\n }\n\n <div class=\"relative\">\n <input\n [owlDateTimeTrigger]=\"picker\"\n [owlDateTime]=\"picker\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [min]=\"minDate\"\n [max]=\"maxDate\"\n (blur)=\"onBlur()\"\n [value]=\"value\"\n readonly\n class=\"input-default pr-9\"\n />\n <span\n [owlDateTimeTrigger]=\"picker\"\n class=\"absolute inset-y-0 right-0 flex items-center pr-2.5 cursor-pointer text-text-placeholder hover:text-text-primary transition-colors\"\n >\n <fx-ui-hero-icon icon=\"calendar\" [size]=\"20\" class=\"text-text-primary\"></fx-ui-hero-icon>\n </span>\n </div>\n <owl-date-time\n #picker\n [startAt]=\"startAt\"\n [pickerType]=\"type\"\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(var(--border-default) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-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 :not(.owl-dt-calendar-cell-disabled):hover>.owl-dt-calendar-cell-content:not(.owl-dt-calendar-cell-selected){--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-content{color:rgb(var(--text-primary))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-selected{background-color:rgb(var(--primary))!important;color:#fff!important}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-today:not(.owl-dt-calendar-cell-selected){border-color:rgb(var(--primary))!important}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-disabled>.owl-dt-calendar-cell-content{color:rgb(var(--text-placeholder))!important;opacity:.6!important;cursor:not-allowed;pointer-events:none}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-content.owl-dt-calendar-cell-out{color:rgb(var(--text-secondary))!important;opacity:.6!important}::ng-deep .owl-dt-timer-content .owl-dt-timer-input{border-radius:.5rem;border-width:1px;--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{height:auto!important;color:rgb(var(--text-primary))!important;display:flex!important;align-items:center!important;justify-content:flex-end!important;gap:8px;padding:8px 12px;border-top:1px solid rgb(var(--border-default))}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button{width:auto!important;height:32px!important;border-radius:6px!important;width:60px!important;padding-top:4px!important;padding-bottom:4px!important;font-size:13px!important;font-weight:600!important;border:1px solid rgb(var(--border-default))!important;background-color:rgb(var(--bg-primary))!important;color:rgb(var(--text-primary))!important;cursor:pointer;transition:opacity .15s ease}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button:hover{background-color:rgb(var(--bg-hover))!important}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button:last-child{background-color:rgb(var(--primary))!important;border-color:rgb(var(--primary))!important;color:#fff!important}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button:last-child:hover{opacity:.85}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button .owl-dt-control-button-content{height:100%!important;width:100%!important;padding:0!important;background-color:transparent!important;color:inherit!important;display:flex!important;align-items:center!important;justify-content:center!important}::ng-deep .owl-dt-calendar-control-content .owl-dt-control-button-content{font-weight:500;--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-table .owl-dt-calendar-header{--tw-text-opacity: 1;color:rgb(var(--text-secondary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-weekdays th{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: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$2.OwlDateTimeTriggerDirective, selector: "[owlDateTimeTrigger]", inputs: ["owlDateTimeTrigger", "disabled"] }, { kind: "directive", type: i2$2.OwlDateTimeInputDirective, selector: "input[owlDateTime]", inputs: ["required", "owlDateTime", "owlDateTimeFilter", "_disabled", "min", "max", "selectMode", "rangeSeparator", "value", "values"], outputs: ["dateTimeChange", "dateTimeInput"], exportAs: ["owlDateTimeInput"] }, { kind: "component", type: i2$2.OwlDateTimeComponent, selector: "owl-date-time", inputs: ["backdropClass", "panelClass", "startAt", "endAt", "pickerType", "pickerMode", "disabled", "opened", "scrollStrategy"], outputs: ["afterPickerClosed", "beforePickerOpen", "afterPickerOpen", "yearSelected", "monthSelected", "dateSelected"], exportAs: ["owlDateTime"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2241
2761
|
}
|
|
2242
2762
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DatetimePicker, decorators: [{
|
|
2243
2763
|
type: Component,
|
|
2244
2764
|
args: [{ selector: 'fx-ui-datetime-picker', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col mb-4 w-full text-left\">\n @if (label) {\n <label class=\"txt-field-label\">\n {{ label }}\n <span *ngIf=\"required\" class=\"txt-required\">*</span>\n </label>\n }\n\n <div class=\"relative\">\n <input\n [owlDateTimeTrigger]=\"picker\"\n [owlDateTime]=\"picker\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [min]=\"minDate\"\n [max]=\"maxDate\"\n (blur)=\"onBlur()\"\n [value]=\"value\"\n readonly\n class=\"input-default pr-9\"\n />\n <span\n [owlDateTimeTrigger]=\"picker\"\n class=\"absolute inset-y-0 right-0 flex items-center pr-2.5 cursor-pointer text-text-placeholder hover:text-text-primary transition-colors\"\n >\n <fx-ui-hero-icon icon=\"calendar\" [size]=\"20\" class=\"text-text-primary\"></fx-ui-hero-icon>\n </span>\n </div>\n <owl-date-time\n #picker\n [startAt]=\"startAt\"\n [pickerType]=\"type\"\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(var(--border-default) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-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 :not(.owl-dt-calendar-cell-disabled):hover>.owl-dt-calendar-cell-content:not(.owl-dt-calendar-cell-selected){--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-content{color:rgb(var(--text-primary))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-selected{background-color:rgb(var(--primary))!important;color:#fff!important}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-today:not(.owl-dt-calendar-cell-selected){border-color:rgb(var(--primary))!important}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-disabled>.owl-dt-calendar-cell-content{color:rgb(var(--text-placeholder))!important;opacity:.6!important;cursor:not-allowed;pointer-events:none}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-content.owl-dt-calendar-cell-out{color:rgb(var(--text-secondary))!important;opacity:.6!important}::ng-deep .owl-dt-timer-content .owl-dt-timer-input{border-radius:.5rem;border-width:1px;--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{height:auto!important;color:rgb(var(--text-primary))!important;display:flex!important;align-items:center!important;justify-content:flex-end!important;gap:8px;padding:8px 12px;border-top:1px solid rgb(var(--border-default))}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button{width:auto!important;height:32px!important;border-radius:6px!important;width:60px!important;padding-top:4px!important;padding-bottom:4px!important;font-size:13px!important;font-weight:600!important;border:1px solid rgb(var(--border-default))!important;background-color:rgb(var(--bg-primary))!important;color:rgb(var(--text-primary))!important;cursor:pointer;transition:opacity .15s ease}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button:hover{background-color:rgb(var(--bg-hover))!important}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button:last-child{background-color:rgb(var(--primary))!important;border-color:rgb(var(--primary))!important;color:#fff!important}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button:last-child:hover{opacity:.85}::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button .owl-dt-control-button-content{height:100%!important;width:100%!important;padding:0!important;background-color:transparent!important;color:inherit!important;display:flex!important;align-items:center!important;justify-content:center!important}::ng-deep .owl-dt-calendar-control-content .owl-dt-control-button-content{font-weight:500;--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-table .owl-dt-calendar-header{--tw-text-opacity: 1;color:rgb(var(--text-secondary) / var(--tw-text-opacity, 1))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-weekdays th{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"] }]
|
|
2245
|
-
}], ctorParameters: () => [{ type:
|
|
2765
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
|
|
2246
2766
|
type: Input
|
|
2247
2767
|
}], placeholder: [{
|
|
2248
2768
|
type: Input
|
|
@@ -2250,8 +2770,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2250
2770
|
type: Input
|
|
2251
2771
|
}], type: [{
|
|
2252
2772
|
type: Input
|
|
2253
|
-
}], disabled: [{
|
|
2254
|
-
type: Input
|
|
2255
2773
|
}], minDate: [{
|
|
2256
2774
|
type: Input
|
|
2257
2775
|
}], maxDate: [{
|
|
@@ -2363,11 +2881,11 @@ class DndUploadComponent {
|
|
|
2363
2881
|
});
|
|
2364
2882
|
}
|
|
2365
2883
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DndUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2366
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: DndUploadComponent, isStandalone: false, selector: "fx-ui-dnd-upload", inputs: { multiple: "multiple", accept: "accept", maxSizeMB: "maxSizeMB", strictSize: "strictSize", icon: "icon", accentColor: "accentColor" }, outputs: { fileDrop: "fileDrop", fileClick: "fileClick", uploadComplete: "uploadComplete", uploadError: "uploadError" }, ngImport: i0, template: "<div\n class=\"dnd-wrapper\"\n [ngStyle]=\"accentStyle\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"dnd-area\"\n [class.drag-over]=\"isDragOver\"\n (click)=\"onAreaClick(fileInput, $event)\"\n (keydown.enter)=\"onAreaClick(fileInput, $event)\"\n >\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"40\"\n class=\"flex dnd-icon\"\n ></fx-ui-hero-icon>\n <div class=\"dnd-text\">\n <span class=\"dnd-link\">Click to upload</span>\n <span class=\"dnd-or\">or drag and drop</span>\n </div>\n <div class=\"dnd-hint\">\n @if (accept) {\n Accepted: {{ accept }}\n } @else {\n Any file type\n }\n \u2014 Max {{ maxSizeMB }} MB\n </div>\n\n <input\n #fileInput\n type=\"file\"\n class=\"dnd-input\"\n [attr.multiple]=\"multiple ? '' : null\"\n [attr.accept]=\"accept\"\n (change)=\"onFileSelected($event)\"\n />\n </div>\n</div>\n", styles: [":host{--dnd-accent: rgba(var(--gradient-primary-start) / 1)}.dnd-wrapper{display:block;width:100%}.dnd-area{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:160px;padding:32px 24px;border:2px dashed color-mix(in srgb,var(--dnd-accent) 40%,transparent);border-radius:12px;background:color-mix(in srgb,var(--dnd-accent) 4%,transparent);cursor:pointer;outline:none;transition:all .2s ease;position:relative}.dnd-area:hover{border-color:color-mix(in srgb,var(--dnd-accent) 70%,transparent);background:color-mix(in srgb,var(--dnd-accent) 8%,transparent)}.dnd-area:focus-visible{box-shadow:0 0 0 3px color-mix(in srgb,var(--dnd-accent) 20%,transparent)}.dnd-area.drag-over{border-color:var(--dnd-accent);background:color-mix(in srgb,var(--dnd-accent) 10%,transparent)}.dnd-icon{color:var(--dnd-accent)}.dnd-text{display:flex;align-items:center;gap:4px;font-size:14px;flex-wrap:wrap;justify-content:center}.dnd-link{color:var(--dnd-accent);font-weight:600;text-decoration:underline}.dnd-or{color:rgba(var(--text-secondary)/1)}.dnd-hint{font-size:12px;color:rgba(var(--text-secondary)/.7)}.dnd-input{position:absolute;width:0;height:0;overflow:hidden;opacity:0}@media(max-width:640px){.dnd-area{min-height:120px;padding:24px 16px}.dnd-text{font-size:13px}}\n"], dependencies: [{ kind: "directive", type:
|
|
2884
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: DndUploadComponent, isStandalone: false, selector: "fx-ui-dnd-upload", inputs: { multiple: "multiple", accept: "accept", maxSizeMB: "maxSizeMB", strictSize: "strictSize", icon: "icon", accentColor: "accentColor" }, outputs: { fileDrop: "fileDrop", fileClick: "fileClick", uploadComplete: "uploadComplete", uploadError: "uploadError" }, ngImport: i0, template: "<div\n class=\"dnd-wrapper\"\n [ngStyle]=\"accentStyle\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"dnd-area\"\n [class.drag-over]=\"isDragOver\"\n (click)=\"onAreaClick(fileInput, $event)\"\n (keydown.enter)=\"onAreaClick(fileInput, $event)\"\n >\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"40\"\n class=\"flex dnd-icon\"\n ></fx-ui-hero-icon>\n <div class=\"dnd-text\">\n <span class=\"dnd-link\">Click to upload</span>\n <span class=\"dnd-or\">or drag and drop</span>\n </div>\n <div class=\"dnd-hint\">\n @if (accept) {\n Accepted: {{ accept }}\n } @else {\n Any file type\n }\n \u2014 Max {{ maxSizeMB }} MB\n </div>\n\n <input\n #fileInput\n type=\"file\"\n class=\"dnd-input\"\n [attr.multiple]=\"multiple ? '' : null\"\n [attr.accept]=\"accept\"\n (change)=\"onFileSelected($event)\"\n />\n </div>\n</div>\n", styles: [":host{--dnd-accent: rgba(var(--gradient-primary-start) / 1)}.dnd-wrapper{display:block;width:100%}.dnd-area{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:160px;padding:32px 24px;border:2px dashed color-mix(in srgb,var(--dnd-accent) 40%,transparent);border-radius:12px;background:color-mix(in srgb,var(--dnd-accent) 4%,transparent);cursor:pointer;outline:none;transition:all .2s ease;position:relative}.dnd-area:hover{border-color:color-mix(in srgb,var(--dnd-accent) 70%,transparent);background:color-mix(in srgb,var(--dnd-accent) 8%,transparent)}.dnd-area:focus-visible{box-shadow:0 0 0 3px color-mix(in srgb,var(--dnd-accent) 20%,transparent)}.dnd-area.drag-over{border-color:var(--dnd-accent);background:color-mix(in srgb,var(--dnd-accent) 10%,transparent)}.dnd-icon{color:var(--dnd-accent)}.dnd-text{display:flex;align-items:center;gap:4px;font-size:14px;flex-wrap:wrap;justify-content:center}.dnd-link{color:var(--dnd-accent);font-weight:600;text-decoration:underline}.dnd-or{color:rgba(var(--text-secondary)/1)}.dnd-hint{font-size:12px;color:rgba(var(--text-secondary)/.7)}.dnd-input{position:absolute;width:0;height:0;overflow:hidden;opacity:0}@media (max-width: 640px){.dnd-area{min-height:120px;padding:24px 16px}.dnd-text{font-size:13px}}\n"], dependencies: [{ kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
2367
2885
|
}
|
|
2368
2886
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DndUploadComponent, decorators: [{
|
|
2369
2887
|
type: Component,
|
|
2370
|
-
args: [{ selector: 'fx-ui-dnd-upload', standalone: false, template: "<div\n class=\"dnd-wrapper\"\n [ngStyle]=\"accentStyle\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"dnd-area\"\n [class.drag-over]=\"isDragOver\"\n (click)=\"onAreaClick(fileInput, $event)\"\n (keydown.enter)=\"onAreaClick(fileInput, $event)\"\n >\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"40\"\n class=\"flex dnd-icon\"\n ></fx-ui-hero-icon>\n <div class=\"dnd-text\">\n <span class=\"dnd-link\">Click to upload</span>\n <span class=\"dnd-or\">or drag and drop</span>\n </div>\n <div class=\"dnd-hint\">\n @if (accept) {\n Accepted: {{ accept }}\n } @else {\n Any file type\n }\n \u2014 Max {{ maxSizeMB }} MB\n </div>\n\n <input\n #fileInput\n type=\"file\"\n class=\"dnd-input\"\n [attr.multiple]=\"multiple ? '' : null\"\n [attr.accept]=\"accept\"\n (change)=\"onFileSelected($event)\"\n />\n </div>\n</div>\n", styles: [":host{--dnd-accent: rgba(var(--gradient-primary-start) / 1)}.dnd-wrapper{display:block;width:100%}.dnd-area{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:160px;padding:32px 24px;border:2px dashed color-mix(in srgb,var(--dnd-accent) 40%,transparent);border-radius:12px;background:color-mix(in srgb,var(--dnd-accent) 4%,transparent);cursor:pointer;outline:none;transition:all .2s ease;position:relative}.dnd-area:hover{border-color:color-mix(in srgb,var(--dnd-accent) 70%,transparent);background:color-mix(in srgb,var(--dnd-accent) 8%,transparent)}.dnd-area:focus-visible{box-shadow:0 0 0 3px color-mix(in srgb,var(--dnd-accent) 20%,transparent)}.dnd-area.drag-over{border-color:var(--dnd-accent);background:color-mix(in srgb,var(--dnd-accent) 10%,transparent)}.dnd-icon{color:var(--dnd-accent)}.dnd-text{display:flex;align-items:center;gap:4px;font-size:14px;flex-wrap:wrap;justify-content:center}.dnd-link{color:var(--dnd-accent);font-weight:600;text-decoration:underline}.dnd-or{color:rgba(var(--text-secondary)/1)}.dnd-hint{font-size:12px;color:rgba(var(--text-secondary)/.7)}.dnd-input{position:absolute;width:0;height:0;overflow:hidden;opacity:0}@media(max-width:640px){.dnd-area{min-height:120px;padding:24px 16px}.dnd-text{font-size:13px}}\n"] }]
|
|
2888
|
+
args: [{ selector: 'fx-ui-dnd-upload', standalone: false, template: "<div\n class=\"dnd-wrapper\"\n [ngStyle]=\"accentStyle\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"dnd-area\"\n [class.drag-over]=\"isDragOver\"\n (click)=\"onAreaClick(fileInput, $event)\"\n (keydown.enter)=\"onAreaClick(fileInput, $event)\"\n >\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"40\"\n class=\"flex dnd-icon\"\n ></fx-ui-hero-icon>\n <div class=\"dnd-text\">\n <span class=\"dnd-link\">Click to upload</span>\n <span class=\"dnd-or\">or drag and drop</span>\n </div>\n <div class=\"dnd-hint\">\n @if (accept) {\n Accepted: {{ accept }}\n } @else {\n Any file type\n }\n \u2014 Max {{ maxSizeMB }} MB\n </div>\n\n <input\n #fileInput\n type=\"file\"\n class=\"dnd-input\"\n [attr.multiple]=\"multiple ? '' : null\"\n [attr.accept]=\"accept\"\n (change)=\"onFileSelected($event)\"\n />\n </div>\n</div>\n", styles: [":host{--dnd-accent: rgba(var(--gradient-primary-start) / 1)}.dnd-wrapper{display:block;width:100%}.dnd-area{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:160px;padding:32px 24px;border:2px dashed color-mix(in srgb,var(--dnd-accent) 40%,transparent);border-radius:12px;background:color-mix(in srgb,var(--dnd-accent) 4%,transparent);cursor:pointer;outline:none;transition:all .2s ease;position:relative}.dnd-area:hover{border-color:color-mix(in srgb,var(--dnd-accent) 70%,transparent);background:color-mix(in srgb,var(--dnd-accent) 8%,transparent)}.dnd-area:focus-visible{box-shadow:0 0 0 3px color-mix(in srgb,var(--dnd-accent) 20%,transparent)}.dnd-area.drag-over{border-color:var(--dnd-accent);background:color-mix(in srgb,var(--dnd-accent) 10%,transparent)}.dnd-icon{color:var(--dnd-accent)}.dnd-text{display:flex;align-items:center;gap:4px;font-size:14px;flex-wrap:wrap;justify-content:center}.dnd-link{color:var(--dnd-accent);font-weight:600;text-decoration:underline}.dnd-or{color:rgba(var(--text-secondary)/1)}.dnd-hint{font-size:12px;color:rgba(var(--text-secondary)/.7)}.dnd-input{position:absolute;width:0;height:0;overflow:hidden;opacity:0}@media (max-width: 640px){.dnd-area{min-height:120px;padding:24px 16px}.dnd-text{font-size:13px}}\n"] }]
|
|
2371
2889
|
}], propDecorators: { multiple: [{
|
|
2372
2890
|
type: Input
|
|
2373
2891
|
}], accept: [{
|
|
@@ -2405,7 +2923,7 @@ class FlowConnection {
|
|
|
2405
2923
|
];
|
|
2406
2924
|
}
|
|
2407
2925
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FlowConnection, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2408
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: FlowConnection, isStandalone: false, selector: "fx-ui-flow-connection", inputs: { nodes: "nodes", edges: "edges", backgroundColor: "backgroundColor", view: "view" }, ngImport: i0, template: "<vflow\n [background]=\"{\n type: 'solid',\n color: `rgba(var(${backgroundColor})`\n}\"\n [nodes]=\"nodes\"\n [edges]=\"edges\"\n (onConnect)=\"handleConnection($event)\"\n [view]=\"view\"\n/>\n", styles: [""], dependencies: [{ kind: "component", type:
|
|
2926
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: FlowConnection, isStandalone: false, selector: "fx-ui-flow-connection", inputs: { nodes: "nodes", edges: "edges", backgroundColor: "backgroundColor", view: "view" }, ngImport: i0, template: "<vflow\n [background]=\"{\n type: 'solid',\n color: `rgba(var(${backgroundColor})`\n}\"\n [nodes]=\"nodes\"\n [edges]=\"edges\"\n (onConnect)=\"handleConnection($event)\"\n [view]=\"view\"\n/>\n", styles: [""], dependencies: [{ kind: "component", type: i38.VflowComponent, selector: "vflow", inputs: ["view", "minZoom", "maxZoom", "background", "optimization", "entitiesSelectable", "keyboardShortcuts", "connection", "snapGrid", "elevateNodesOnSelect", "elevateEdgesOnSelect", "nodes", "alignmentHelper", "edges"], outputs: ["onComponentNodeEvent"] }, { kind: "directive", type: i38.ConnectionControllerDirective, selector: "[onConnect], [onReconnect], [connect], [reconnect]", outputs: ["onConnect", "connect", "onReconnect", "reconnect"] }] });
|
|
2409
2927
|
}
|
|
2410
2928
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FlowConnection, decorators: [{
|
|
2411
2929
|
type: Component,
|
|
@@ -2428,7 +2946,6 @@ class InputComponent extends FxComponent {
|
|
|
2428
2946
|
placeholder = '';
|
|
2429
2947
|
errorMessages = {};
|
|
2430
2948
|
required = false;
|
|
2431
|
-
disabled = false;
|
|
2432
2949
|
suffixIcon;
|
|
2433
2950
|
class;
|
|
2434
2951
|
maxlength;
|
|
@@ -2438,15 +2955,15 @@ class InputComponent extends FxComponent {
|
|
|
2438
2955
|
suffixClick = new EventEmitter();
|
|
2439
2956
|
showPassword = false;
|
|
2440
2957
|
validateError = null;
|
|
2441
|
-
constructor(
|
|
2442
|
-
super(
|
|
2958
|
+
constructor(ref) {
|
|
2959
|
+
super();
|
|
2443
2960
|
this.ref = ref;
|
|
2444
2961
|
}
|
|
2445
2962
|
ngAfterViewInit() {
|
|
2446
2963
|
this.ref.detectChanges();
|
|
2447
2964
|
}
|
|
2448
|
-
|
|
2449
|
-
this.
|
|
2965
|
+
writeValue(value) {
|
|
2966
|
+
this.value = value ?? '';
|
|
2450
2967
|
}
|
|
2451
2968
|
onInput(event) {
|
|
2452
2969
|
const input = event.target;
|
|
@@ -2488,13 +3005,13 @@ class InputComponent extends FxComponent {
|
|
|
2488
3005
|
return 'number';
|
|
2489
3006
|
return this.type;
|
|
2490
3007
|
}
|
|
2491
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InputComponent, deps: [{ token:
|
|
2492
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: InputComponent, isStandalone: false, selector: "fx-ui-input", inputs: { label: "label", tooltip: "tooltip", type: "type", placeholder: "placeholder", errorMessages: "errorMessages", required: "required",
|
|
3008
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3009
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: InputComponent, isStandalone: false, selector: "fx-ui-input", inputs: { label: "label", tooltip: "tooltip", type: "type", placeholder: "placeholder", errorMessages: "errorMessages", required: "required", 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) {\n <label class=\"block txt-field-label\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\">*</span>\n }\n @if (tooltip) {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [size]=\"16\"\n class=\"inline-block align-middle ml-0.5 text-text-secondary cursor-help relative -top-px\"\n [matTooltip]=\"tooltip\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n ></fx-ui-hero-icon>\n }\n </label>\n }\n\n <div class=\"relative\">\n <input\n appTrimOnBlur\n [appTrimOnBlurCollapse]=\"true\"\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 [class.input-invalid]=\"invalid\"\n [class.pr-8]=\"type === 'password' || suffixIcon\"\n [class.txt-otp-input]=\"type === 'otp'\"\n />\n @if (type === 'password' || suffixIcon) {\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 <fx-ui-hero-icon\n [icon]=\"showPassword ? 'eye-slash' : 'eye'\"\n [size]=\"18\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n } @else if (suffixIcon) {\n <fx-ui-hero-icon\n [icon]=\"suffixIcon\"\n [size]=\"18\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n }\n </button>\n }\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: TrimOnBlurDirective, selector: "[appTrimOnBlur]", inputs: ["appTrimOnBlurCollapse"] }, { kind: "directive", type: i56.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
2493
3010
|
}
|
|
2494
3011
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InputComponent, decorators: [{
|
|
2495
3012
|
type: Component,
|
|
2496
3013
|
args: [{ selector: 'fx-ui-input', standalone: false, template: "<div class=\"mb-4 text-left w-full text-text-primary\" [class]=\"class\">\n @if (label) {\n <label class=\"block txt-field-label\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\">*</span>\n }\n @if (tooltip) {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [size]=\"16\"\n class=\"inline-block align-middle ml-0.5 text-text-secondary cursor-help relative -top-px\"\n [matTooltip]=\"tooltip\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n ></fx-ui-hero-icon>\n }\n </label>\n }\n\n <div class=\"relative\">\n <input\n appTrimOnBlur\n [appTrimOnBlurCollapse]=\"true\"\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 [class.input-invalid]=\"invalid\"\n [class.pr-8]=\"type === 'password' || suffixIcon\"\n [class.txt-otp-input]=\"type === 'otp'\"\n />\n @if (type === 'password' || suffixIcon) {\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 <fx-ui-hero-icon\n [icon]=\"showPassword ? 'eye-slash' : 'eye'\"\n [size]=\"18\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n } @else if (suffixIcon) {\n <fx-ui-hero-icon\n [icon]=\"suffixIcon\"\n [size]=\"18\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n }\n </button>\n }\n </div>\n\n @if (invalid) {\n <div class=\"txt-invalid\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n" }]
|
|
2497
|
-
}], ctorParameters: () => [{ type:
|
|
3014
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
|
|
2498
3015
|
type: Input
|
|
2499
3016
|
}], tooltip: [{
|
|
2500
3017
|
type: Input
|
|
@@ -2506,8 +3023,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2506
3023
|
type: Input
|
|
2507
3024
|
}], required: [{
|
|
2508
3025
|
type: Input
|
|
2509
|
-
}], disabled: [{
|
|
2510
|
-
type: Input
|
|
2511
3026
|
}], suffixIcon: [{
|
|
2512
3027
|
type: Input
|
|
2513
3028
|
}], class: [{
|
|
@@ -2528,7 +3043,7 @@ class LoadingPanel {
|
|
|
2528
3043
|
show = false;
|
|
2529
3044
|
message = "Loading";
|
|
2530
3045
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LoadingPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2531
|
-
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=\"url(#spinner-gradient)\" width=\"50\" height=\"50\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs>\n <linearGradient id=\"spinner-gradient\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n <stop offset=\"0%\" style=\"stop-color: rgb(var(--gradient-primary-start)); stop-opacity: 1\" />\n <stop offset=\"100%\" style=\"stop-color: rgb(var(--gradient-primary-end)); stop-opacity: 1\" />\n </linearGradient>\n </defs>\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:
|
|
3046
|
+
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=\"url(#spinner-gradient)\" width=\"50\" height=\"50\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs>\n <linearGradient id=\"spinner-gradient\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n <stop offset=\"0%\" style=\"stop-color: rgb(var(--gradient-primary-start)); stop-opacity: 1\" />\n <stop offset=\"100%\" style=\"stop-color: rgb(var(--gradient-primary-end)); stop-opacity: 1\" />\n </linearGradient>\n </defs>\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: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
2532
3047
|
}
|
|
2533
3048
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LoadingPanel, decorators: [{
|
|
2534
3049
|
type: Component,
|
|
@@ -2544,19 +3059,15 @@ class RadioButtonToggleComponent extends FxComponent {
|
|
|
2544
3059
|
label;
|
|
2545
3060
|
required = false;
|
|
2546
3061
|
options = [];
|
|
2547
|
-
disabled = false;
|
|
2548
3062
|
errorMessages = {};
|
|
2549
3063
|
class;
|
|
2550
|
-
constructor(
|
|
2551
|
-
super(
|
|
3064
|
+
constructor(ref) {
|
|
3065
|
+
super();
|
|
2552
3066
|
this.ref = ref;
|
|
2553
3067
|
}
|
|
2554
3068
|
ngAfterViewInit() {
|
|
2555
3069
|
this.ref.detectChanges();
|
|
2556
3070
|
}
|
|
2557
|
-
setDisabledState(isDisabled) {
|
|
2558
|
-
this.disabled = isDisabled;
|
|
2559
|
-
}
|
|
2560
3071
|
onSelectValue(value) {
|
|
2561
3072
|
if (this.disabled)
|
|
2562
3073
|
return;
|
|
@@ -2564,20 +3075,18 @@ class RadioButtonToggleComponent extends FxComponent {
|
|
|
2564
3075
|
this.onChange(value);
|
|
2565
3076
|
this.onTouched();
|
|
2566
3077
|
}
|
|
2567
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonToggleComponent, deps: [{ token:
|
|
2568
|
-
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",
|
|
3078
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonToggleComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3079
|
+
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", 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: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
2569
3080
|
}
|
|
2570
3081
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonToggleComponent, decorators: [{
|
|
2571
3082
|
type: Component,
|
|
2572
3083
|
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" }]
|
|
2573
|
-
}], ctorParameters: () => [{ type:
|
|
3084
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
|
|
2574
3085
|
type: Input
|
|
2575
3086
|
}], required: [{
|
|
2576
3087
|
type: Input
|
|
2577
3088
|
}], options: [{
|
|
2578
3089
|
type: Input
|
|
2579
|
-
}], disabled: [{
|
|
2580
|
-
type: Input
|
|
2581
3090
|
}], errorMessages: [{
|
|
2582
3091
|
type: Input
|
|
2583
3092
|
}], class: [{
|
|
@@ -2590,19 +3099,15 @@ class RadioButtonComponent extends FxComponent {
|
|
|
2590
3099
|
tooltip = '';
|
|
2591
3100
|
required = false;
|
|
2592
3101
|
options = [];
|
|
2593
|
-
disabled = false;
|
|
2594
3102
|
errorMessages = {};
|
|
2595
3103
|
class;
|
|
2596
|
-
constructor(
|
|
2597
|
-
super(
|
|
3104
|
+
constructor(ref) {
|
|
3105
|
+
super();
|
|
2598
3106
|
this.ref = ref;
|
|
2599
3107
|
}
|
|
2600
3108
|
ngAfterViewInit() {
|
|
2601
3109
|
this.ref.detectChanges();
|
|
2602
3110
|
}
|
|
2603
|
-
setDisabledState(isDisabled) {
|
|
2604
|
-
this.disabled = isDisabled;
|
|
2605
|
-
}
|
|
2606
3111
|
onSelectValue(value) {
|
|
2607
3112
|
if (this.disabled)
|
|
2608
3113
|
return;
|
|
@@ -2610,13 +3115,13 @@ class RadioButtonComponent extends FxComponent {
|
|
|
2610
3115
|
this.onChange(value);
|
|
2611
3116
|
this.onTouched();
|
|
2612
3117
|
}
|
|
2613
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonComponent, deps: [{ token:
|
|
2614
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RadioButtonComponent, isStandalone: false, selector: "fx-ui-radio", inputs: { label: "label", tooltip: "tooltip", required: "required", options: "options",
|
|
3118
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3119
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RadioButtonComponent, isStandalone: false, selector: "fx-ui-radio", inputs: { label: "label", tooltip: "tooltip", required: "required", options: "options", 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) {\n <span class=\"txt-required\">*</span>\n }\n @if (tooltip) {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [size]=\"16\"\n class=\"inline-block align-middle ml-0.5 text-text-secondary cursor-help relative -top-px\"\n [matTooltip]=\"tooltip\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n ></fx-ui-hero-icon>\n }\n </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 [matTooltip]=\"opt.tooltip || ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\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) {\n <span class=\"radio-dot\"></span>\n }\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: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i56.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
2615
3120
|
}
|
|
2616
3121
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonComponent, decorators: [{
|
|
2617
3122
|
type: Component,
|
|
2618
3123
|
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) {\n <span class=\"txt-required\">*</span>\n }\n @if (tooltip) {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [size]=\"16\"\n class=\"inline-block align-middle ml-0.5 text-text-secondary cursor-help relative -top-px\"\n [matTooltip]=\"tooltip\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n ></fx-ui-hero-icon>\n }\n </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 [matTooltip]=\"opt.tooltip || ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\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) {\n <span class=\"radio-dot\"></span>\n }\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" }]
|
|
2619
|
-
}], ctorParameters: () => [{ type:
|
|
3124
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
|
|
2620
3125
|
type: Input
|
|
2621
3126
|
}], tooltip: [{
|
|
2622
3127
|
type: Input
|
|
@@ -2624,8 +3129,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2624
3129
|
type: Input
|
|
2625
3130
|
}], options: [{
|
|
2626
3131
|
type: Input
|
|
2627
|
-
}], disabled: [{
|
|
2628
|
-
type: Input
|
|
2629
3132
|
}], errorMessages: [{
|
|
2630
3133
|
type: Input
|
|
2631
3134
|
}], class: [{
|
|
@@ -2654,8 +3157,8 @@ class RichTextAreaComponent extends FxComponent {
|
|
|
2654
3157
|
];
|
|
2655
3158
|
contentChange = new EventEmitter();
|
|
2656
3159
|
quillInstance;
|
|
2657
|
-
constructor(
|
|
2658
|
-
super(
|
|
3160
|
+
constructor(cdr, styleLoader, platformId) {
|
|
3161
|
+
super();
|
|
2659
3162
|
this.cdr = cdr;
|
|
2660
3163
|
this.styleLoader = styleLoader;
|
|
2661
3164
|
this.platformId = platformId;
|
|
@@ -2698,17 +3201,18 @@ class RichTextAreaComponent extends FxComponent {
|
|
|
2698
3201
|
}
|
|
2699
3202
|
}
|
|
2700
3203
|
setDisabledState(isDisabled) {
|
|
3204
|
+
this.disabled = isDisabled;
|
|
2701
3205
|
if (this.quillInstance) {
|
|
2702
3206
|
this.quillInstance.enable(!isDisabled);
|
|
2703
3207
|
}
|
|
2704
3208
|
}
|
|
2705
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RichTextAreaComponent, deps: [{ token:
|
|
3209
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RichTextAreaComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: QuillStyleLoaderService }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component });
|
|
2706
3210
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: RichTextAreaComponent, isStandalone: false, selector: "fx-ui-rich-text-area", inputs: { placeholder: "placeholder", toolbarOptions: "toolbarOptions" }, outputs: { contentChange: "contentChange" }, viewQueries: [{ propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"w-full rounded-2xl shadow-sm p-1 bg-bg-primary\">\n <div #editorContainer class=\"min-h-[200px] text-base\"></div>\n</div>", styles: [":host{display:block}.ql-toolbar{border-top-left-radius:.25rem;border-top-right-radius:.25rem;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));padding:.5rem}.ql-container{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.ql-editor{min-height:200px;padding:.75rem;font-size:1rem}\n"] });
|
|
2707
3211
|
}
|
|
2708
3212
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RichTextAreaComponent, decorators: [{
|
|
2709
3213
|
type: Component,
|
|
2710
3214
|
args: [{ selector: 'fx-ui-rich-text-area', standalone: false, template: "<div class=\"w-full rounded-2xl shadow-sm p-1 bg-bg-primary\">\n <div #editorContainer class=\"min-h-[200px] text-base\"></div>\n</div>", styles: [":host{display:block}.ql-toolbar{border-top-left-radius:.25rem;border-top-right-radius:.25rem;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));padding:.5rem}.ql-container{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.ql-editor{min-height:200px;padding:.75rem;font-size:1rem}\n"] }]
|
|
2711
|
-
}], ctorParameters: () => [{ type:
|
|
3215
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: QuillStyleLoaderService }, { type: undefined, decorators: [{
|
|
2712
3216
|
type: Inject,
|
|
2713
3217
|
args: [PLATFORM_ID]
|
|
2714
3218
|
}] }], propDecorators: { editorContainer: [{
|
|
@@ -2725,16 +3229,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2725
3229
|
class SearchBarComponent extends FxComponent {
|
|
2726
3230
|
ref;
|
|
2727
3231
|
placeholder = 'Search...';
|
|
2728
|
-
disabled = false;
|
|
2729
3232
|
search = new EventEmitter();
|
|
2730
3233
|
valueChange = new EventEmitter();
|
|
2731
|
-
constructor(
|
|
2732
|
-
super(
|
|
3234
|
+
constructor(ref) {
|
|
3235
|
+
super();
|
|
2733
3236
|
this.ref = ref;
|
|
2734
3237
|
}
|
|
2735
3238
|
ngAfterViewInit() {
|
|
2736
3239
|
this.ref.detectChanges();
|
|
2737
3240
|
}
|
|
3241
|
+
writeValue(value) {
|
|
3242
|
+
this.value = value ?? '';
|
|
3243
|
+
}
|
|
2738
3244
|
onValueChange(value) {
|
|
2739
3245
|
this.value = value;
|
|
2740
3246
|
this.setValue(value);
|
|
@@ -2750,15 +3256,13 @@ class SearchBarComponent extends FxComponent {
|
|
|
2750
3256
|
this.valueChange.emit('');
|
|
2751
3257
|
this.search.emit('');
|
|
2752
3258
|
}
|
|
2753
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SearchBarComponent, deps: [{ token:
|
|
2754
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: SearchBarComponent, isStandalone: false, selector: "fx-ui-search-bar", inputs: { placeholder: "placeholder"
|
|
3259
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SearchBarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3260
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: SearchBarComponent, isStandalone: false, selector: "fx-ui-search-bar", inputs: { placeholder: "placeholder" }, 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: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
2755
3261
|
}
|
|
2756
3262
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SearchBarComponent, decorators: [{
|
|
2757
3263
|
type: Component,
|
|
2758
3264
|
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" }]
|
|
2759
|
-
}], ctorParameters: () => [{ type:
|
|
2760
|
-
type: Input
|
|
2761
|
-
}], disabled: [{
|
|
3265
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { placeholder: [{
|
|
2762
3266
|
type: Input
|
|
2763
3267
|
}], search: [{
|
|
2764
3268
|
type: Output
|
|
@@ -2773,7 +3277,6 @@ class SelectComponent extends FxComponent {
|
|
|
2773
3277
|
placeholder = '';
|
|
2774
3278
|
options = [];
|
|
2775
3279
|
multiple = false;
|
|
2776
|
-
disabled = false;
|
|
2777
3280
|
errorMessages = {};
|
|
2778
3281
|
required = false;
|
|
2779
3282
|
class;
|
|
@@ -2784,16 +3287,29 @@ class SelectComponent extends FxComponent {
|
|
|
2784
3287
|
searchTerm = '';
|
|
2785
3288
|
filteredOptions = [];
|
|
2786
3289
|
search$ = new Subject();
|
|
2787
|
-
|
|
2788
|
-
|
|
3290
|
+
destroyRef = inject(DestroyRef);
|
|
3291
|
+
constructor(ref) {
|
|
3292
|
+
super();
|
|
2789
3293
|
this.ref = ref;
|
|
2790
3294
|
}
|
|
3295
|
+
// mat-select treats '' as "nothing selected"; keep the legacy empty value.
|
|
3296
|
+
writeValue(value) {
|
|
3297
|
+
this.value = value ?? '';
|
|
3298
|
+
}
|
|
2791
3299
|
ngOnInit() {
|
|
2792
3300
|
this.filteredOptions = this.options;
|
|
2793
3301
|
this.search$
|
|
2794
|
-
.pipe(debounceTime(300), distinctUntilChanged())
|
|
3302
|
+
.pipe(debounceTime(300), distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))
|
|
2795
3303
|
.subscribe((term) => this.performSearch(term));
|
|
2796
3304
|
}
|
|
3305
|
+
ngOnChanges(changes) {
|
|
3306
|
+
// Sync the rendered list when options arrive/refresh asynchronously
|
|
3307
|
+
// (ngOnInit captures the initial — often empty — array only).
|
|
3308
|
+
if (changes['options']) {
|
|
3309
|
+
this.filteredOptions = this.options ?? [];
|
|
3310
|
+
this.ref?.detectChanges();
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
2797
3313
|
ngAfterViewInit() {
|
|
2798
3314
|
this.ref.detectChanges();
|
|
2799
3315
|
}
|
|
@@ -2822,7 +3338,6 @@ class SelectComponent extends FxComponent {
|
|
|
2822
3338
|
}
|
|
2823
3339
|
const result = await this.searchFn(term);
|
|
2824
3340
|
this.filteredOptions = result;
|
|
2825
|
-
console.log(this.filteredOptions);
|
|
2826
3341
|
Promise.resolve().then(() => this.ref.detectChanges());
|
|
2827
3342
|
}
|
|
2828
3343
|
onSelectionChange(value) {
|
|
@@ -2835,13 +3350,13 @@ class SelectComponent extends FxComponent {
|
|
|
2835
3350
|
}
|
|
2836
3351
|
return this.value === value;
|
|
2837
3352
|
}
|
|
2838
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SelectComponent, deps: [{ token:
|
|
2839
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SelectComponent, isStandalone: false, selector: "fx-ui-select", inputs: { label: "label", tooltip: "tooltip", placeholder: "placeholder", options: "options", multiple: "multiple",
|
|
3353
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SelectComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3354
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SelectComponent, isStandalone: false, selector: "fx-ui-select", inputs: { label: "label", tooltip: "tooltip", placeholder: "placeholder", options: "options", multiple: "multiple", errorMessages: "errorMessages", required: "required", class: "class", enableSearch: "enableSearch", searchFn: "searchFn" }, outputs: { closed: "closed" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"mb-4 text-left w-full\" [class]=\"class\">\n @if (label) {\n <label class=\"block txt-field-label\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\">*</span>\n }\n @if (tooltip) {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [size]=\"16\"\n class=\"inline-block align-middle ml-0.5 text-text-secondary cursor-help relative -top-px\"\n [matTooltip]=\"tooltip\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n ></fx-ui-hero-icon>\n }\n </label>\n }\n\n <mat-form-field\n [attr.invalid]=\"invalid || null\"\n class=\"fx-select-field w-full shadow-sm\"\n appearance=\"fill\"\n >\n <mat-select\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event.value)\"\n (openedChange)=\"onOpened($event)\"\n (blur)=\"onTouched()\"\n >\n @if (enableSearch) {\n <div class=\"px-semi w-full\">\n <input\n type=\"text\"\n [placeholder]=\"'Search'\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n class=\"text-text-primary placeholder:text-text-placeholder w-full bg-bg-primary border-b px-semi py-normal border-border-default focus:outline-none focus:border-gradient-primary-start text-sm text-text-primary tracking-normal ring-0 transition-colors duration-500 ease-in-out\"\n />\n </div>\n }\n <mat-option *ngFor=\"let option of filteredOptions\" [value]=\"option.value\">\n <span class=\"txt-default\">{{ option.label }}</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n @if (invalid) {\n <div class=\"txt-invalid text-left\">\n {{ getErrorMessage(label) }}\n </div>\n }\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:.375rem;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(--gradient-primary-start))!important;outline:none!important;border-radius:.375rem}::ng-deep .fx-select-field.mat-form-field-invalid .mat-mdc-form-field-flex{border:1px solid rgb(var(--bg-error-bold))!important;box-shadow:none!important}::ng-deep mat-form-field[invalid] .mat-mdc-form-field-flex{border:1px solid rgb(var(--bg-error-bold))!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 .mat-mdc-select-arrow svg{display:none!important}::ng-deep .fx-select-field .mat-mdc-select-arrow-wrapper .mat-mdc-select-arrow{width:8px!important;height:8px!important;border-style:solid;border-color:currentColor;border-width:0 1.5px 1.5px 0;transform:rotate(45deg);margin-top:-3px;color:rgb(var(--text-secondary))!important}::ng-deep .mat-mdc-select-panel{background-color:rgb(var(--bg-primary))!important;border:1px solid rgb(var(--border-default))!important;border-radius:.375rem!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}.mat-select-panel .search-option-full-width{padding-left:0!important;padding-right:0!important;display:block;pointer-events:none;line-height:initial;height:auto}.mat-select-panel .search-option-full-width .search-bar{width:100%;padding:8px 16px;border:none;border-bottom:1px solid #ddd;box-sizing:border-box}::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-form-field-flex,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-form-field-flex{background-color:rgb(var(--bg-primary-hover))!important;border-color:rgb(var(--border-default))!important;cursor:not-allowed!important;opacity:.6;box-shadow:none!important}::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-select-value,::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-select-placeholder,::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-select-arrow,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-select-value,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-select-placeholder,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-select-arrow{color:rgb(var(--text-placeholder))!important}::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-select,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-select{cursor:not-allowed!important}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: i3.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.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i56.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
2840
3355
|
}
|
|
2841
3356
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SelectComponent, decorators: [{
|
|
2842
3357
|
type: Component,
|
|
2843
|
-
args: [{ selector: 'fx-ui-select', standalone: false, template: "<div class=\"mb-4 text-left w-full\" [class]=\"class\">\n @if (label) {\n <label class=\"block txt-field-label\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\">*</span>\n }\n @if (tooltip) {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [size]=\"16\"\n class=\"inline-block align-middle ml-0.5 text-text-secondary cursor-help relative -top-px\"\n [matTooltip]=\"tooltip\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n ></fx-ui-hero-icon>\n }\n </label>\n }\n\n <mat-form-field\n [attr.invalid]=\"invalid || null\"\n class=\"fx-select-field w-full shadow-sm\"\n appearance=\"fill\"\n >\n <mat-select\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event.value)\"\n (openedChange)=\"onOpened($event)\"\n (blur)=\"onTouched()\"\n >\n @if (enableSearch) {\n <div class=\"px-semi w-full\">\n <input\n type=\"text\"\n [placeholder]=\"'Search'\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n class=\"text-text-primary placeholder:text-text-placeholder w-full bg-bg-primary border-b px-semi py-normal border-border-default focus:outline-none focus:border-gradient-primary-start text-sm text-text-primary tracking-normal ring-0 transition-colors duration-500 ease-in-out\"\n />\n </div>\n }\n <mat-option *ngFor=\"let option of filteredOptions\" [value]=\"option.value\">\n <span class=\"txt-default\">{{ option.label }}</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n @if (invalid) {\n <div class=\"txt-invalid text-left\">\n {{ getErrorMessage(label) }}\n </div>\n }\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:.375rem;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(--gradient-primary-start))!important;outline:none!important;border-radius:.375rem}::ng-deep .fx-select-field.mat-form-field-invalid .mat-mdc-form-field-flex{border:1px solid rgb(var(--bg-error-bold))!important;box-shadow:none!important}::ng-deep mat-form-field[invalid] .mat-mdc-form-field-flex{border:1px solid rgb(var(--bg-error-bold))!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-
|
|
2844
|
-
}], ctorParameters: () => [{ type:
|
|
3358
|
+
args: [{ selector: 'fx-ui-select', standalone: false, template: "<div class=\"mb-4 text-left w-full\" [class]=\"class\">\n @if (label) {\n <label class=\"block txt-field-label\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\">*</span>\n }\n @if (tooltip) {\n <fx-ui-hero-icon\n icon=\"information-circle\"\n [size]=\"16\"\n class=\"inline-block align-middle ml-0.5 text-text-secondary cursor-help relative -top-px\"\n [matTooltip]=\"tooltip\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n ></fx-ui-hero-icon>\n }\n </label>\n }\n\n <mat-form-field\n [attr.invalid]=\"invalid || null\"\n class=\"fx-select-field w-full shadow-sm\"\n appearance=\"fill\"\n >\n <mat-select\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [multiple]=\"multiple\"\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event.value)\"\n (openedChange)=\"onOpened($event)\"\n (blur)=\"onTouched()\"\n >\n @if (enableSearch) {\n <div class=\"px-semi w-full\">\n <input\n type=\"text\"\n [placeholder]=\"'Search'\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange($event)\"\n (click)=\"$event.stopPropagation()\"\n class=\"text-text-primary placeholder:text-text-placeholder w-full bg-bg-primary border-b px-semi py-normal border-border-default focus:outline-none focus:border-gradient-primary-start text-sm text-text-primary tracking-normal ring-0 transition-colors duration-500 ease-in-out\"\n />\n </div>\n }\n <mat-option *ngFor=\"let option of filteredOptions\" [value]=\"option.value\">\n <span class=\"txt-default\">{{ option.label }}</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n @if (invalid) {\n <div class=\"txt-invalid text-left\">\n {{ getErrorMessage(label) }}\n </div>\n }\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:.375rem;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(--gradient-primary-start))!important;outline:none!important;border-radius:.375rem}::ng-deep .fx-select-field.mat-form-field-invalid .mat-mdc-form-field-flex{border:1px solid rgb(var(--bg-error-bold))!important;box-shadow:none!important}::ng-deep mat-form-field[invalid] .mat-mdc-form-field-flex{border:1px solid rgb(var(--bg-error-bold))!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 .mat-mdc-select-arrow svg{display:none!important}::ng-deep .fx-select-field .mat-mdc-select-arrow-wrapper .mat-mdc-select-arrow{width:8px!important;height:8px!important;border-style:solid;border-color:currentColor;border-width:0 1.5px 1.5px 0;transform:rotate(45deg);margin-top:-3px;color:rgb(var(--text-secondary))!important}::ng-deep .mat-mdc-select-panel{background-color:rgb(var(--bg-primary))!important;border:1px solid rgb(var(--border-default))!important;border-radius:.375rem!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}.mat-select-panel .search-option-full-width{padding-left:0!important;padding-right:0!important;display:block;pointer-events:none;line-height:initial;height:auto}.mat-select-panel .search-option-full-width .search-bar{width:100%;padding:8px 16px;border:none;border-bottom:1px solid #ddd;box-sizing:border-box}::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-form-field-flex,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-form-field-flex{background-color:rgb(var(--bg-primary-hover))!important;border-color:rgb(var(--border-default))!important;cursor:not-allowed!important;opacity:.6;box-shadow:none!important}::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-select-value,::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-select-placeholder,::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-select-arrow,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-select-value,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-select-placeholder,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-select-arrow{color:rgb(var(--text-placeholder))!important}::ng-deep .fx-select-field.mat-form-field-disabled .mat-mdc-select,::ng-deep .fx-select-field:has(.mat-mdc-select-disabled) .mat-mdc-select{cursor:not-allowed!important}\n"] }]
|
|
3359
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
|
|
2845
3360
|
type: Input
|
|
2846
3361
|
}], tooltip: [{
|
|
2847
3362
|
type: Input
|
|
@@ -2851,8 +3366,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2851
3366
|
type: Input
|
|
2852
3367
|
}], multiple: [{
|
|
2853
3368
|
type: Input
|
|
2854
|
-
}], disabled: [{
|
|
2855
|
-
type: Input
|
|
2856
3369
|
}], errorMessages: [{
|
|
2857
3370
|
type: Input
|
|
2858
3371
|
}], required: [{
|
|
@@ -2871,7 +3384,7 @@ class SkeletonTableLoadingComponent {
|
|
|
2871
3384
|
columns = 5;
|
|
2872
3385
|
rows = 5;
|
|
2873
3386
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonTableLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2874
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SkeletonTableLoadingComponent, isStandalone: false, selector: "fx-ui-skeleton-table-loading", inputs: { columns: "columns", rows: "rows" }, ngImport: i0, template: "<div class=\"w-full animate-pulse space-y-normal\">\n <div\n class=\"grid gap-small\"\n [ngStyle]=\"{ 'grid-template-columns': 'repeat(' + columns + ', minmax(0, 1fr))' }\"\n >\n @for(col of [].constructor(columns); track col) {\n <div class=\"h-6 bg-bg-hover rounded\"></div>\n }\n </div>\n\n @for(row of [].constructor(rows); track row) {\n <div\n class=\"grid gap-small\"\n [ngStyle]=\"{ 'grid-template-columns': 'repeat(' + columns + ', minmax(0, 1fr))' }\"\n >\n @for(col of [].constructor(columns); track col) {\n <div class=\"h-7 bg-bg-hover rounded\"></div>\n }\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type:
|
|
3387
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SkeletonTableLoadingComponent, isStandalone: false, selector: "fx-ui-skeleton-table-loading", inputs: { columns: "columns", rows: "rows" }, ngImport: i0, template: "<div class=\"w-full animate-pulse space-y-normal\">\n <div\n class=\"grid gap-small\"\n [ngStyle]=\"{ 'grid-template-columns': 'repeat(' + columns + ', minmax(0, 1fr))' }\"\n >\n @for(col of [].constructor(columns); track col) {\n <div class=\"h-6 bg-bg-hover rounded\"></div>\n }\n </div>\n\n @for(row of [].constructor(rows); track row) {\n <div\n class=\"grid gap-small\"\n [ngStyle]=\"{ 'grid-template-columns': 'repeat(' + columns + ', minmax(0, 1fr))' }\"\n >\n @for(col of [].constructor(columns); track col) {\n <div class=\"h-7 bg-bg-hover rounded\"></div>\n }\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
|
|
2875
3388
|
}
|
|
2876
3389
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonTableLoadingComponent, decorators: [{
|
|
2877
3390
|
type: Component,
|
|
@@ -2890,11 +3403,10 @@ class SliderComponent extends FxComponent {
|
|
|
2890
3403
|
max = 100;
|
|
2891
3404
|
step = 1;
|
|
2892
3405
|
vertical = false;
|
|
2893
|
-
disabled = false;
|
|
2894
3406
|
valueChange = new EventEmitter();
|
|
2895
3407
|
dragging = false;
|
|
2896
|
-
constructor(
|
|
2897
|
-
super(
|
|
3408
|
+
constructor(ref) {
|
|
3409
|
+
super();
|
|
2898
3410
|
this.ref = ref;
|
|
2899
3411
|
}
|
|
2900
3412
|
ngAfterViewInit() {
|
|
@@ -2942,7 +3454,9 @@ class SliderComponent extends FxComponent {
|
|
|
2942
3454
|
try {
|
|
2943
3455
|
event.target.releasePointerCapture(event.pointerId);
|
|
2944
3456
|
}
|
|
2945
|
-
catch {
|
|
3457
|
+
catch {
|
|
3458
|
+
// pointer capture may already be released
|
|
3459
|
+
}
|
|
2946
3460
|
this.dragging = false;
|
|
2947
3461
|
this.onTouched();
|
|
2948
3462
|
}
|
|
@@ -3008,13 +3522,13 @@ class SliderComponent extends FxComponent {
|
|
|
3008
3522
|
? { bottom: `${this.percent}%`, transform: 'translateY(50%)' }
|
|
3009
3523
|
: { left: `${this.percent}%`, transform: 'translateX(-50%)' };
|
|
3010
3524
|
}
|
|
3011
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SliderComponent, deps: [{ token:
|
|
3012
|
-
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"
|
|
3525
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SliderComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3526
|
+
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" }, 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: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
|
|
3013
3527
|
}
|
|
3014
3528
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SliderComponent, decorators: [{
|
|
3015
3529
|
type: Component,
|
|
3016
3530
|
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" }]
|
|
3017
|
-
}], ctorParameters: () => [{ type:
|
|
3531
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { trackRef: [{
|
|
3018
3532
|
type: ViewChild,
|
|
3019
3533
|
args: ['track', { static: true }]
|
|
3020
3534
|
}], thumbRef: [{
|
|
@@ -3028,8 +3542,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
3028
3542
|
type: Input
|
|
3029
3543
|
}], vertical: [{
|
|
3030
3544
|
type: Input
|
|
3031
|
-
}], disabled: [{
|
|
3032
|
-
type: Input
|
|
3033
3545
|
}], valueChange: [{
|
|
3034
3546
|
type: Output
|
|
3035
3547
|
}], onKeydown: [{
|
|
@@ -3039,17 +3551,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
3039
3551
|
|
|
3040
3552
|
class SwitchComponent extends FxComponent {
|
|
3041
3553
|
cdr;
|
|
3042
|
-
disabled = false;
|
|
3043
3554
|
onSwitch = new EventEmitter();
|
|
3044
3555
|
ngAfterViewInit() {
|
|
3045
3556
|
this.cdr.detectChanges();
|
|
3046
3557
|
}
|
|
3047
|
-
constructor(
|
|
3048
|
-
super(
|
|
3558
|
+
constructor(cdr) {
|
|
3559
|
+
super();
|
|
3049
3560
|
this.cdr = cdr;
|
|
3050
3561
|
}
|
|
3051
|
-
|
|
3052
|
-
this.
|
|
3562
|
+
writeValue(value) {
|
|
3563
|
+
this.value = value ?? false;
|
|
3053
3564
|
}
|
|
3054
3565
|
toggle() {
|
|
3055
3566
|
if (this.disabled)
|
|
@@ -3059,15 +3570,13 @@ class SwitchComponent extends FxComponent {
|
|
|
3059
3570
|
this.onChange(this.value);
|
|
3060
3571
|
this.onTouched();
|
|
3061
3572
|
}
|
|
3062
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SwitchComponent, deps: [{ token:
|
|
3063
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SwitchComponent, isStandalone: false, selector: "fx-ui-switch",
|
|
3573
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SwitchComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3574
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SwitchComponent, isStandalone: false, selector: "fx-ui-switch", outputs: { onSwitch: "onSwitch" }, usesInheritance: true, ngImport: i0, template: "<div\n class=\"relative 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: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
3064
3575
|
}
|
|
3065
3576
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SwitchComponent, decorators: [{
|
|
3066
3577
|
type: Component,
|
|
3067
3578
|
args: [{ selector: 'fx-ui-switch', standalone: false, template: "<div\n class=\"relative 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" }]
|
|
3068
|
-
}], ctorParameters: () => [{ type:
|
|
3069
|
-
type: Input
|
|
3070
|
-
}], onSwitch: [{
|
|
3579
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { onSwitch: [{
|
|
3071
3580
|
type: Output
|
|
3072
3581
|
}] } });
|
|
3073
3582
|
|
|
@@ -3175,7 +3684,7 @@ class TabGroupComponent {
|
|
|
3175
3684
|
this.updateUnderlinePosition();
|
|
3176
3685
|
}
|
|
3177
3686
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabGroupComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
|
|
3178
|
-
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) {\n <fx-ui-hero-icon\n [icon]=\"tab.icon\"\n [size]=\"20\"\n class=\"flex mr-[2px]\"\n [ngClass]=\"{\n 'text-gradient-primary-start mb-small': i === activeIndex,\n 'text-text-placeholder': i !== activeIndex,\n }\"\n ></fx-ui-hero-icon>\n }\n <div\n [ngClass]=\"\n i === activeIndex ? 'txt-field-label text-gradient-primary-start' : 'txt-placeholder'\n \"\n >\n {{ tab.label }}\n </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(--gradient-primary-start));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;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:
|
|
3687
|
+
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) {\n <fx-ui-hero-icon\n [icon]=\"tab.icon\"\n [size]=\"20\"\n class=\"flex mr-[2px]\"\n [ngClass]=\"{\n 'text-gradient-primary-start mb-small': i === activeIndex,\n 'text-text-placeholder': i !== activeIndex,\n }\"\n ></fx-ui-hero-icon>\n }\n <div\n [ngClass]=\"\n i === activeIndex ? 'txt-field-label text-gradient-primary-start' : 'txt-placeholder'\n \"\n >\n {{ tab.label }}\n </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(--gradient-primary-start));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;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: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
3179
3688
|
}
|
|
3180
3689
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabGroupComponent, decorators: [{
|
|
3181
3690
|
type: Component,
|
|
@@ -3218,12 +3727,12 @@ class TagComponent {
|
|
|
3218
3727
|
rounded = true;
|
|
3219
3728
|
icon;
|
|
3220
3729
|
solid = false;
|
|
3221
|
-
|
|
3730
|
+
clicked = new EventEmitter();
|
|
3222
3731
|
onClick() {
|
|
3223
|
-
this.
|
|
3732
|
+
this.clicked.emit();
|
|
3224
3733
|
}
|
|
3225
3734
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3226
|
-
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", solid: "solid" }, outputs: {
|
|
3735
|
+
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", solid: "solid" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<div\n (click)=\"onClick()\"\n [class]=\"\n `flex flex-row gap-small ${rounded ? 'tag-round' : 'tag-square'} tag-${type}${solid ? '-solid' : ''}`\n \"\n>\n @if (icon) {\n <fx-ui-hero-icon\n [class]=\"`flex txt-tag-${type} ${solid && type !== 'default' ? 'text-white' : ''}`\"\n [icon]=\"icon\"\n [size]=\"18\"\n ></fx-ui-hero-icon>\n }\n\n <div [class]=\"`txt-tag-${type} ${solid && type !== 'default' ? 'text-white font-medium' : ''}`\">\n {{ label }}\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
3227
3736
|
}
|
|
3228
3737
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TagComponent, decorators: [{
|
|
3229
3738
|
type: Component,
|
|
@@ -3238,7 +3747,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
3238
3747
|
type: Input
|
|
3239
3748
|
}], solid: [{
|
|
3240
3749
|
type: Input
|
|
3241
|
-
}],
|
|
3750
|
+
}], clicked: [{
|
|
3242
3751
|
type: Output
|
|
3243
3752
|
}] } });
|
|
3244
3753
|
|
|
@@ -3327,7 +3836,7 @@ class TreeDiagram {
|
|
|
3327
3836
|
this.cdr.detectChanges();
|
|
3328
3837
|
}
|
|
3329
3838
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TreeDiagram, deps: [{ token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3330
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: TreeDiagram, isStandalone: false, selector: "fx-ui-tree-diagram", inputs: { data: "data" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }, { propertyName: "root", first: true, predicate: ["root"], descendants: true }, { propertyName: "children", predicate: ["child"], descendants: true }], ngImport: i0, template: "<div class=\"relative p-8\" #container>\n\n <!-- ROOT -->\n <div\n #root\n class=\"mx-auto w-fit bg-blue-600 text-white px-7 py-3 rounded-md font-semibold text-center\"\n >\n {{ data.label }}\n </div>\n\n <!-- CHILDREN -->\n <div class=\"mt-16 flex justify-center gap-16\">\n <div\n *ngFor=\"let child of data.children\"\n #child\n class=\"w-48 bg-rose-600 text-white px-4 py-4 rounded-lg text-center\"\n >\n <div class=\"font-semibold text-lg\">{{ child.label }}</div>\n <div class=\"mt-1 text-sm opacity-90\">{{ child.status }}</div>\n </div>\n </div>\n\n <!-- SVG CONNECTORS -->\n <svg\n class=\"absolute inset-0 pointer-events-none\"\n [attr.width]=\"svgWidth\"\n [attr.height]=\"svgHeight\"\n >\n <line\n *ngFor=\"let line of lines\"\n [attr.x1]=\"line.x1\"\n [attr.y1]=\"line.y1\"\n [attr.x2]=\"line.x2\"\n [attr.y2]=\"line.y2\"\n stroke=\"#1f2937\"\n stroke-width=\"2\"\n />\n </svg>\n\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type:
|
|
3839
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: TreeDiagram, isStandalone: false, selector: "fx-ui-tree-diagram", inputs: { data: "data" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }, { propertyName: "root", first: true, predicate: ["root"], descendants: true }, { propertyName: "children", predicate: ["child"], descendants: true }], ngImport: i0, template: "<div class=\"relative p-8\" #container>\n\n <!-- ROOT -->\n <div\n #root\n class=\"mx-auto w-fit bg-blue-600 text-white px-7 py-3 rounded-md font-semibold text-center\"\n >\n {{ data.label }}\n </div>\n\n <!-- CHILDREN -->\n <div class=\"mt-16 flex justify-center gap-16\">\n <div\n *ngFor=\"let child of data.children\"\n #child\n class=\"w-48 bg-rose-600 text-white px-4 py-4 rounded-lg text-center\"\n >\n <div class=\"font-semibold text-lg\">{{ child.label }}</div>\n <div class=\"mt-1 text-sm opacity-90\">{{ child.status }}</div>\n </div>\n </div>\n\n <!-- SVG CONNECTORS -->\n <svg\n class=\"absolute inset-0 pointer-events-none\"\n [attr.width]=\"svgWidth\"\n [attr.height]=\"svgHeight\"\n >\n <line\n *ngFor=\"let line of lines\"\n [attr.x1]=\"line.x1\"\n [attr.y1]=\"line.y1\"\n [attr.x2]=\"line.x2\"\n [attr.y2]=\"line.y2\"\n stroke=\"#1f2937\"\n stroke-width=\"2\"\n />\n </svg>\n\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
3331
3840
|
}
|
|
3332
3841
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TreeDiagram, decorators: [{
|
|
3333
3842
|
type: Component,
|
|
@@ -3380,11 +3889,11 @@ class KanbanBoardComponent {
|
|
|
3380
3889
|
});
|
|
3381
3890
|
}
|
|
3382
3891
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: KanbanBoardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3383
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: KanbanBoardComponent, isStandalone: false, selector: "fx-ui-kanban-board", inputs: { columns: "columns", itemTemplate: "itemTemplate" }, outputs: { columnChanged: "columnChanged" }, ngImport: i0, template: "<div class=\"kanban-board\">\n <div class=\"kanban-columns\">\n @for (column of columns; track column.id) {\n <div class=\"kanban-column\">\n <div class=\"kanban-column-header\">\n <h3 class=\"kanban-column-title\">{{ column.title }}</h3>\n <span class=\"kanban-column-count\">{{ column.items.length }}</span>\n </div>\n \n <div\n class=\"kanban-column-content\"\n cdkDropList\n [id]=\"column.id\"\n [cdkDropListData]=\"column.items\"\n [cdkDropListConnectedTo]=\"getColumnIds()\"\n (cdkDropListDropped)=\"onDrop($event, column.id)\"\n >\n @for (item of column.items; track $index) {\n <div class=\"kanban-item\" cdkDrag>\n <div class=\"kanban-item-placeholder\" *cdkDragPlaceholder></div>\n \n @if (itemTemplate) {\n <ng-container\n *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item, index: $index }\"\n ></ng-container>\n } @else {\n <div class=\"kanban-item-default\">\n {{ item }}\n </div>\n }\n </div>\n }\n \n @if (column.items.length === 0) {\n <div class=\"kanban-column-empty\">\n Drop items here\n </div>\n }\n </div>\n </div>\n }\n </div>\n</div>\n", styles: [".kanban-board{height:100%;width:100%;overflow-x:auto}.kanban-columns{display:flex;min-height:100%;gap:1rem;padding:1rem}.kanban-column{display:flex;min-width:300px;flex-direction:column;border-radius:.5rem;--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}}.kanban-column{flex-shrink:0}.kanban-column-header{display:flex;align-items:center;justify-content:space-between;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1));padding:1rem}@media(prefers-color-scheme:dark){.kanban-column-header{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}}.kanban-column-title{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column-title{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}}.kanban-column-count{border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1));padding:.25rem .5rem;font-size:.875rem;font-weight:500;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column-count{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}}.kanban-column-content{flex:1 1 0%}.kanban-column-content>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.kanban-column-content{overflow-y:auto;padding:1rem;min-height:200px}.kanban-item{border-radius:.5rem;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(255 255 255 / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@media(prefers-color-scheme:dark){.kanban-item{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}}.kanban-item{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;cursor:move}.kanban-item:hover{--tw-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / .1), 0 2px 4px -2px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.kanban-item-default{padding:1rem;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-item-default{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}}.kanban-item-placeholder{border-radius:.5rem;border-width:2px;border-style:dashed;--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-item-placeholder{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}}.kanban-item-placeholder{opacity:.5;min-height:60px}.kanban-column-empty{display:flex;height:8rem;align-items:center;justify-content:center;font-size:.875rem;--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column-empty{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}}.kanban-column-empty{border-radius:.5rem;border-width:2px;border-style:dashed;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column-empty{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}}.cdk-drag-preview{border-radius:.5rem;opacity:.8;--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)}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.kanban-column-content.cdk-drop-list-dragging .kanban-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "directive", type:
|
|
3892
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: KanbanBoardComponent, isStandalone: false, selector: "fx-ui-kanban-board", inputs: { columns: "columns", itemTemplate: "itemTemplate" }, outputs: { columnChanged: "columnChanged" }, ngImport: i0, template: "<div class=\"kanban-board\">\n <div class=\"kanban-columns\">\n @for (column of columns; track column.id) {\n <div class=\"kanban-column\">\n <div class=\"kanban-column-header\">\n <h3 class=\"kanban-column-title\">{{ column.title }}</h3>\n <span class=\"kanban-column-count\">{{ column.items.length }}</span>\n </div>\n \n <div\n class=\"kanban-column-content\"\n cdkDropList\n [id]=\"column.id\"\n [cdkDropListData]=\"column.items\"\n [cdkDropListConnectedTo]=\"getColumnIds()\"\n (cdkDropListDropped)=\"onDrop($event, column.id)\"\n >\n @for (item of column.items; track $index) {\n <div class=\"kanban-item\" cdkDrag>\n <div class=\"kanban-item-placeholder\" *cdkDragPlaceholder></div>\n \n @if (itemTemplate) {\n <ng-container\n *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item, index: $index }\"\n ></ng-container>\n } @else {\n <div class=\"kanban-item-default\">\n {{ item }}\n </div>\n }\n </div>\n }\n \n @if (column.items.length === 0) {\n <div class=\"kanban-column-empty\">\n Drop items here\n </div>\n }\n </div>\n </div>\n }\n </div>\n</div>\n", styles: [".kanban-board{height:100%;width:100%;overflow-x:auto}.kanban-columns{display:flex;min-height:100%;gap:1rem;padding:1rem}.kanban-column{display:flex;min-width:300px;flex-direction:column;border-radius:.5rem;--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}}.kanban-column{flex-shrink:0}.kanban-column-header{display:flex;align-items:center;justify-content:space-between;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1));padding:1rem}@media (prefers-color-scheme: dark){.kanban-column-header{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}}.kanban-column-title{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column-title{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}}.kanban-column-count{border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1));padding:.25rem .5rem;font-size:.875rem;font-weight:500;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column-count{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}}.kanban-column-content{flex:1 1 0%}.kanban-column-content>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.kanban-column-content{overflow-y:auto;padding:1rem;min-height:200px}.kanban-item{border-radius:.5rem;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(255 255 255 / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@media (prefers-color-scheme: dark){.kanban-item{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}}.kanban-item{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;cursor:move}.kanban-item:hover{--tw-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / .1), 0 2px 4px -2px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.kanban-item-default{padding:1rem;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-item-default{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}}.kanban-item-placeholder{border-radius:.5rem;border-width:2px;border-style:dashed;--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-item-placeholder{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}}.kanban-item-placeholder{opacity:.5;min-height:60px}.kanban-column-empty{display:flex;height:8rem;align-items:center;justify-content:center;font-size:.875rem;--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column-empty{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}}.kanban-column-empty{border-radius:.5rem;border-width:2px;border-style:dashed;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column-empty{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}}.cdk-drag-preview{border-radius:.5rem;opacity:.8;--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)}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.kanban-column-content.cdk-drop-list-dragging .kanban-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2$3.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i2$3.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i2$3.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }] });
|
|
3384
3893
|
}
|
|
3385
3894
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: KanbanBoardComponent, decorators: [{
|
|
3386
3895
|
type: Component,
|
|
3387
|
-
args: [{ selector: 'fx-ui-kanban-board', standalone: false, template: "<div class=\"kanban-board\">\n <div class=\"kanban-columns\">\n @for (column of columns; track column.id) {\n <div class=\"kanban-column\">\n <div class=\"kanban-column-header\">\n <h3 class=\"kanban-column-title\">{{ column.title }}</h3>\n <span class=\"kanban-column-count\">{{ column.items.length }}</span>\n </div>\n \n <div\n class=\"kanban-column-content\"\n cdkDropList\n [id]=\"column.id\"\n [cdkDropListData]=\"column.items\"\n [cdkDropListConnectedTo]=\"getColumnIds()\"\n (cdkDropListDropped)=\"onDrop($event, column.id)\"\n >\n @for (item of column.items; track $index) {\n <div class=\"kanban-item\" cdkDrag>\n <div class=\"kanban-item-placeholder\" *cdkDragPlaceholder></div>\n \n @if (itemTemplate) {\n <ng-container\n *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item, index: $index }\"\n ></ng-container>\n } @else {\n <div class=\"kanban-item-default\">\n {{ item }}\n </div>\n }\n </div>\n }\n \n @if (column.items.length === 0) {\n <div class=\"kanban-column-empty\">\n Drop items here\n </div>\n }\n </div>\n </div>\n }\n </div>\n</div>\n", styles: [".kanban-board{height:100%;width:100%;overflow-x:auto}.kanban-columns{display:flex;min-height:100%;gap:1rem;padding:1rem}.kanban-column{display:flex;min-width:300px;flex-direction:column;border-radius:.5rem;--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}}.kanban-column{flex-shrink:0}.kanban-column-header{display:flex;align-items:center;justify-content:space-between;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1));padding:1rem}@media(prefers-color-scheme:dark){.kanban-column-header{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}}.kanban-column-title{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column-title{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}}.kanban-column-count{border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1));padding:.25rem .5rem;font-size:.875rem;font-weight:500;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column-count{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}}.kanban-column-content{flex:1 1 0%}.kanban-column-content>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.kanban-column-content{overflow-y:auto;padding:1rem;min-height:200px}.kanban-item{border-radius:.5rem;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(255 255 255 / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@media(prefers-color-scheme:dark){.kanban-item{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}}.kanban-item{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;cursor:move}.kanban-item:hover{--tw-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / .1), 0 2px 4px -2px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.kanban-item-default{padding:1rem;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-item-default{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}}.kanban-item-placeholder{border-radius:.5rem;border-width:2px;border-style:dashed;--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-item-placeholder{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}}.kanban-item-placeholder{opacity:.5;min-height:60px}.kanban-column-empty{display:flex;height:8rem;align-items:center;justify-content:center;font-size:.875rem;--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column-empty{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}}.kanban-column-empty{border-radius:.5rem;border-width:2px;border-style:dashed;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}@media(prefers-color-scheme:dark){.kanban-column-empty{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}}.cdk-drag-preview{border-radius:.5rem;opacity:.8;--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)}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.kanban-column-content.cdk-drop-list-dragging .kanban-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}\n"] }]
|
|
3896
|
+
args: [{ selector: 'fx-ui-kanban-board', standalone: false, template: "<div class=\"kanban-board\">\n <div class=\"kanban-columns\">\n @for (column of columns; track column.id) {\n <div class=\"kanban-column\">\n <div class=\"kanban-column-header\">\n <h3 class=\"kanban-column-title\">{{ column.title }}</h3>\n <span class=\"kanban-column-count\">{{ column.items.length }}</span>\n </div>\n \n <div\n class=\"kanban-column-content\"\n cdkDropList\n [id]=\"column.id\"\n [cdkDropListData]=\"column.items\"\n [cdkDropListConnectedTo]=\"getColumnIds()\"\n (cdkDropListDropped)=\"onDrop($event, column.id)\"\n >\n @for (item of column.items; track $index) {\n <div class=\"kanban-item\" cdkDrag>\n <div class=\"kanban-item-placeholder\" *cdkDragPlaceholder></div>\n \n @if (itemTemplate) {\n <ng-container\n *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item, index: $index }\"\n ></ng-container>\n } @else {\n <div class=\"kanban-item-default\">\n {{ item }}\n </div>\n }\n </div>\n }\n \n @if (column.items.length === 0) {\n <div class=\"kanban-column-empty\">\n Drop items here\n </div>\n }\n </div>\n </div>\n }\n </div>\n</div>\n", styles: [".kanban-board{height:100%;width:100%;overflow-x:auto}.kanban-columns{display:flex;min-height:100%;gap:1rem;padding:1rem}.kanban-column{display:flex;min-width:300px;flex-direction:column;border-radius:.5rem;--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}}.kanban-column{flex-shrink:0}.kanban-column-header{display:flex;align-items:center;justify-content:space-between;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1));padding:1rem}@media (prefers-color-scheme: dark){.kanban-column-header{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}}.kanban-column-title{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column-title{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}}.kanban-column-count{border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1));padding:.25rem .5rem;font-size:.875rem;font-weight:500;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column-count{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}}.kanban-column-content{flex:1 1 0%}.kanban-column-content>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.kanban-column-content{overflow-y:auto;padding:1rem;min-height:200px}.kanban-item{border-radius:.5rem;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(255 255 255 / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@media (prefers-color-scheme: dark){.kanban-item{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}}.kanban-item{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;cursor:move}.kanban-item:hover{--tw-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / .1), 0 2px 4px -2px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.kanban-item-default{padding:1rem;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-item-default{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}}.kanban-item-placeholder{border-radius:.5rem;border-width:2px;border-style:dashed;--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-item-placeholder{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}}.kanban-item-placeholder{opacity:.5;min-height:60px}.kanban-column-empty{display:flex;height:8rem;align-items:center;justify-content:center;font-size:.875rem;--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column-empty{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}}.kanban-column-empty{border-radius:.5rem;border-width:2px;border-style:dashed;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}@media (prefers-color-scheme: dark){.kanban-column-empty{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}}.cdk-drag-preview{border-radius:.5rem;opacity:.8;--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)}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.kanban-column-content.cdk-drop-list-dragging .kanban-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}\n"] }]
|
|
3388
3897
|
}], propDecorators: { columns: [{
|
|
3389
3898
|
type: Input
|
|
3390
3899
|
}], itemTemplate: [{
|
|
@@ -3496,7 +4005,7 @@ class DrawerComponent {
|
|
|
3496
4005
|
return this.isExpanded ? 'expanded' : 'collapsed';
|
|
3497
4006
|
}
|
|
3498
4007
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DrawerComponent, deps: [{ token: i1$4.Router }], target: i0.ɵɵFactoryTarget.Component });
|
|
3499
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: DrawerComponent, isStandalone: false, selector: "fx-ui-drawer", inputs: { items: "items", isExpanded: "isExpanded", logo: "logo", version: "version" }, outputs: { toggleExpanded: "toggleExpanded", itemClicked: "itemClicked" }, ngImport: i0, template: "<div class=\"drawer-host-wrapper\">\n <a\n href=\"/\"\n class=\"h-[60px]\"\n [ngClass]=\"{ 'flex items-center justify-center': !isExpanded, 'p-4': isExpanded }\"\n >\n @if (logo) {\n <img\n [src]=\"logo\"\n class=\"h-[20px] w-auto transition-all duration-300 ease-in-out\"\n [ngClass]=\"{ 'scale-90': !isExpanded, 'ml-5': isExpanded }\"\n />\n } @else {\n <div class=\"h-[30px] w-auto transition-all duration-300 ease-in-out\"></div>\n }\n </a>\n <div class=\"drawer-container\" [@drawerExpand]=\"getDrawerState()\">\n <!-- Navigation Items -->\n <nav class=\"drawer-nav\">\n <ng-container *ngFor=\"let item of items\">\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n </ng-container>\n </nav>\n\n <!-- Version -->\n <div *ngIf=\"version\" class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n <span *ngIf=\"isExpanded\">{{ version }}</span>\n <span *ngIf=\"!isExpanded\" class=\"drawer-version-dot\"></span>\n </div>\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n (click)=\"toggleDrawer()\"\n [matTooltip]=\"isExpanded ? 'Collapse' : 'Expand'\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n matTooltipPosition=\"right\"\n >\n <fx-ui-hero-icon\n [icon]=\"isExpanded ? 'chevron-left' : 'chevron-right'\"\n [size]=\"16\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n </button>\n</div>\n\n<!-- Recursive Template for Drawer Items -->\n<ng-template #drawerItem let-item let-level=\"level\">\n <div class=\"drawer-item-wrapper\">\n <!-- Item Button/Link -->\n <a\n *ngIf=\"item.route && !item.children\"\n [routerLink]=\"item.route\"\n class=\"drawer-item\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 16 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"20\" class=\"item-icon\"></fx-ui-hero-icon>\n <span *ngIf=\"isExpanded\" class=\"item-label\">{{ item.label }}</span>\n </div>\n </a>\n\n <button\n *ngIf=\"!item.route || item.children\"\n type=\"button\"\n class=\"drawer-item\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 16 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-sm font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"20\" class=\"item-icon\"></fx-ui-hero-icon>\n <span *ngIf=\"isExpanded\" class=\"item-label\">{{ item.label }}</span>\n <fx-ui-hero-icon\n *ngIf=\"isExpanded && item.children && item.children.length > 0\"\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n </div>\n </button>\n\n <!-- Accordion Children -->\n <div\n *ngIf=\"item.children && item.children.length > 0\"\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n <ng-container *ngFor=\"let child of item.children\">\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n </ng-container>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.drawer-host-wrapper{position:relative;height:100%;border-right-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1))}.drawer-container{display:flex;height:100%;flex-direction:column;overflow:auto;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));padding-left:.5rem;padding-right:.5rem;transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:1.5rem;width:1.5rem;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);right:-12px;transition:all .2s ease}.toggle-btn:hover{--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / .1), 0 2px 4px -2px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.toggle-btn:active{transform:translateY(-50%) scale(.9)}.toggle-btn:focus-visible{outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary) / 1)}.drawer-nav{flex:1 1 0%;overflow-y:auto;overflow-x:hidden;padding-top:.5rem;padding-bottom:.5rem}.drawer-nav::-webkit-scrollbar{width:.375rem}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:.125rem;--tw-bg-opacity: 1;background-color:rgb(var(--border-default) / var(--tw-bg-opacity, 1))}.drawer-nav::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(var(--text-placeholder) / var(--tw-bg-opacity, 1))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;margin-top:.25rem;display:flex;min-height:2rem;width:100%;cursor:pointer;align-items:center;border-radius:.25rem;border-style:none;background-color:transparent;padding:.5rem 1rem;--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1));text-decoration-line:none;transition:all .2s ease}.drawer-item:hover{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}.drawer-item.active{background-image:linear-gradient(135deg,rgb(var(--gradient-primary-start)),rgb(var(--gradient-primary-end)));font-weight:500;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.drawer-item.active .item-icon{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.drawer-item:active{transform:scale(.98)}.drawer-item:focus-visible{outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary) / 1)}.drawer-item{-webkit-tap-highlight-color:transparent;outline:2px solid transparent;outline-offset:2px}.item-content{display:flex;width:100%;align-items:center;gap:.75rem;overflow:hidden}.item-icon{flex-shrink:0;color:inherit}.item-label{flex:1 1 0%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;font-size:13px;line-height:1.25rem}.chevron-icon{margin-left:auto;flex-shrink:0;--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;-webkit-user-select:none;user-select:none;align-items:center;justify-content:center;border-top-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));padding:.75rem 1rem;font-size:11px;--tw-text-opacity: 1;color:rgb(var(--text-placeholder) / var(--tw-text-opacity, 1));font-family:Roboto,monospace}.drawer-version-dot{display:block;height:.375rem;width:.375rem;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(var(--text-placeholder) / var(--tw-bg-opacity, 1))}.drawer-container[style*=\"width: 64px\"] .drawer-item{justify-content:center;padding-left:16px!important}.drawer-container[style*=\"width: 64px\"] .item-content{justify-content:center}\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: "directive", type: i1$4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], animations: [
|
|
4008
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: DrawerComponent, isStandalone: false, selector: "fx-ui-drawer", inputs: { items: "items", isExpanded: "isExpanded", logo: "logo", version: "version" }, outputs: { toggleExpanded: "toggleExpanded", itemClicked: "itemClicked" }, ngImport: i0, template: "<div class=\"drawer-host-wrapper\">\n <a\n href=\"/\"\n class=\"h-[60px]\"\n [ngClass]=\"{ 'flex items-center justify-center': !isExpanded, 'p-4': isExpanded }\"\n >\n @if (logo) {\n <img\n [src]=\"logo\"\n class=\"h-[20px] w-auto transition-all duration-300 ease-in-out\"\n [ngClass]=\"{ 'scale-90': !isExpanded, 'ml-5': isExpanded }\"\n />\n } @else {\n <div class=\"h-[30px] w-auto transition-all duration-300 ease-in-out\"></div>\n }\n </a>\n <div class=\"drawer-container\" [@drawerExpand]=\"getDrawerState()\">\n <!-- Navigation Items -->\n <nav class=\"drawer-nav\">\n <ng-container *ngFor=\"let item of items\">\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n </ng-container>\n </nav>\n\n <!-- Version -->\n <div *ngIf=\"version\" class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n <span *ngIf=\"isExpanded\">{{ version }}</span>\n <span *ngIf=\"!isExpanded\" class=\"drawer-version-dot\"></span>\n </div>\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n (click)=\"toggleDrawer()\"\n [matTooltip]=\"isExpanded ? 'Collapse' : 'Expand'\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n matTooltipPosition=\"right\"\n >\n <fx-ui-hero-icon\n [icon]=\"isExpanded ? 'chevron-left' : 'chevron-right'\"\n [size]=\"16\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n </button>\n</div>\n\n<!-- Recursive Template for Drawer Items -->\n<ng-template #drawerItem let-item let-level=\"level\">\n <div class=\"drawer-item-wrapper\">\n <!-- Item Button/Link -->\n <a\n *ngIf=\"item.route && !item.children\"\n [routerLink]=\"item.route\"\n class=\"drawer-item\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 16 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"20\" class=\"item-icon\"></fx-ui-hero-icon>\n <span *ngIf=\"isExpanded\" class=\"item-label\">{{ item.label }}</span>\n </div>\n </a>\n\n <button\n *ngIf=\"!item.route || item.children\"\n type=\"button\"\n class=\"drawer-item\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 16 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-sm font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"20\" class=\"item-icon\"></fx-ui-hero-icon>\n <span *ngIf=\"isExpanded\" class=\"item-label\">{{ item.label }}</span>\n <fx-ui-hero-icon\n *ngIf=\"isExpanded && item.children && item.children.length > 0\"\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n </div>\n </button>\n\n <!-- Accordion Children -->\n <div\n *ngIf=\"item.children && item.children.length > 0\"\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n <ng-container *ngFor=\"let child of item.children\">\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n </ng-container>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.drawer-host-wrapper{position:relative;height:100%;border-right-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1))}.drawer-container{display:flex;height:100%;flex-direction:column;overflow:auto;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));padding-left:.5rem;padding-right:.5rem;transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:1.5rem;width:1.5rem;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);right:-12px;transition:all .2s ease}.toggle-btn:hover{--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / .1), 0 2px 4px -2px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.toggle-btn:active{transform:translateY(-50%) scale(.9)}.toggle-btn:focus-visible{outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary) / 1)}.drawer-nav{flex:1 1 0%;overflow-y:auto;overflow-x:hidden;padding-top:.5rem;padding-bottom:.5rem}.drawer-nav::-webkit-scrollbar{width:.375rem}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:.125rem;--tw-bg-opacity: 1;background-color:rgb(var(--border-default) / var(--tw-bg-opacity, 1))}.drawer-nav::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(var(--text-placeholder) / var(--tw-bg-opacity, 1))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;margin-top:.25rem;display:flex;min-height:2rem;width:100%;cursor:pointer;align-items:center;border-radius:.25rem;border-style:none;background-color:transparent;padding:.5rem 1rem;--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1));text-decoration-line:none;transition:all .2s ease;-webkit-tap-highlight-color:transparent;outline:2px solid transparent;outline-offset:2px}.drawer-item:hover{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}.drawer-item.active{background-image:linear-gradient(135deg,rgb(var(--gradient-primary-start)),rgb(var(--gradient-primary-end)));font-weight:500;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.drawer-item.active .item-icon{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.drawer-item:active{transform:scale(.98)}.drawer-item:focus-visible{outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary) / 1)}.item-content{display:flex;width:100%;align-items:center;gap:.75rem;overflow:hidden}.item-icon{flex-shrink:0;color:inherit}.item-label{flex:1 1 0%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;font-size:13px;line-height:1.25rem}.chevron-icon{margin-left:auto;flex-shrink:0;--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;-webkit-user-select:none;user-select:none;align-items:center;justify-content:center;border-top-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));padding:.75rem 1rem;font-size:11px;--tw-text-opacity: 1;color:rgb(var(--text-placeholder) / var(--tw-text-opacity, 1));font-family:Roboto,monospace}.drawer-version-dot{display:block;height:.375rem;width:.375rem;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(var(--text-placeholder) / var(--tw-bg-opacity, 1))}.drawer-container[style*=\"width: 64px\"] .drawer-item{justify-content:center;padding-left:16px!important}.drawer-container[style*=\"width: 64px\"] .item-content{justify-content:center}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i56.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], animations: [
|
|
3500
4009
|
trigger('drawerExpand', [
|
|
3501
4010
|
state('collapsed', style({ width: '70px' })),
|
|
3502
4011
|
state('expanded', style({ width: '260px' })),
|
|
@@ -3522,7 +4031,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
3522
4031
|
state('expanded', style({ height: '*', overflow: 'visible', opacity: 1 })),
|
|
3523
4032
|
transition('collapsed <=> expanded', animate('300ms cubic-bezier(0.4, 0, 0.2, 1)')),
|
|
3524
4033
|
]),
|
|
3525
|
-
], template: "<div class=\"drawer-host-wrapper\">\n <a\n href=\"/\"\n class=\"h-[60px]\"\n [ngClass]=\"{ 'flex items-center justify-center': !isExpanded, 'p-4': isExpanded }\"\n >\n @if (logo) {\n <img\n [src]=\"logo\"\n class=\"h-[20px] w-auto transition-all duration-300 ease-in-out\"\n [ngClass]=\"{ 'scale-90': !isExpanded, 'ml-5': isExpanded }\"\n />\n } @else {\n <div class=\"h-[30px] w-auto transition-all duration-300 ease-in-out\"></div>\n }\n </a>\n <div class=\"drawer-container\" [@drawerExpand]=\"getDrawerState()\">\n <!-- Navigation Items -->\n <nav class=\"drawer-nav\">\n <ng-container *ngFor=\"let item of items\">\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n </ng-container>\n </nav>\n\n <!-- Version -->\n <div *ngIf=\"version\" class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n <span *ngIf=\"isExpanded\">{{ version }}</span>\n <span *ngIf=\"!isExpanded\" class=\"drawer-version-dot\"></span>\n </div>\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n (click)=\"toggleDrawer()\"\n [matTooltip]=\"isExpanded ? 'Collapse' : 'Expand'\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n matTooltipPosition=\"right\"\n >\n <fx-ui-hero-icon\n [icon]=\"isExpanded ? 'chevron-left' : 'chevron-right'\"\n [size]=\"16\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n </button>\n</div>\n\n<!-- Recursive Template for Drawer Items -->\n<ng-template #drawerItem let-item let-level=\"level\">\n <div class=\"drawer-item-wrapper\">\n <!-- Item Button/Link -->\n <a\n *ngIf=\"item.route && !item.children\"\n [routerLink]=\"item.route\"\n class=\"drawer-item\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 16 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"20\" class=\"item-icon\"></fx-ui-hero-icon>\n <span *ngIf=\"isExpanded\" class=\"item-label\">{{ item.label }}</span>\n </div>\n </a>\n\n <button\n *ngIf=\"!item.route || item.children\"\n type=\"button\"\n class=\"drawer-item\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 16 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-sm font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"20\" class=\"item-icon\"></fx-ui-hero-icon>\n <span *ngIf=\"isExpanded\" class=\"item-label\">{{ item.label }}</span>\n <fx-ui-hero-icon\n *ngIf=\"isExpanded && item.children && item.children.length > 0\"\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n </div>\n </button>\n\n <!-- Accordion Children -->\n <div\n *ngIf=\"item.children && item.children.length > 0\"\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n <ng-container *ngFor=\"let child of item.children\">\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n </ng-container>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.drawer-host-wrapper{position:relative;height:100%;border-right-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1))}.drawer-container{display:flex;height:100%;flex-direction:column;overflow:auto;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));padding-left:.5rem;padding-right:.5rem;transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:1.5rem;width:1.5rem;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);right:-12px;transition:all .2s ease}.toggle-btn:hover{--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / .1), 0 2px 4px -2px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.toggle-btn:active{transform:translateY(-50%) scale(.9)}.toggle-btn:focus-visible{outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary) / 1)}.drawer-nav{flex:1 1 0%;overflow-y:auto;overflow-x:hidden;padding-top:.5rem;padding-bottom:.5rem}.drawer-nav::-webkit-scrollbar{width:.375rem}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:.125rem;--tw-bg-opacity: 1;background-color:rgb(var(--border-default) / var(--tw-bg-opacity, 1))}.drawer-nav::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(var(--text-placeholder) / var(--tw-bg-opacity, 1))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;margin-top:.25rem;display:flex;min-height:2rem;width:100%;cursor:pointer;align-items:center;border-radius:.25rem;border-style:none;background-color:transparent;padding:.5rem 1rem;--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1));text-decoration-line:none;transition:all .2s ease}.drawer-item:hover{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}.drawer-item.active{background-image:linear-gradient(135deg,rgb(var(--gradient-primary-start)),rgb(var(--gradient-primary-end)));font-weight:500;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.drawer-item.active .item-icon{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.drawer-item:active{transform:scale(.98)}.drawer-item:focus-visible{outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary) / 1)}.
|
|
4034
|
+
], template: "<div class=\"drawer-host-wrapper\">\n <a\n href=\"/\"\n class=\"h-[60px]\"\n [ngClass]=\"{ 'flex items-center justify-center': !isExpanded, 'p-4': isExpanded }\"\n >\n @if (logo) {\n <img\n [src]=\"logo\"\n class=\"h-[20px] w-auto transition-all duration-300 ease-in-out\"\n [ngClass]=\"{ 'scale-90': !isExpanded, 'ml-5': isExpanded }\"\n />\n } @else {\n <div class=\"h-[30px] w-auto transition-all duration-300 ease-in-out\"></div>\n }\n </a>\n <div class=\"drawer-container\" [@drawerExpand]=\"getDrawerState()\">\n <!-- Navigation Items -->\n <nav class=\"drawer-nav\">\n <ng-container *ngFor=\"let item of items\">\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n </ng-container>\n </nav>\n\n <!-- Version -->\n <div *ngIf=\"version\" class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n <span *ngIf=\"isExpanded\">{{ version }}</span>\n <span *ngIf=\"!isExpanded\" class=\"drawer-version-dot\"></span>\n </div>\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n (click)=\"toggleDrawer()\"\n [matTooltip]=\"isExpanded ? 'Collapse' : 'Expand'\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n matTooltipPosition=\"right\"\n >\n <fx-ui-hero-icon\n [icon]=\"isExpanded ? 'chevron-left' : 'chevron-right'\"\n [size]=\"16\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n </button>\n</div>\n\n<!-- Recursive Template for Drawer Items -->\n<ng-template #drawerItem let-item let-level=\"level\">\n <div class=\"drawer-item-wrapper\">\n <!-- Item Button/Link -->\n <a\n *ngIf=\"item.route && !item.children\"\n [routerLink]=\"item.route\"\n class=\"drawer-item\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 16 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"20\" class=\"item-icon\"></fx-ui-hero-icon>\n <span *ngIf=\"isExpanded\" class=\"item-label\">{{ item.label }}</span>\n </div>\n </a>\n\n <button\n *ngIf=\"!item.route || item.children\"\n type=\"button\"\n class=\"drawer-item\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 16 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-sm font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"20\" class=\"item-icon\"></fx-ui-hero-icon>\n <span *ngIf=\"isExpanded\" class=\"item-label\">{{ item.label }}</span>\n <fx-ui-hero-icon\n *ngIf=\"isExpanded && item.children && item.children.length > 0\"\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n </div>\n </button>\n\n <!-- Accordion Children -->\n <div\n *ngIf=\"item.children && item.children.length > 0\"\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n <ng-container *ngFor=\"let child of item.children\">\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n </ng-container>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.drawer-host-wrapper{position:relative;height:100%;border-right-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1))}.drawer-container{display:flex;height:100%;flex-direction:column;overflow:auto;--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));padding-left:.5rem;padding-right:.5rem;transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:1.5rem;width:1.5rem;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary) / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);right:-12px;transition:all .2s ease}.toggle-btn:hover{--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / .1), 0 2px 4px -2px rgb(var(--shadow-color) / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.toggle-btn:active{transform:translateY(-50%) scale(.9)}.toggle-btn:focus-visible{outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary) / 1)}.drawer-nav{flex:1 1 0%;overflow-y:auto;overflow-x:hidden;padding-top:.5rem;padding-bottom:.5rem}.drawer-nav::-webkit-scrollbar{width:.375rem}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:.125rem;--tw-bg-opacity: 1;background-color:rgb(var(--border-default) / var(--tw-bg-opacity, 1))}.drawer-nav::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(var(--text-placeholder) / var(--tw-bg-opacity, 1))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;margin-top:.25rem;display:flex;min-height:2rem;width:100%;cursor:pointer;align-items:center;border-radius:.25rem;border-style:none;background-color:transparent;padding:.5rem 1rem;--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1));text-decoration-line:none;transition:all .2s ease;-webkit-tap-highlight-color:transparent;outline:2px solid transparent;outline-offset:2px}.drawer-item:hover{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-bg-opacity: 1;background-color:rgb(var(--bg-primary-hover) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1))}.drawer-item.active{background-image:linear-gradient(135deg,rgb(var(--gradient-primary-start)),rgb(var(--gradient-primary-end)));font-weight:500;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.drawer-item.active .item-icon{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.drawer-item:active{transform:scale(.98)}.drawer-item:focus-visible{outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary) / 1)}.item-content{display:flex;width:100%;align-items:center;gap:.75rem;overflow:hidden}.item-icon{flex-shrink:0;color:inherit}.item-label{flex:1 1 0%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;font-size:13px;line-height:1.25rem}.chevron-icon{margin-left:auto;flex-shrink:0;--tw-text-opacity: 1;color:rgb(var(--text-primary) / var(--tw-text-opacity, 1));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;-webkit-user-select:none;user-select:none;align-items:center;justify-content:center;border-top-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--border-default) / var(--tw-border-opacity, 1));padding:.75rem 1rem;font-size:11px;--tw-text-opacity: 1;color:rgb(var(--text-placeholder) / var(--tw-text-opacity, 1));font-family:Roboto,monospace}.drawer-version-dot{display:block;height:.375rem;width:.375rem;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(var(--text-placeholder) / var(--tw-bg-opacity, 1))}.drawer-container[style*=\"width: 64px\"] .drawer-item{justify-content:center;padding-left:16px!important}.drawer-container[style*=\"width: 64px\"] .item-content{justify-content:center}\n"] }]
|
|
3526
4035
|
}], ctorParameters: () => [{ type: i1$4.Router }], propDecorators: { items: [{
|
|
3527
4036
|
type: Input
|
|
3528
4037
|
}], isExpanded: [{
|
|
@@ -3537,6 +4046,294 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
3537
4046
|
type: Output
|
|
3538
4047
|
}] } });
|
|
3539
4048
|
|
|
4049
|
+
/** Row-card skeleton placeholder for master-detail list panes. */
|
|
4050
|
+
class SkeletonListComponent {
|
|
4051
|
+
rows = 5;
|
|
4052
|
+
range(n) {
|
|
4053
|
+
return Array.from({ length: Number(n) || 0 }, (_, i) => i);
|
|
4054
|
+
}
|
|
4055
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4056
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SkeletonListComponent, isStandalone: false, selector: "fx-ui-skeleton-list", inputs: { rows: "rows" }, ngImport: i0, template: "<div class=\"flex flex-col gap-normal animate-pulse\">\n @for (r of range(rows); track r) {\n <div class=\"rounded-normal border border-border-default p-semi\">\n <div class=\"flex items-center gap-normal mb-small\">\n <div class=\"w-8 h-8 rounded-normal bg-bg-hover shrink-0\"></div>\n <div class=\"h-4 flex-1 rounded bg-bg-hover\"></div>\n <div class=\"h-5 w-12 rounded-full bg-bg-hover shrink-0\"></div>\n </div>\n <div class=\"h-3 w-3/4 rounded bg-bg-hover\"></div>\n </div>\n }\n</div>\n" });
|
|
4057
|
+
}
|
|
4058
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonListComponent, decorators: [{
|
|
4059
|
+
type: Component,
|
|
4060
|
+
args: [{ selector: 'fx-ui-skeleton-list', standalone: false, template: "<div class=\"flex flex-col gap-normal animate-pulse\">\n @for (r of range(rows); track r) {\n <div class=\"rounded-normal border border-border-default p-semi\">\n <div class=\"flex items-center gap-normal mb-small\">\n <div class=\"w-8 h-8 rounded-normal bg-bg-hover shrink-0\"></div>\n <div class=\"h-4 flex-1 rounded bg-bg-hover\"></div>\n <div class=\"h-5 w-12 rounded-full bg-bg-hover shrink-0\"></div>\n </div>\n <div class=\"h-3 w-3/4 rounded bg-bg-hover\"></div>\n </div>\n }\n</div>\n" }]
|
|
4061
|
+
}], propDecorators: { rows: [{
|
|
4062
|
+
type: Input
|
|
4063
|
+
}] } });
|
|
4064
|
+
|
|
4065
|
+
/** Card-shaped skeleton placeholder for detail panels. */
|
|
4066
|
+
class SkeletonDetailComponent {
|
|
4067
|
+
/** Number of content cards rendered below the header card. */
|
|
4068
|
+
cards = 3;
|
|
4069
|
+
/** Rows per content card. */
|
|
4070
|
+
rows = 4;
|
|
4071
|
+
range(n) {
|
|
4072
|
+
return Array.from({ length: Number(n) || 0 }, (_, i) => i);
|
|
4073
|
+
}
|
|
4074
|
+
rowWidth(i) {
|
|
4075
|
+
return [90, 70, 80, 60][i % 4];
|
|
4076
|
+
}
|
|
4077
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4078
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SkeletonDetailComponent, isStandalone: false, selector: "fx-ui-skeleton-detail", inputs: { cards: "cards", rows: "rows" }, ngImport: i0, template: "<div class=\"flex flex-col gap-xl animate-pulse\">\n <div class=\"card-common\">\n <div class=\"flex items-start gap-normal\">\n <div class=\"w-10 h-10 rounded-lg bg-bg-hover shrink-0\"></div>\n <div class=\"flex-1 min-w-0 flex flex-col gap-normal\">\n <div class=\"h-5 w-1/2 rounded bg-bg-hover\"></div>\n <div class=\"h-3 w-3/4 rounded bg-bg-hover\"></div>\n </div>\n </div>\n </div>\n\n @for (c of range(cards); track c) {\n <div class=\"card-common flex flex-col gap-large\">\n <div class=\"h-4 w-1/3 rounded bg-bg-hover\"></div>\n <div class=\"flex flex-col gap-normal\">\n @for (r of range(rows); track r) {\n <div class=\"h-3 rounded bg-bg-hover\" [style.width.%]=\"rowWidth(r)\"></div>\n }\n </div>\n </div>\n }\n</div>\n" });
|
|
4079
|
+
}
|
|
4080
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonDetailComponent, decorators: [{
|
|
4081
|
+
type: Component,
|
|
4082
|
+
args: [{ selector: 'fx-ui-skeleton-detail', standalone: false, template: "<div class=\"flex flex-col gap-xl animate-pulse\">\n <div class=\"card-common\">\n <div class=\"flex items-start gap-normal\">\n <div class=\"w-10 h-10 rounded-lg bg-bg-hover shrink-0\"></div>\n <div class=\"flex-1 min-w-0 flex flex-col gap-normal\">\n <div class=\"h-5 w-1/2 rounded bg-bg-hover\"></div>\n <div class=\"h-3 w-3/4 rounded bg-bg-hover\"></div>\n </div>\n </div>\n </div>\n\n @for (c of range(cards); track c) {\n <div class=\"card-common flex flex-col gap-large\">\n <div class=\"h-4 w-1/3 rounded bg-bg-hover\"></div>\n <div class=\"flex flex-col gap-normal\">\n @for (r of range(rows); track r) {\n <div class=\"h-3 rounded bg-bg-hover\" [style.width.%]=\"rowWidth(r)\"></div>\n }\n </div>\n </div>\n }\n</div>\n" }]
|
|
4083
|
+
}], propDecorators: { cards: [{
|
|
4084
|
+
type: Input
|
|
4085
|
+
}], rows: [{
|
|
4086
|
+
type: Input
|
|
4087
|
+
}] } });
|
|
4088
|
+
|
|
4089
|
+
/** KPI tile row: big number + tinted icon box + caption, in a responsive grid. */
|
|
4090
|
+
class StatCardsComponent {
|
|
4091
|
+
cards = [];
|
|
4092
|
+
/** Grid columns; defaults to one column per card. */
|
|
4093
|
+
cols;
|
|
4094
|
+
get gridColumns() {
|
|
4095
|
+
// No explicit cols → responsive auto-fit so tiles stack on narrow viewports.
|
|
4096
|
+
if (this.cols === undefined) {
|
|
4097
|
+
return 'repeat(auto-fit, minmax(180px, 1fr))';
|
|
4098
|
+
}
|
|
4099
|
+
return `repeat(${this.cols}, minmax(0, 1fr))`;
|
|
4100
|
+
}
|
|
4101
|
+
numClass(card) {
|
|
4102
|
+
return card.tone ? toneText(card.tone) : 'text-text-primary';
|
|
4103
|
+
}
|
|
4104
|
+
boxClass(card) {
|
|
4105
|
+
return card.tone ? `bg-${card.tone}/10 ${toneText(card.tone)}` : 'bg-bg-hover text-text-secondary';
|
|
4106
|
+
}
|
|
4107
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StatCardsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4108
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StatCardsComponent, isStandalone: false, selector: "fx-ui-stat-cards", inputs: { cards: "cards", cols: "cols" }, ngImport: i0, template: "<div class=\"grid gap-normal\" [ngStyle]=\"{ 'grid-template-columns': gridColumns }\">\n @for (card of cards; track card.label) {\n <div class=\"card-common flex items-center gap-normal\">\n @if (card.icon) {\n <div\n class=\"w-10 h-10 rounded-lg flex items-center justify-center shrink-0\"\n [ngClass]=\"boxClass(card)\"\n >\n <fx-ui-hero-icon [icon]=\"card.icon\" [size]=\"20\"></fx-ui-hero-icon>\n </div>\n }\n <div class=\"flex flex-col min-w-0\">\n <span class=\"txt-heading-04\" [ngClass]=\"numClass(card)\">{{ card.value }}</span>\n <span class=\"txt-utility-caption text-text-secondary truncate\">{{ card.label }}</span>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
4109
|
+
}
|
|
4110
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StatCardsComponent, decorators: [{
|
|
4111
|
+
type: Component,
|
|
4112
|
+
args: [{ selector: 'fx-ui-stat-cards', standalone: false, template: "<div class=\"grid gap-normal\" [ngStyle]=\"{ 'grid-template-columns': gridColumns }\">\n @for (card of cards; track card.label) {\n <div class=\"card-common flex items-center gap-normal\">\n @if (card.icon) {\n <div\n class=\"w-10 h-10 rounded-lg flex items-center justify-center shrink-0\"\n [ngClass]=\"boxClass(card)\"\n >\n <fx-ui-hero-icon [icon]=\"card.icon\" [size]=\"20\"></fx-ui-hero-icon>\n </div>\n }\n <div class=\"flex flex-col min-w-0\">\n <span class=\"txt-heading-04\" [ngClass]=\"numClass(card)\">{{ card.value }}</span>\n <span class=\"txt-utility-caption text-text-secondary truncate\">{{ card.label }}</span>\n </div>\n </div>\n }\n</div>\n" }]
|
|
4113
|
+
}], propDecorators: { cards: [{
|
|
4114
|
+
type: Input
|
|
4115
|
+
}], cols: [{
|
|
4116
|
+
type: Input
|
|
4117
|
+
}] } });
|
|
4118
|
+
|
|
4119
|
+
/** Centered "no data" block. The message is caller-translated (no i18n in lib). */
|
|
4120
|
+
class EmptyStateComponent {
|
|
4121
|
+
message = 'No data';
|
|
4122
|
+
/** Optional icon (hero-icon name). */
|
|
4123
|
+
icon;
|
|
4124
|
+
/** Min height of the block, CSS length. */
|
|
4125
|
+
height = '120px';
|
|
4126
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4127
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: EmptyStateComponent, isStandalone: false, selector: "fx-ui-empty-state", inputs: { message: "message", icon: "icon", height: "height" }, ngImport: i0, template: "<div\n class=\"flex flex-col items-center justify-center gap-small w-full\"\n [style.minHeight]=\"height\"\n>\n @if (icon) {\n <fx-ui-hero-icon class=\"text-text-placeholder\" [icon]=\"icon\" [size]=\"24\"></fx-ui-hero-icon>\n }\n <div class=\"txt-default text-text-placeholder\">{{ message }}</div>\n</div>\n", dependencies: [{ kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
4128
|
+
}
|
|
4129
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: EmptyStateComponent, decorators: [{
|
|
4130
|
+
type: Component,
|
|
4131
|
+
args: [{ selector: 'fx-ui-empty-state', standalone: false, template: "<div\n class=\"flex flex-col items-center justify-center gap-small w-full\"\n [style.minHeight]=\"height\"\n>\n @if (icon) {\n <fx-ui-hero-icon class=\"text-text-placeholder\" [icon]=\"icon\" [size]=\"24\"></fx-ui-hero-icon>\n }\n <div class=\"txt-default text-text-placeholder\">{{ message }}</div>\n</div>\n" }]
|
|
4132
|
+
}], propDecorators: { message: [{
|
|
4133
|
+
type: Input
|
|
4134
|
+
}], icon: [{
|
|
4135
|
+
type: Input
|
|
4136
|
+
}], height: [{
|
|
4137
|
+
type: Input
|
|
4138
|
+
}] } });
|
|
4139
|
+
|
|
4140
|
+
/**
|
|
4141
|
+
* Tone-tinted filter chip row. Replaces the per-tab chipClass() copies —
|
|
4142
|
+
* including their classic bug of comparing a hardcoded filter key: the active
|
|
4143
|
+
* chip here is always derived from [value].
|
|
4144
|
+
*/
|
|
4145
|
+
class FilterChipsComponent {
|
|
4146
|
+
options = [];
|
|
4147
|
+
value = '';
|
|
4148
|
+
valueChange = new EventEmitter();
|
|
4149
|
+
/** Per-value tone overrides (e.g. { Safe: 'information', Protected: 'discovery' as any }). */
|
|
4150
|
+
toneOverrides = {};
|
|
4151
|
+
select(option) {
|
|
4152
|
+
this.value = option.value;
|
|
4153
|
+
this.valueChange.emit(option.value);
|
|
4154
|
+
}
|
|
4155
|
+
chipClass(option) {
|
|
4156
|
+
const active = this.value === option.value;
|
|
4157
|
+
if (!option.value) {
|
|
4158
|
+
return active
|
|
4159
|
+
? 'bg-text-primary text-text-focus'
|
|
4160
|
+
: 'bg-bg-hover text-text-secondary hover:bg-gradient-primary-start/10 hover:text-gradient-primary-start';
|
|
4161
|
+
}
|
|
4162
|
+
const tone = option.value in this.toneOverrides
|
|
4163
|
+
? this.toneOverrides[option.value]
|
|
4164
|
+
: severityTone(option.value);
|
|
4165
|
+
if (!tone) {
|
|
4166
|
+
return active ? 'bg-text-primary text-text-focus' : `${toneBadge(null)} hover:opacity-50`;
|
|
4167
|
+
}
|
|
4168
|
+
return active ? `bg-${tone} text-text-focus` : `${toneBadge(tone)} hover:opacity-50`;
|
|
4169
|
+
}
|
|
4170
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FilterChipsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4171
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: FilterChipsComponent, isStandalone: false, selector: "fx-ui-filter-chips", inputs: { options: "options", value: "value", toneOverrides: "toneOverrides" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"flex flex-wrap items-center gap-small\">\n @for (option of options; track option.value) {\n <button\n type=\"button\"\n class=\"px-3 py-1 rounded-full txt-utility-caption font-medium transition-colors cursor-pointer\"\n [ngClass]=\"chipClass(option)\"\n (click)=\"select(option)\"\n >\n {{ option.label }}\n </button>\n }\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
4172
|
+
}
|
|
4173
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FilterChipsComponent, decorators: [{
|
|
4174
|
+
type: Component,
|
|
4175
|
+
args: [{ selector: 'fx-ui-filter-chips', standalone: false, template: "<div class=\"flex flex-wrap items-center gap-small\">\n @for (option of options; track option.value) {\n <button\n type=\"button\"\n class=\"px-3 py-1 rounded-full txt-utility-caption font-medium transition-colors cursor-pointer\"\n [ngClass]=\"chipClass(option)\"\n (click)=\"select(option)\"\n >\n {{ option.label }}\n </button>\n }\n</div>\n" }]
|
|
4176
|
+
}], propDecorators: { options: [{
|
|
4177
|
+
type: Input
|
|
4178
|
+
}], value: [{
|
|
4179
|
+
type: Input
|
|
4180
|
+
}], valueChange: [{
|
|
4181
|
+
type: Output
|
|
4182
|
+
}], toneOverrides: [{
|
|
4183
|
+
type: Input
|
|
4184
|
+
}] } });
|
|
4185
|
+
|
|
4186
|
+
/** Thin tone-coloured progress/score bar with optional label and caption. */
|
|
4187
|
+
class MeterComponent {
|
|
4188
|
+
value = 0;
|
|
4189
|
+
max = 10;
|
|
4190
|
+
tone = null;
|
|
4191
|
+
/** Caller-translated texts; omitted → bar only. */
|
|
4192
|
+
label;
|
|
4193
|
+
caption;
|
|
4194
|
+
get percent() {
|
|
4195
|
+
const max = Number(this.max) || 1;
|
|
4196
|
+
const pct = (Number(this.value) / max) * 100;
|
|
4197
|
+
return Math.min(100, Math.max(0, pct));
|
|
4198
|
+
}
|
|
4199
|
+
get fillClass() {
|
|
4200
|
+
return toneBg(this.tone);
|
|
4201
|
+
}
|
|
4202
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MeterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4203
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MeterComponent, isStandalone: false, selector: "fx-ui-meter", inputs: { value: "value", max: "max", tone: "tone", label: "label", caption: "caption" }, ngImport: i0, template: "<div class=\"flex flex-col gap-small w-full\">\n @if (label || caption) {\n <div class=\"flex items-center justify-between gap-normal\">\n @if (label) {\n <span class=\"txt-field-label !mb-0\">{{ label }}</span>\n }\n @if (caption) {\n <span class=\"txt-utility-caption text-text-secondary\">{{ caption }}</span>\n }\n </div>\n }\n <div class=\"h-2 rounded-full bg-bg-hover overflow-hidden\">\n <div class=\"h-full rounded-full\" [ngClass]=\"fillClass\" [style.width.%]=\"percent\"></div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
4204
|
+
}
|
|
4205
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MeterComponent, decorators: [{
|
|
4206
|
+
type: Component,
|
|
4207
|
+
args: [{ selector: 'fx-ui-meter', standalone: false, template: "<div class=\"flex flex-col gap-small w-full\">\n @if (label || caption) {\n <div class=\"flex items-center justify-between gap-normal\">\n @if (label) {\n <span class=\"txt-field-label !mb-0\">{{ label }}</span>\n }\n @if (caption) {\n <span class=\"txt-utility-caption text-text-secondary\">{{ caption }}</span>\n }\n </div>\n }\n <div class=\"h-2 rounded-full bg-bg-hover overflow-hidden\">\n <div class=\"h-full rounded-full\" [ngClass]=\"fillClass\" [style.width.%]=\"percent\"></div>\n </div>\n</div>\n" }]
|
|
4208
|
+
}], propDecorators: { value: [{
|
|
4209
|
+
type: Input
|
|
4210
|
+
}], max: [{
|
|
4211
|
+
type: Input
|
|
4212
|
+
}], tone: [{
|
|
4213
|
+
type: Input
|
|
4214
|
+
}], label: [{
|
|
4215
|
+
type: Input
|
|
4216
|
+
}], caption: [{
|
|
4217
|
+
type: Input
|
|
4218
|
+
}] } });
|
|
4219
|
+
|
|
4220
|
+
/** Detail-panel section: card with an icon + heading header and projected body. */
|
|
4221
|
+
class SectionCardComponent {
|
|
4222
|
+
/** Caller-translated heading. */
|
|
4223
|
+
title = '';
|
|
4224
|
+
/** hero-icon name; omitted → text-only header. */
|
|
4225
|
+
icon;
|
|
4226
|
+
iconTone = null;
|
|
4227
|
+
get iconClass() {
|
|
4228
|
+
return this.iconTone ? toneText(this.iconTone) : 'text-text-secondary';
|
|
4229
|
+
}
|
|
4230
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SectionCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4231
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SectionCardComponent, isStandalone: false, selector: "fx-ui-section-card", inputs: { title: "title", icon: "icon", iconTone: "iconTone" }, ngImport: i0, template: "<div class=\"card-common\">\n <div class=\"flex items-center gap-normal mb-large\">\n @if (icon) {\n <fx-ui-hero-icon [ngClass]=\"iconClass\" [icon]=\"icon\" [size]=\"18\"></fx-ui-hero-icon>\n }\n <span class=\"txt-heading-06\">{{ title }}</span>\n </div>\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
|
|
4232
|
+
}
|
|
4233
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SectionCardComponent, decorators: [{
|
|
4234
|
+
type: Component,
|
|
4235
|
+
args: [{ selector: 'fx-ui-section-card', standalone: false, template: "<div class=\"card-common\">\n <div class=\"flex items-center gap-normal mb-large\">\n @if (icon) {\n <fx-ui-hero-icon [ngClass]=\"iconClass\" [icon]=\"icon\" [size]=\"18\"></fx-ui-hero-icon>\n }\n <span class=\"txt-heading-06\">{{ title }}</span>\n </div>\n <ng-content></ng-content>\n</div>\n" }]
|
|
4236
|
+
}], propDecorators: { title: [{
|
|
4237
|
+
type: Input
|
|
4238
|
+
}], icon: [{
|
|
4239
|
+
type: Input
|
|
4240
|
+
}], iconTone: [{
|
|
4241
|
+
type: Input
|
|
4242
|
+
}] } });
|
|
4243
|
+
|
|
4244
|
+
/**
|
|
4245
|
+
* Label-over-value field for detail panels. The label uses txt-field-label
|
|
4246
|
+
* with its baked-in margin neutralised (the known mb-1 alignment gotcha) —
|
|
4247
|
+
* spacing is owned by this component.
|
|
4248
|
+
*/
|
|
4249
|
+
class InfoFieldComponent {
|
|
4250
|
+
/** Caller-translated label. */
|
|
4251
|
+
label = '';
|
|
4252
|
+
value;
|
|
4253
|
+
/** Colours the value; null/undefined renders the primary text colour. */
|
|
4254
|
+
tone = null;
|
|
4255
|
+
/** Monospace value (hashes, paths). */
|
|
4256
|
+
mono = false;
|
|
4257
|
+
/** Placeholder when value is empty. */
|
|
4258
|
+
placeholder = '---';
|
|
4259
|
+
get displayValue() {
|
|
4260
|
+
if (this.value === null || this.value === undefined || this.value === '') {
|
|
4261
|
+
return this.placeholder;
|
|
4262
|
+
}
|
|
4263
|
+
return String(this.value);
|
|
4264
|
+
}
|
|
4265
|
+
get valueClass() {
|
|
4266
|
+
const toneClass = this.tone ? toneText(this.tone) : 'text-text-primary';
|
|
4267
|
+
return this.mono ? `${toneClass} font-mono break-all` : toneClass;
|
|
4268
|
+
}
|
|
4269
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InfoFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4270
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: InfoFieldComponent, isStandalone: false, selector: "fx-ui-info-field", inputs: { label: "label", value: "value", tone: "tone", mono: "mono", placeholder: "placeholder" }, ngImport: i0, template: "<div class=\"flex flex-col gap-small min-w-0\">\n <span class=\"txt-field-label !mb-0\">{{ label }}</span>\n <span class=\"txt-default\" [ngClass]=\"valueClass\">{{ displayValue }}</span>\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
4271
|
+
}
|
|
4272
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InfoFieldComponent, decorators: [{
|
|
4273
|
+
type: Component,
|
|
4274
|
+
args: [{ selector: 'fx-ui-info-field', standalone: false, template: "<div class=\"flex flex-col gap-small min-w-0\">\n <span class=\"txt-field-label !mb-0\">{{ label }}</span>\n <span class=\"txt-default\" [ngClass]=\"valueClass\">{{ displayValue }}</span>\n</div>\n" }]
|
|
4275
|
+
}], propDecorators: { label: [{
|
|
4276
|
+
type: Input
|
|
4277
|
+
}], value: [{
|
|
4278
|
+
type: Input
|
|
4279
|
+
}], tone: [{
|
|
4280
|
+
type: Input
|
|
4281
|
+
}], mono: [{
|
|
4282
|
+
type: Input
|
|
4283
|
+
}], placeholder: [{
|
|
4284
|
+
type: Input
|
|
4285
|
+
}] } });
|
|
4286
|
+
|
|
4287
|
+
/**
|
|
4288
|
+
* Compact total/critical/high/medium(/low) badge cluster used in table cells.
|
|
4289
|
+
* Pass counts via [stats]; missing fields are skipped. Labels are numbers, so
|
|
4290
|
+
* no i18n is involved; the total badge renders neutral.
|
|
4291
|
+
*/
|
|
4292
|
+
class SeverityBadgesComponent {
|
|
4293
|
+
stats = null;
|
|
4294
|
+
/** Show zero-count badges (default true, mirrors the table-cell usage). */
|
|
4295
|
+
showZero = true;
|
|
4296
|
+
/** Append the severity letter to counts ("3C", "5H", "2M") per the report design. */
|
|
4297
|
+
suffixed = false;
|
|
4298
|
+
badgeClick = new EventEmitter();
|
|
4299
|
+
static TONES = {
|
|
4300
|
+
total: null,
|
|
4301
|
+
critical: 'critical',
|
|
4302
|
+
high: 'danger',
|
|
4303
|
+
medium: 'warning',
|
|
4304
|
+
low: 'success',
|
|
4305
|
+
};
|
|
4306
|
+
get badges() {
|
|
4307
|
+
const s = this.stats ?? {};
|
|
4308
|
+
return ['total', 'critical', 'high', 'medium', 'low']
|
|
4309
|
+
.filter((key) => s[key] !== undefined && (this.showZero || Number(s[key]) > 0))
|
|
4310
|
+
.map((key) => {
|
|
4311
|
+
const count = Number(s[key]) || 0;
|
|
4312
|
+
const label = this.suffixed && key !== 'total' ? `${count}${key.charAt(0).toUpperCase()}` : count;
|
|
4313
|
+
return { key, label, tone: SeverityBadgesComponent.TONES[key] };
|
|
4314
|
+
});
|
|
4315
|
+
}
|
|
4316
|
+
badgeClass(badge) {
|
|
4317
|
+
return badge.tone
|
|
4318
|
+
? `bg-${badge.tone}/10 text-${badge.tone}`
|
|
4319
|
+
: 'bg-bg-hover text-text-primary';
|
|
4320
|
+
}
|
|
4321
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SeverityBadgesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4322
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SeverityBadgesComponent, isStandalone: false, selector: "fx-ui-severity-badges", inputs: { stats: "stats", showZero: "showZero", suffixed: "suffixed" }, outputs: { badgeClick: "badgeClick" }, ngImport: i0, template: "<div class=\"flex items-center gap-small\">\n @for (badge of badges; track badge.key) {\n <span\n class=\"px-2 py-0.5 rounded-full txt-utility-caption font-medium cursor-pointer\"\n [ngClass]=\"badgeClass(badge)\"\n (click)=\"badgeClick.emit(badge.key)\"\n >{{ badge.label }}</span\n >\n }\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
4323
|
+
}
|
|
4324
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SeverityBadgesComponent, decorators: [{
|
|
4325
|
+
type: Component,
|
|
4326
|
+
args: [{ selector: 'fx-ui-severity-badges', standalone: false, template: "<div class=\"flex items-center gap-small\">\n @for (badge of badges; track badge.key) {\n <span\n class=\"px-2 py-0.5 rounded-full txt-utility-caption font-medium cursor-pointer\"\n [ngClass]=\"badgeClass(badge)\"\n (click)=\"badgeClick.emit(badge.key)\"\n >{{ badge.label }}</span\n >\n }\n</div>\n" }]
|
|
4327
|
+
}], propDecorators: { stats: [{
|
|
4328
|
+
type: Input
|
|
4329
|
+
}], showZero: [{
|
|
4330
|
+
type: Input
|
|
4331
|
+
}], suffixed: [{
|
|
4332
|
+
type: Input
|
|
4333
|
+
}], badgeClick: [{
|
|
4334
|
+
type: Output
|
|
4335
|
+
}] } });
|
|
4336
|
+
|
|
3540
4337
|
const FX_COMPONENTS = [
|
|
3541
4338
|
InputComponent,
|
|
3542
4339
|
SelectComponent,
|
|
@@ -3565,6 +4362,15 @@ const FX_COMPONENTS = [
|
|
|
3565
4362
|
TableCell,
|
|
3566
4363
|
KanbanBoardComponent,
|
|
3567
4364
|
DrawerComponent,
|
|
4365
|
+
SkeletonListComponent,
|
|
4366
|
+
SkeletonDetailComponent,
|
|
4367
|
+
StatCardsComponent,
|
|
4368
|
+
EmptyStateComponent,
|
|
4369
|
+
FilterChipsComponent,
|
|
4370
|
+
MeterComponent,
|
|
4371
|
+
SectionCardComponent,
|
|
4372
|
+
InfoFieldComponent,
|
|
4373
|
+
SeverityBadgesComponent,
|
|
3568
4374
|
];
|
|
3569
4375
|
|
|
3570
4376
|
class ConfirmationDialogComponent {
|
|
@@ -3594,13 +4400,13 @@ class ConfirmationDialogComponent {
|
|
|
3594
4400
|
cancel() {
|
|
3595
4401
|
this.ref.close(false);
|
|
3596
4402
|
}
|
|
3597
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ConfirmationDialogComponent, deps: [{ token: i1$
|
|
3598
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: ConfirmationDialogComponent, isStandalone: false, selector: "fx-ui-confirmation-dialog", ngImport: i0, template: "<div animate.enter=\"fade-in-animation\" class=\"dialog-container\">\n <h1 class=\"txt-heading-05 dialog-header\">{{ title }}</h1>\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\n buttonVariant=\"primary\"\n class=\"mr-1\"\n [label]=\"confirmLabel\"\n (clicked)=\"accept()\"\n [loading]=\"loading\"\n class=\"min-w-[100px]\"\n ></fx-ui-button>\n </mat-dialog-actions>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$
|
|
4403
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ConfirmationDialogComponent, deps: [{ token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
|
|
4404
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: ConfirmationDialogComponent, isStandalone: false, selector: "fx-ui-confirmation-dialog", ngImport: i0, template: "<div animate.enter=\"fade-in-animation\" class=\"dialog-container\">\n <h1 class=\"txt-heading-05 dialog-header\">{{ title }}</h1>\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\n buttonVariant=\"primary\"\n class=\"mr-1\"\n [label]=\"confirmLabel\"\n (clicked)=\"accept()\"\n [loading]=\"loading\"\n class=\"min-w-[100px]\"\n ></fx-ui-button>\n </mat-dialog-actions>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$2.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"] }] });
|
|
3599
4405
|
}
|
|
3600
4406
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ConfirmationDialogComponent, decorators: [{
|
|
3601
4407
|
type: Component,
|
|
3602
4408
|
args: [{ selector: 'fx-ui-confirmation-dialog', standalone: false, template: "<div animate.enter=\"fade-in-animation\" class=\"dialog-container\">\n <h1 class=\"txt-heading-05 dialog-header\">{{ title }}</h1>\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\n buttonVariant=\"primary\"\n class=\"mr-1\"\n [label]=\"confirmLabel\"\n (clicked)=\"accept()\"\n [loading]=\"loading\"\n class=\"min-w-[100px]\"\n ></fx-ui-button>\n </mat-dialog-actions>\n</div>\n" }]
|
|
3603
|
-
}], ctorParameters: () => [{ type: i1$
|
|
4409
|
+
}], ctorParameters: () => [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
|
|
3604
4410
|
type: Inject,
|
|
3605
4411
|
args: [MAT_DIALOG_DATA]
|
|
3606
4412
|
}] }] });
|
|
@@ -3620,7 +4426,7 @@ const MY_MOMENT_FORMATS = {
|
|
|
3620
4426
|
};
|
|
3621
4427
|
class UiModule {
|
|
3622
4428
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
3623
|
-
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, RichTextAreaComponent, SkeletonTableLoadingComponent, FlowConnection, CircleProgressBar, TreeDiagram, TableCell, KanbanBoardComponent, DrawerComponent, ConfirmationDialogComponent], imports: [CommonModule,
|
|
4429
|
+
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, RichTextAreaComponent, SkeletonTableLoadingComponent, FlowConnection, CircleProgressBar, TreeDiagram, TableCell, KanbanBoardComponent, DrawerComponent, SkeletonListComponent, SkeletonDetailComponent, StatCardsComponent, EmptyStateComponent, FilterChipsComponent, MeterComponent, SectionCardComponent, InfoFieldComponent, SeverityBadgesComponent, ConfirmationDialogComponent], imports: [CommonModule,
|
|
3624
4430
|
FormsModule,
|
|
3625
4431
|
ReactiveFormsModule,
|
|
3626
4432
|
RouterModule,
|
|
@@ -3629,7 +4435,7 @@ class UiModule {
|
|
|
3629
4435
|
OwlMomentDateTimeModule,
|
|
3630
4436
|
HasPermissionDirective,
|
|
3631
4437
|
TrimOnBlurDirective,
|
|
3632
|
-
NgHeroiconsModule,
|
|
4438
|
+
NgHeroiconsModule, i38.VflowComponent, i38.HandleComponent, i38.ResizableComponent, i38.SelectableDirective, i38.MiniMapComponent, i38.NodeToolbarComponent, i38.CustomTemplateEdgeComponent, i38.DragHandleDirective, i38.ConnectionControllerDirective, i38.NodeHtmlTemplateDirective, i38.NodeSvgTemplateDirective, i38.GroupNodeTemplateDirective, i38.EdgeLabelHtmlTemplateDirective, i38.EdgeTemplateDirective, i38.ConnectionTemplateDirective, i38.HandleTemplateDirective, i1$5.NgxEchartsModule, i3.MatSelectModule, i41.MatRadioModule, i42.MatButtonModule, i43.MatIconModule, i44.MatPaginatorModule, i45.MatTableModule, i46.MatSnackBarModule, i1$2.MatDialogModule, i48.MatCheckboxModule, i49.MatCardModule, i50.MatDatepickerModule, i51.MatTimepickerModule, i52.MatBadgeModule, i53.MatExpansionModule, i54.MatFormFieldModule, i55.MatMenuModule, i56.MatTooltipModule, i2$3.DragDropModule], exports: [InputComponent, SelectComponent, RadioButtonComponent, CheckboxComponent, DndUploadComponent, ButtonComponent, RadioButtonToggleComponent, DatetimePicker, LoadingPanel, SearchBarComponent, TabGroupComponent, TabComponent, HeroIconComponent, ToastComponent, ToastContainerComponent, TagComponent, ChartComponent, SliderComponent, SwitchComponent, RichTextAreaComponent, SkeletonTableLoadingComponent, FlowConnection, CircleProgressBar, TreeDiagram, TableCell, KanbanBoardComponent, DrawerComponent, SkeletonListComponent, SkeletonDetailComponent, StatCardsComponent, EmptyStateComponent, FilterChipsComponent, MeterComponent, SectionCardComponent, InfoFieldComponent, SeverityBadgesComponent, ConfirmationDialogComponent,
|
|
3633
4439
|
// Module
|
|
3634
4440
|
FormsModule,
|
|
3635
4441
|
ReactiveFormsModule,
|
|
@@ -3637,7 +4443,7 @@ class UiModule {
|
|
|
3637
4443
|
OwlDateTimeModule,
|
|
3638
4444
|
OwlNativeDateTimeModule,
|
|
3639
4445
|
HasPermissionDirective,
|
|
3640
|
-
NgHeroiconsModule, i3
|
|
4446
|
+
NgHeroiconsModule, i3.MatSelectModule, i41.MatRadioModule, i42.MatButtonModule, i43.MatIconModule, i44.MatPaginatorModule, i45.MatTableModule, i46.MatSnackBarModule, i1$2.MatDialogModule, i48.MatCheckboxModule, i49.MatCardModule, i50.MatDatepickerModule, i51.MatTimepickerModule, i52.MatBadgeModule, i53.MatExpansionModule, i54.MatFormFieldModule, i55.MatMenuModule, i56.MatTooltipModule, i2$3.DragDropModule] });
|
|
3641
4447
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, providers: [
|
|
3642
4448
|
importProvidersFrom(NgHeroiconsModule.forRoot()),
|
|
3643
4449
|
{ provide: OWL_DATE_TIME_FORMATS, useValue: MY_MOMENT_FORMATS },
|
|
@@ -3648,14 +4454,14 @@ class UiModule {
|
|
|
3648
4454
|
OwlDateTimeModule,
|
|
3649
4455
|
OwlNativeDateTimeModule,
|
|
3650
4456
|
OwlMomentDateTimeModule,
|
|
3651
|
-
NgHeroiconsModule,
|
|
4457
|
+
NgHeroiconsModule, i38.VflowComponent, i38.HandleComponent, i38.ResizableComponent, i38.MiniMapComponent, i38.NodeToolbarComponent, i38.CustomTemplateEdgeComponent, NgxEchartsModule.forRoot({ echarts: () => import('echarts') }), MATERIAL_MODULE,
|
|
3652
4458
|
// Module
|
|
3653
4459
|
FormsModule,
|
|
3654
4460
|
ReactiveFormsModule,
|
|
3655
4461
|
RouterModule,
|
|
3656
4462
|
OwlDateTimeModule,
|
|
3657
4463
|
OwlNativeDateTimeModule,
|
|
3658
|
-
NgHeroiconsModule, i3
|
|
4464
|
+
NgHeroiconsModule, i3.MatSelectModule, i41.MatRadioModule, i42.MatButtonModule, i43.MatIconModule, i44.MatPaginatorModule, i45.MatTableModule, i46.MatSnackBarModule, i1$2.MatDialogModule, i48.MatCheckboxModule, i49.MatCardModule, i50.MatDatepickerModule, i51.MatTimepickerModule, i52.MatBadgeModule, i53.MatExpansionModule, i54.MatFormFieldModule, i55.MatMenuModule, i56.MatTooltipModule, i2$3.DragDropModule] });
|
|
3659
4465
|
}
|
|
3660
4466
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, decorators: [{
|
|
3661
4467
|
type: NgModule,
|
|
@@ -3705,5 +4511,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
3705
4511
|
* Generated bundle index. Do not edit.
|
|
3706
4512
|
*/
|
|
3707
4513
|
|
|
3708
|
-
export { AuthInterceptor, AuthStateService, BaseComponent, BaseDialogComponent, BaseResolver, BaseTableComponent, BreadcrumbService, ButtonComponent, ChartComponent, CheckboxComponent, CircleProgressBar, ConfirmationDialogComponent, DatetimePicker, DndUploadComponent, DrawerComponent, FlowConnection, FxLoadingService, FxStorageService, FxToastrService, FxUtils, FxValidators, HasPermissionDirective, HeroIconComponent, HttpLoaderFactory, HttpWrapper, InputComponent, KanbanBoardComponent, LoadingPanel, MY_MOMENT_FORMATS, NotificationService, PermissionGuard, PermissionService, QuillStyleLoaderService, RadioButtonComponent, RadioButtonToggleComponent, RichTextAreaComponent, SearchBarComponent, SelectComponent, SkeletonTableLoadingComponent, SliderComponent, SwitchComponent, TabComponent, TabGroupComponent, TableCell, TagComponent, ThemeService, ToastComponent, ToastContainerComponent, TranslationModule, TranslationService, TreeDiagram, TrimOnBlurDirective, UiModule };
|
|
4514
|
+
export { AuthInterceptor, AuthStateService, BaseComponent, BaseDialogComponent, BaseResolver, BaseTableComponent, BreadcrumbService, ButtonComponent, ChartComponent, CheckboxComponent, CircleProgressBar, ConfirmationDialogComponent, DatetimePicker, DndUploadComponent, DrawerComponent, EmptyStateComponent, FilterChipsComponent, FlowConnection, FxLoadingService, FxStorageService, FxToastrService, FxUtils, FxValidators, HasPermissionDirective, HeroIconComponent, HttpLoaderFactory, HttpWrapper, InfoFieldComponent, InputComponent, KanbanBoardComponent, LoadingPanel, MY_MOMENT_FORMATS, MeterComponent, NotificationService, PermissionGuard, PermissionService, QuillStyleLoaderService, RadioButtonComponent, RadioButtonToggleComponent, RealtimeTableSync, RichTextAreaComponent, SearchBarComponent, SectionCardComponent, SelectComponent, SeverityBadgesComponent, SkeletonDetailComponent, SkeletonListComponent, SkeletonTableLoadingComponent, SliderComponent, StatCardsComponent, SwitchComponent, TabComponent, TabGroupComponent, TableCell, TagComponent, ThemeService, ToastComponent, ToastContainerComponent, TranslationModule, TranslationService, TreeDiagram, TrimOnBlurDirective, UiModule, countTone, createApi, fxListResolver, scoreTone, severityTone, toneBadge, toneBg, toneColor, toneText };
|
|
3709
4515
|
//# sourceMappingURL=foxeltech-angular-ui.mjs.map
|