@foxeltech/angular-ui 0.3.0 → 0.4.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.
Files changed (54) hide show
  1. package/fesm2022/foxeltech-angular-ui-chart.mjs +392 -0
  2. package/fesm2022/foxeltech-angular-ui-chart.mjs.map +1 -0
  3. package/fesm2022/foxeltech-angular-ui-flow.mjs +38 -0
  4. package/fesm2022/foxeltech-angular-ui-flow.mjs.map +1 -0
  5. package/fesm2022/foxeltech-angular-ui-rich-text.mjs +156 -0
  6. package/fesm2022/foxeltech-angular-ui-rich-text.mjs.map +1 -0
  7. package/fesm2022/foxeltech-angular-ui.mjs +890 -1499
  8. package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
  9. package/fx-icons.svg +97 -0
  10. package/package.json +23 -16
  11. package/src/lib/styles/tailwind.css +0 -1
  12. package/src/lib/ui/components/button/button.component.html +14 -14
  13. package/src/lib/ui/components/checkbox/checkbox.component.html +2 -2
  14. package/src/lib/ui/components/circle-progress-bar/circle-progress-bar.component.html +2 -2
  15. package/src/lib/ui/components/datetime-picker/datetime-picker.component.html +54 -28
  16. package/src/lib/ui/components/datetime-picker/datetime-picker.component.scss +25 -137
  17. package/src/lib/ui/components/dnd-upload/dnd-upload.component.html +3 -3
  18. package/src/lib/ui/components/drawer/drawer.component.html +75 -61
  19. package/src/lib/ui/components/empty-state/empty-state.component.html +2 -2
  20. package/src/lib/ui/components/hero-icon/hero-icon.component.html +10 -9
  21. package/src/lib/ui/components/info-field/info-field.component.html +1 -1
  22. package/src/lib/ui/components/input/input.component.html +6 -6
  23. package/src/lib/ui/components/kanban-board/kanban-board.component.html +1 -1
  24. package/src/lib/ui/components/loading-panel/loading-panel.component.html +53 -53
  25. package/src/lib/ui/components/master-detail/master-detail.component.html +9 -9
  26. package/src/lib/ui/components/menu/menu.component.html +27 -0
  27. package/src/lib/ui/components/radio-button/radio-button.component.html +26 -26
  28. package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +3 -3
  29. package/src/lib/ui/components/search-bar/search-bar.component.html +12 -11
  30. package/src/lib/ui/components/section-card/section-card.component.html +1 -1
  31. package/src/lib/ui/components/select/select.component.html +14 -12
  32. package/src/lib/ui/components/skeleton-detail/skeleton-detail.component.html +2 -2
  33. package/src/lib/ui/components/skeleton-list/skeleton-list.component.html +1 -1
  34. package/src/lib/ui/components/skeleton-table-loading/skeleton-table-loading.component.html +5 -5
  35. package/src/lib/ui/components/slider/slider.component.html +22 -20
  36. package/src/lib/ui/components/stat-cards/stat-cards.component.html +1 -1
  37. package/src/lib/ui/components/switch/switch.component.html +1 -1
  38. package/src/lib/ui/components/tab-group/tab-group.component.html +35 -32
  39. package/src/lib/ui/components/table-cell/table-cell.component.html +2 -2
  40. package/src/lib/ui/components/tag/tag.component.html +4 -4
  41. package/src/lib/ui/components/toast/toast.component.html +42 -40
  42. package/src/lib/ui/components/toast-container/toast-container.component.html +1 -0
  43. package/src/lib/ui/components/tree-diagram/tree-diagram.component.html +22 -20
  44. package/tailwind.css +0 -1
  45. package/types/foxeltech-angular-ui-chart.d.ts +53 -0
  46. package/types/foxeltech-angular-ui-flow.d.ts +14 -0
  47. package/types/foxeltech-angular-ui-rich-text.d.ts +35 -0
  48. package/{index.d.ts → types/foxeltech-angular-ui.d.ts} +394 -387
  49. package/src/lib/ui/components/chart/chart.component.html +0 -20
  50. package/src/lib/ui/components/chart/chart.component.scss +0 -49
  51. package/src/lib/ui/components/flow-connection/flow-connection.component.html +0 -10
  52. package/src/lib/ui/components/flow-connection/flow-connection.component.scss +0 -0
  53. package/src/lib/ui/components/rich-text-area/rich-text-area.component.html +0 -3
  54. package/src/lib/ui/components/rich-text-area/rich-text-area.component.scss +0 -18
@@ -1,68 +1,35 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, DestroyRef, Injector, Directive, Input, Component, createComponent, Injectable, ViewChild, Inject, EventEmitter, NgModule, HostListener, PLATFORM_ID, Output, ChangeDetectionStrategy, TemplateRef, ContentChildren, ViewChildren, ContentChild, importProvidersFrom } from '@angular/core';
3
- import * as i45 from '@angular/material/paginator';
4
- import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
5
- import * as i46 from '@angular/material/table';
6
- import { MatTableDataSource, MatTable, MatTableModule } from '@angular/material/table';
7
- import * as i1$1 from '@angular/common';
8
- import { isPlatformBrowser, CommonModule } from '@angular/common';
9
- import * as i1 from '@dimaslz/ng-heroicons';
10
- import { NgHeroiconsModule } from '@dimaslz/ng-heroicons';
11
- import _, { clamp } from 'lodash';
2
+ import { inject, DestroyRef, Injector, Directive, InjectionToken, input, isDevMode, ChangeDetectionStrategy, Component, Input, createComponent, Injectable, viewChild, ViewChild, Inject, EventEmitter, NgModule, HostListener, output, ChangeDetectorRef, TemplateRef, contentChildren, Output, ViewChildren, contentChild } from '@angular/core';
3
+ import { MatPaginator } from '@angular/material/paginator';
4
+ import { MatTableDataSource, MatTable } from '@angular/material/table';
5
+ import { NgClass, NgStyle, NgTemplateOutlet } from '@angular/common';
12
6
  import { Observable, firstValueFrom, Subject, debounceTime, distinctUntilChanged, BehaviorSubject, throwError, filter, takeUntil } from 'rxjs';
13
- import moment from 'moment';
14
7
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
15
8
  import * as i2 from '@angular/common/http';
16
9
  import { HttpRequest, HttpClient } from '@angular/common/http';
17
- import * as i1$2 from '@angular/material/dialog';
18
- import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
19
- import * as i1$3 from '@ngx-translate/core';
10
+ import * as i1 from '@angular/material/dialog';
11
+ import { MAT_DIALOG_DATA, MatDialogTitle, MatDialogContent, MatDialogActions, MatDialog } from '@angular/material/dialog';
12
+ import * as i1$1 from '@ngx-translate/core';
20
13
  import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
21
14
  import { TranslateHttpLoader } from '@ngx-translate/http-loader';
22
- import * as i2$1 from '@angular/forms';
15
+ import * as i1$3 from '@angular/forms';
23
16
  import { NgControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
24
- import * as i1$4 from '@angular/router';
25
- import { NavigationEnd, RouterModule } from '@angular/router';
17
+ import * as i2$1 from '@angular/router';
18
+ import { NavigationEnd, RouterLink, RouterModule } from '@angular/router';
26
19
  import { catchError } from 'rxjs/operators';
27
20
  import * as signalR from '@microsoft/signalr';
28
- import * as i3 from '@angular/material/select';
29
- import { MatSelectModule } from '@angular/material/select';
30
- import * as i42 from '@angular/material/radio';
31
- import { MatRadioModule } from '@angular/material/radio';
32
- import * as i43 from '@angular/material/button';
33
- import { MatButtonModule } from '@angular/material/button';
34
- import * as i44 from '@angular/material/icon';
35
- import { MatIconModule } from '@angular/material/icon';
36
- import * as i47 from '@angular/material/snack-bar';
37
- import { MatSnackBarModule } from '@angular/material/snack-bar';
38
- import * as i49 from '@angular/material/checkbox';
39
- import { MatCheckboxModule } from '@angular/material/checkbox';
40
- import * as i50 from '@angular/material/card';
41
- import { MatCardModule } from '@angular/material/card';
42
- import * as i51 from '@angular/material/datepicker';
21
+ import { CdkScrollable } from '@angular/cdk/scrolling';
22
+ import * as i1$2 from '@angular/material/datepicker';
43
23
  import { MatDatepickerModule } from '@angular/material/datepicker';
44
- import * as i52 from '@angular/material/timepicker';
24
+ import * as i2$2 from '@angular/material/timepicker';
45
25
  import { MatTimepickerModule } from '@angular/material/timepicker';
46
- import * as i53 from '@angular/material/badge';
47
- import { MatBadgeModule } from '@angular/material/badge';
48
- import * as i54 from '@angular/material/expansion';
49
- import { MatExpansionModule } from '@angular/material/expansion';
50
- import * as i55 from '@angular/material/form-field';
51
- import { MatFormFieldModule } from '@angular/material/form-field';
52
- import * as i56 from '@angular/material/menu';
26
+ import { MAT_DATE_LOCALE, provideNativeDateAdapter } from '@angular/material/core';
27
+ import { MatTooltip } from '@angular/material/tooltip';
28
+ import { MatFormField, MatSelect, MatOption } from '@angular/material/select';
29
+ import { moveItemInArray, transferArrayItem, CdkDropList, CdkDrag, CdkDragPlaceholder } from '@angular/cdk/drag-drop';
30
+ import { trigger, state, style, transition, animate } from '@angular/animations';
31
+ import * as i1$4 from '@angular/material/menu';
53
32
  import { MatMenuModule } from '@angular/material/menu';
54
- import * as i57 from '@angular/material/tooltip';
55
- import { MatTooltipModule } from '@angular/material/tooltip';
56
- import * as i2$3 from '@angular/cdk/drag-drop';
57
- import { DragDropModule, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
58
- import * as i2$2 from '@danielmoncada/angular-datetime-picker';
59
- import { OwlDateTimeModule, OwlNativeDateTimeModule, OWL_DATE_TIME_FORMATS } from '@danielmoncada/angular-datetime-picker';
60
- import * as i1$5 from 'ngx-echarts';
61
- import { NgxEchartsModule } from 'ngx-echarts';
62
- import * as i39 from 'ngx-vflow';
63
- import { Vflow } from 'ngx-vflow';
64
- import { trigger, state, transition, style, animate } from '@angular/animations';
65
- import { OwlMomentDateTimeModule } from '@danielmoncada/angular-datetime-picker-moment-adapter';
66
33
 
67
34
  class BaseComponent {
68
35
  injector;
@@ -76,63 +43,79 @@ class BaseComponent {
76
43
  }
77
44
  // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method -- subclasses across host apps call super.ngOnDestroy(); removing this breaks them at runtime
78
45
  ngOnDestroy() { }
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 });
80
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: BaseComponent, isStandalone: true, ngImport: i0 });
46
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BaseComponent, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive });
47
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.20", type: BaseComponent, isStandalone: true, ngImport: i0 });
81
48
  }
82
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseComponent, decorators: [{
49
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BaseComponent, decorators: [{
83
50
  type: Directive
84
51
  }], ctorParameters: () => [{ type: i0.Injector }] });
85
52
 
53
+ /**
54
+ * Where the generated Heroicons sprite is served from. Defaults to
55
+ * 'fx-icons.svg' at the app base — consumers copy it from the package via an
56
+ * angular.json assets glob (same pattern as the lib fonts):
57
+ * { "input": "node_modules/@foxeltech/angular-ui", "glob": "fx-icons.svg", "output": "." }
58
+ */
59
+ const FX_ICON_SPRITE_URL = new InjectionToken('FX_ICON_SPRITE_URL', {
60
+ providedIn: 'root',
61
+ factory: () => 'fx-icons.svg',
62
+ });
63
+ let spriteChecked = false;
64
+ /**
65
+ * Heroicons rendered from the self-hosted sprite (see
66
+ * scripts/generate-icon-sprite.mjs) — every 24px outline/solid icon is
67
+ * available by name with no per-icon registration and no runtime icon
68
+ * library. API kept compatible with the old @dimaslz/ng-heroicons wrapper.
69
+ */
86
70
  class HeroIconComponent {
87
- stroke = 1.5;
88
- icon;
89
- solid;
90
- outline;
91
- size;
92
- color;
93
- class;
94
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HeroIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
95
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: HeroIconComponent, isStandalone: false, selector: "fx-ui-hero-icon", inputs: { stroke: "stroke", icon: "icon", solid: "solid", outline: "outline", size: "size", color: "color", class: "class" }, ngImport: i0, template: "<ng-heroicons\n [stroke]=\"stroke\"\n [icon]=\"icon\"\n [size]=\"size\"\n [solid]=\"solid\"\n [outline]=\"outline\"\n [color]=\"color\"\n [class]=\"class\"\n/>\n", styles: [""], dependencies: [{ kind: "component", type: i1.DynamicComponent, selector: "ng-heroicons", inputs: ["icon", "size", "color", "stroke", "outline", "solid", "class", "style"] }] });
71
+ stroke = input(1.5, ...(ngDevMode ? [{ debugName: "stroke" }] : /* istanbul ignore next */ []));
72
+ icon = input(...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
73
+ solid = input(...(ngDevMode ? [undefined, { debugName: "solid" }] : /* istanbul ignore next */ []));
74
+ outline = input(...(ngDevMode ? [undefined, { debugName: "outline" }] : /* istanbul ignore next */ []));
75
+ size = input(...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
76
+ color = input(...(ngDevMode ? [undefined, { debugName: "color" }] : /* istanbul ignore next */ []));
77
+ class = input(...(ngDevMode ? [undefined, { debugName: "class" }] : /* istanbul ignore next */ []));
78
+ spriteUrl = inject(FX_ICON_SPRITE_URL);
79
+ constructor() {
80
+ // One warning per app when the sprite asset was not copied — otherwise
81
+ // every icon just renders blank and nobody knows why.
82
+ if (isDevMode() && !spriteChecked && typeof fetch === 'function') {
83
+ spriteChecked = true;
84
+ fetch(this.spriteUrl, { method: 'HEAD' })
85
+ .then((r) => {
86
+ if (!r.ok)
87
+ throw new Error(String(r.status));
88
+ })
89
+ .catch(() => console.warn(`[fx-ui-hero-icon] Sprite '${this.spriteUrl}' not found — add the fx-icons.svg ` +
90
+ `assets glob from @foxeltech/angular-ui to angular.json (see FX_ICON_SPRITE_URL docs).`));
91
+ }
92
+ }
93
+ get href() {
94
+ const name = this.solid() ? `${this.icon()}-solid` : this.icon();
95
+ return `${this.spriteUrl}#${name}`;
96
+ }
97
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: HeroIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
98
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.20", type: HeroIconComponent, isStandalone: true, selector: "fx-ui-hero-icon", inputs: { stroke: { classPropertyName: "stroke", publicName: "stroke", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, solid: { classPropertyName: "solid", publicName: "solid", isSignal: true, isRequired: false, transformFunction: null }, outline: { classPropertyName: "outline", publicName: "outline", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<svg\n [attr.width]=\"size() || 24\"\n [attr.height]=\"size() || 24\"\n [attr.stroke-width]=\"solid() ? null : stroke()\"\n [style.color]=\"color() || null\"\n [class]=\"class()\"\n aria-hidden=\"true\"\n>\n <use [attr.href]=\"href\" />\n</svg>\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush });
96
99
  }
97
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HeroIconComponent, decorators: [{
100
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: HeroIconComponent, decorators: [{
98
101
  type: Component,
99
- args: [{ selector: 'fx-ui-hero-icon', standalone: false, template: "<ng-heroicons\n [stroke]=\"stroke\"\n [icon]=\"icon\"\n [size]=\"size\"\n [solid]=\"solid\"\n [outline]=\"outline\"\n [color]=\"color\"\n [class]=\"class\"\n/>\n" }]
100
- }], propDecorators: { stroke: [{
101
- type: Input
102
- }], icon: [{
103
- type: Input
104
- }], solid: [{
105
- type: Input
106
- }], outline: [{
107
- type: Input
108
- }], size: [{
109
- type: Input
110
- }], color: [{
111
- type: Input
112
- }], class: [{
113
- type: Input
114
- }] } });
102
+ args: [{ selector: 'fx-ui-hero-icon', changeDetection: ChangeDetectionStrategy.OnPush, template: "<svg\n [attr.width]=\"size() || 24\"\n [attr.height]=\"size() || 24\"\n [attr.stroke-width]=\"solid() ? null : stroke()\"\n [style.color]=\"color() || null\"\n [class]=\"class()\"\n aria-hidden=\"true\"\n>\n <use [attr.href]=\"href\" />\n</svg>\n" }]
103
+ }], ctorParameters: () => [], propDecorators: { stroke: [{ type: i0.Input, args: [{ isSignal: true, alias: "stroke", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], solid: [{ type: i0.Input, args: [{ isSignal: true, alias: "solid", required: false }] }], outline: [{ type: i0.Input, args: [{ isSignal: true, alias: "outline", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
115
104
 
116
105
  class ToastComponent {
117
- toastId;
106
+ toastId = input.required(...(ngDevMode ? [{ debugName: "toastId" }] : /* istanbul ignore next */ []));
118
107
  title = '';
119
- message = '';
120
- type;
121
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
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 [attr.role]=\"type === 'error' ? 'alert' : 'status'\"\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=\"\" aria-hidden=\"true\">\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"] }] });
108
+ message = input('', ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
109
+ type = input(...(ngDevMode ? [undefined, { debugName: "type" }] : /* istanbul ignore next */ []));
110
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
111
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ToastComponent, isStandalone: true, selector: "fx-ui-toast", inputs: { toastId: { classPropertyName: "toastId", publicName: "toastId", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: false, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n animate.enter=\"horizontal-fade-in-animation\"\n animate.leave=\"horizontal-fade-out-animation\"\n [attr.role]=\"type() === 'error' ? 'alert' : 'status'\"\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=\"\" aria-hidden=\"true\">\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 @if (title) {\n <strong class=\"txt-field-label\">{{ title }}</strong>\n }\n <p class=\"txt-default\">{{ message() }}</p>\n </div>\n </div>\n", styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
123
112
  }
124
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastComponent, decorators: [{
113
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ToastComponent, decorators: [{
125
114
  type: Component,
126
- args: [{ selector: 'fx-ui-toast', standalone: false, template: "<div\n animate.enter=\"horizontal-fade-in-animation\"\n animate.leave=\"horizontal-fade-out-animation\"\n [attr.role]=\"type === 'error' ? 'alert' : 'status'\"\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=\"\" aria-hidden=\"true\">\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" }]
127
- }], propDecorators: { toastId: [{
128
- type: Input
129
- }], title: [{
115
+ args: [{ selector: 'fx-ui-toast', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass, HeroIconComponent], template: "<div\n animate.enter=\"horizontal-fade-in-animation\"\n animate.leave=\"horizontal-fade-out-animation\"\n [attr.role]=\"type() === 'error' ? 'alert' : 'status'\"\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=\"\" aria-hidden=\"true\">\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 @if (title) {\n <strong class=\"txt-field-label\">{{ title }}</strong>\n }\n <p class=\"txt-default\">{{ message() }}</p>\n </div>\n </div>\n" }]
116
+ }], propDecorators: { toastId: [{ type: i0.Input, args: [{ isSignal: true, alias: "toastId", required: true }] }], title: [{
130
117
  type: Input
131
- }], message: [{
132
- type: Input
133
- }], type: [{
134
- type: Input
135
- }] } });
118
+ }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }] } });
136
119
 
137
120
  // import { ToastData } from '../../../../public-api';
138
121
  class ToastContainerComponent {
@@ -150,12 +133,12 @@ class ToastContainerComponent {
150
133
  this.toasts = this.toasts.filter(t => t.id !== id);
151
134
  this.ref.detectChanges();
152
135
  }
153
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastContainerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
154
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ToastContainerComponent, isStandalone: false, selector: "fx-ui-toast-container", ngImport: i0, template: "<div\n class=\"fixed top-5 right-5 flex flex-col items-end gap-3 z-[10000] pointer-events-none\"\n>\n @for (toast of toasts; track toast) {\n <fx-ui-toast\n class=\"pointer-events-auto\"\n [message]=\"toast.message\"\n [title]=\"toast.title\"\n [type]=\"toast.type\"\n ></fx-ui-toast>\n }\n</div>", styles: [""], dependencies: [{ kind: "component", type: ToastComponent, selector: "fx-ui-toast", inputs: ["toastId", "title", "message", "type"] }] });
136
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ToastContainerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
137
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ToastContainerComponent, isStandalone: true, selector: "fx-ui-toast-container", ngImport: i0, template: "<div\n class=\"fixed top-5 right-5 flex flex-col items-end gap-3 z-[10000] pointer-events-none\"\n>\n @for (toast of toasts; track toast) {\n <fx-ui-toast\n class=\"pointer-events-auto\"\n [toastId]=\"toast.id\"\n [message]=\"toast.message\"\n [title]=\"toast.title\"\n [type]=\"toast.type\"\n ></fx-ui-toast>\n }\n</div>", styles: [""], dependencies: [{ kind: "component", type: ToastComponent, selector: "fx-ui-toast", inputs: ["toastId", "title", "message", "type"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
155
138
  }
156
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ToastContainerComponent, decorators: [{
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ToastContainerComponent, decorators: [{
157
140
  type: Component,
158
- args: [{ selector: 'fx-ui-toast-container', standalone: false, template: "<div\n class=\"fixed top-5 right-5 flex flex-col items-end gap-3 z-[10000] pointer-events-none\"\n>\n @for (toast of toasts; track toast) {\n <fx-ui-toast\n class=\"pointer-events-auto\"\n [message]=\"toast.message\"\n [title]=\"toast.title\"\n [type]=\"toast.type\"\n ></fx-ui-toast>\n }\n</div>" }]
141
+ args: [{ selector: 'fx-ui-toast-container', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ToastComponent], template: "<div\n class=\"fixed top-5 right-5 flex flex-col items-end gap-3 z-[10000] pointer-events-none\"\n>\n @for (toast of toasts; track toast) {\n <fx-ui-toast\n class=\"pointer-events-auto\"\n [toastId]=\"toast.id\"\n [message]=\"toast.message\"\n [title]=\"toast.title\"\n [type]=\"toast.type\"\n ></fx-ui-toast>\n }\n</div>" }]
159
142
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
160
143
 
161
144
  class FxToastrService {
@@ -203,10 +186,10 @@ class FxToastrService {
203
186
  warning(message, title) {
204
187
  this.show(message, 'warning', title);
205
188
  }
206
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxToastrService, deps: [{ token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Injectable });
207
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxToastrService, providedIn: 'root' });
189
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxToastrService, deps: [{ token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Injectable });
190
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxToastrService, providedIn: 'root' });
208
191
  }
209
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxToastrService, decorators: [{
192
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxToastrService, decorators: [{
210
193
  type: Injectable,
211
194
  args: [{
212
195
  providedIn: 'root',
@@ -214,6 +197,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
214
197
  }], ctorParameters: () => [{ type: i0.ApplicationRef }] });
215
198
 
216
199
  class FxUtils {
200
+ /** Dot-path accessor (lodash _.get replacement — supports 'a.b.c'). */
201
+ static get(obj, path, defaultValue) {
202
+ if (obj == null)
203
+ return defaultValue;
204
+ let cur = obj;
205
+ for (const key of path.split('.')) {
206
+ if (cur == null)
207
+ return defaultValue;
208
+ cur = cur[key];
209
+ }
210
+ return cur === undefined ? defaultValue : cur;
211
+ }
212
+ /** Dot-path setter (lodash _.set replacement — creates missing objects). */
213
+ static set(obj, path, value) {
214
+ const keys = path.split('.');
215
+ let cur = obj;
216
+ for (let i = 0; i < keys.length - 1; i++) {
217
+ if (cur[keys[i]] == null || typeof cur[keys[i]] !== 'object')
218
+ cur[keys[i]] = {};
219
+ cur = cur[keys[i]];
220
+ }
221
+ cur[keys[keys.length - 1]] = value;
222
+ return obj;
223
+ }
224
+ /** Structural equality (lodash _.isEqual replacement for plain data). */
225
+ static deepEqual(a, b) {
226
+ if (a === b)
227
+ return true;
228
+ if (a instanceof Date && b instanceof Date)
229
+ return a.getTime() === b.getTime();
230
+ if (a == null || b == null || typeof a !== 'object' || typeof b !== 'object')
231
+ return false;
232
+ if (Array.isArray(a) !== Array.isArray(b))
233
+ return false;
234
+ const ka = Object.keys(a);
235
+ const kb = Object.keys(b);
236
+ if (ka.length !== kb.length)
237
+ return false;
238
+ return ka.every((k) => FxUtils.deepEqual(a[k], b[k]));
239
+ }
240
+ /** Deep clone for plain data (objects/arrays/Date); functions stay by reference. */
241
+ static cloneDeep(v) {
242
+ if (v === null || typeof v !== 'object')
243
+ return v;
244
+ if (v instanceof Date)
245
+ return new Date(v.getTime());
246
+ if (Array.isArray(v))
247
+ return v.map((x) => FxUtils.cloneDeep(x));
248
+ const out = {};
249
+ for (const k of Object.keys(v))
250
+ out[k] = FxUtils.cloneDeep(v[k]);
251
+ return out;
252
+ }
217
253
  static async preresolve(promises, value, key) {
218
254
  if (key === 'callback' || key === 'socket' || key === 'listener') {
219
255
  promises.push(value);
@@ -254,7 +290,7 @@ class FxUtils {
254
290
  const values = await Promise.all(promises);
255
291
  const raw = {};
256
292
  keys.forEach((key, index) => {
257
- _.set(raw, key, values[index]);
293
+ FxUtils.set(raw, key, values[index]);
258
294
  });
259
295
  return raw;
260
296
  }
@@ -313,13 +349,15 @@ class FxUtils {
313
349
  }
314
350
  }
315
351
  static isSameCollection(collection, compareCollection) {
316
- return _.isEmpty(_.xor(collection, compareCollection));
352
+ const a = new Set(collection ?? []);
353
+ const b = new Set(compareCollection ?? []);
354
+ return a.size === b.size && [...a].every((x) => b.has(x));
317
355
  }
318
356
  static isSameValue(model, compareModel) {
319
- return _.isEqual(model, compareModel);
357
+ return FxUtils.deepEqual(model, compareModel);
320
358
  }
321
359
  static parseError(err) {
322
- const status = _.get(err, 'status');
360
+ const status = err?.status;
323
361
  switch (status) {
324
362
  case 401:
325
363
  return 'Session timeout. Please login again.';
@@ -346,13 +384,13 @@ class FxUtils {
346
384
  case 504:
347
385
  return 'The server took too long to respond. Please try again later.';
348
386
  }
349
- const message = this.isStringEmpty(_.get(err, 'error.errors', ''))
350
- ? _.get(err, 'error.message', 'Unknown Error')
351
- : _.get(err, 'error.errors');
352
- if (this.isStringEmpty(_.get(err, 'error.code'))) {
387
+ const message = this.isStringEmpty(err?.error?.errors ?? '')
388
+ ? (err?.error?.message ?? 'Unknown Error')
389
+ : err?.error?.errors;
390
+ if (this.isStringEmpty(err?.error?.code)) {
353
391
  return message;
354
392
  }
355
- return `${_.get(err, 'error.code')}: ${message}`;
393
+ return `${err?.error?.code}: ${message}`;
356
394
  }
357
395
  /**
358
396
  * Resolve a theme channel triple (`--danger: 255 122 0`) to a CSS colour.
@@ -418,7 +456,7 @@ class FxUtils {
418
456
  }
419
457
  /** Safe deep accessor with the org-wide empty placeholder. */
420
458
  static value(model, key, defaultValue = '---') {
421
- return _.get(model, key, defaultValue);
459
+ return FxUtils.get(model, key, defaultValue);
422
460
  }
423
461
  /**
424
462
  * Severity weight for ordering — kept next to getTagClass so ordering and
@@ -445,12 +483,16 @@ class FxUtils {
445
483
  static formatDateTime(time) {
446
484
  if (FxUtils.isNull(time))
447
485
  return '';
448
- return moment.parseZone(time).local().format('DD/MM/YYYY HH:mm:ss');
486
+ const d = time instanceof Date ? time : new Date(String(time).replace(' ', 'T'));
487
+ if (isNaN(d.getTime()))
488
+ return '';
489
+ const p = (n) => String(n).padStart(2, '0');
490
+ return `${p(d.getDate())}/${p(d.getMonth() + 1)}/${d.getFullYear()} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
449
491
  }
450
492
  /** Seconds → compact duration ("2d 4h", "3h 12m", "45s"). */
451
493
  static formatDuration(totalSeconds) {
452
494
  const sec = Number(totalSeconds);
453
- if (!_.isFinite(sec) || sec < 0)
495
+ if (!Number.isFinite(sec) || sec < 0)
454
496
  return '';
455
497
  const d = Math.floor(sec / 86400);
456
498
  const h = Math.floor((sec % 86400) / 3600);
@@ -468,8 +510,20 @@ class FxUtils {
468
510
  static formatRelative(time) {
469
511
  if (FxUtils.isNull(time))
470
512
  return '';
471
- const m = moment.parseZone(time).local();
472
- return moment().diff(m, 'hours') < 24 ? m.fromNow() : m.format('DD/MM/YYYY');
513
+ const d = time instanceof Date ? time : new Date(String(time).replace(' ', 'T'));
514
+ if (isNaN(d.getTime()))
515
+ return '';
516
+ const diffMs = Date.now() - d.getTime();
517
+ if (diffMs < 24 * 3600_000) {
518
+ // Same wording moment.fromNow() produced for the < 24h range.
519
+ const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
520
+ const mins = Math.round(diffMs / 60_000);
521
+ if (Math.abs(mins) < 60)
522
+ return rtf.format(-mins, 'minute');
523
+ return rtf.format(-Math.round(mins / 60), 'hour');
524
+ }
525
+ const p = (n) => String(n).padStart(2, '0');
526
+ return `${p(d.getDate())}/${p(d.getMonth() + 1)}/${d.getFullYear()}`;
473
527
  }
474
528
  /**
475
529
  * Normalize a snake_case + protobuf-Long API payload for camelCase binding:
@@ -493,7 +547,7 @@ class FxUtils {
493
547
  }
494
548
  const out = {};
495
549
  for (const k of keys) {
496
- const nk = /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(k) ? _.camelCase(k) : k;
550
+ const nk = /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(k) ? k.replace(/_([a-z0-9])/g, (_m, c) => c.toUpperCase()) : k;
497
551
  out[nk] = FxUtils.camelizeDeep(input[k]);
498
552
  }
499
553
  return out;
@@ -629,7 +683,7 @@ class BaseTableComponent extends BaseComponent {
629
683
  dataSourcePlaceholder;
630
684
  config;
631
685
  paginator;
632
- table;
686
+ table = viewChild.required(MatTable);
633
687
  constructor(injector, api, modal, ref) {
634
688
  super(injector);
635
689
  this.api = api;
@@ -675,8 +729,8 @@ class BaseTableComponent extends BaseComponent {
675
729
  listKey = 'data';
676
730
  totalKey = 'total';
677
731
  setDataSource(result) {
678
- this.dataSource.data = _.get(result, this.listKey);
679
- this.total = _.get(result, this.totalKey);
732
+ this.dataSource.data = FxUtils.get(result, this.listKey);
733
+ this.total = FxUtils.get(result, this.totalKey);
680
734
  }
681
735
  _fetchSeq = 0;
682
736
  async fetch() {
@@ -723,10 +777,10 @@ class BaseTableComponent extends BaseComponent {
723
777
  this.keywordChange$.next(keyword);
724
778
  }
725
779
  async create() {
726
- const conf = _.get(this.config, 'create');
727
- const dialog = _.get(conf, 'dialog');
728
- const size = _.get(conf, 'size');
729
- if (_.isNil(conf) || _.isNil(dialog)) {
780
+ const conf = this.config?.create;
781
+ const dialog = conf?.dialog;
782
+ const size = conf?.size;
783
+ if (conf == null || dialog == null) {
730
784
  return;
731
785
  }
732
786
  if (this._lock) {
@@ -758,10 +812,10 @@ class BaseTableComponent extends BaseComponent {
758
812
  });
759
813
  }
760
814
  async update(model) {
761
- const conf = _.get(this.config, 'update');
762
- const dialog = _.get(conf, 'dialog');
763
- const size = _.get(conf, 'size');
764
- if (_.isNil(dialog) || _.isNil(conf)) {
815
+ const conf = this.config?.update;
816
+ const dialog = conf?.dialog;
817
+ const size = conf?.size;
818
+ if (dialog == null || conf == null) {
765
819
  return;
766
820
  }
767
821
  if (this._lock) {
@@ -793,10 +847,10 @@ class BaseTableComponent extends BaseComponent {
793
847
  });
794
848
  }
795
849
  async view(model) {
796
- const conf = _.get(this.config, 'view');
797
- const dialog = _.get(conf, 'dialog');
798
- const size = _.get(conf, 'size');
799
- if (_.isNil(dialog) || _.isNil(conf)) {
850
+ const conf = this.config?.view;
851
+ const dialog = conf?.dialog;
852
+ const size = conf?.size;
853
+ if (dialog == null || conf == null) {
800
854
  return;
801
855
  }
802
856
  if (this._lock) {
@@ -826,9 +880,9 @@ class BaseTableComponent extends BaseComponent {
826
880
  });
827
881
  }
828
882
  async delete(model) {
829
- const conf = _.get(this.config, 'delete');
830
- const dialog = _.get(conf, 'dialog');
831
- if (_.isNil(conf) || _.isNil(dialog)) {
883
+ const conf = this.config?.delete;
884
+ const dialog = conf?.dialog;
885
+ if (conf == null || dialog == null) {
832
886
  return;
833
887
  }
834
888
  if (this._lock) {
@@ -841,10 +895,10 @@ class BaseTableComponent extends BaseComponent {
841
895
  autoFocus: 'first-tabbable',
842
896
  width: '400px',
843
897
  data: {
844
- title: _.get(conf, 'title'),
845
- message: _.get(conf, 'message'),
846
- cancelLabel: _.get(conf, 'cancelTitle'),
847
- confirmLabel: _.get(conf, 'confirmTitle'),
898
+ title: conf?.title,
899
+ message: conf?.message,
900
+ cancelLabel: conf?.cancelTitle,
901
+ confirmLabel: conf?.confirmTitle,
848
902
  callback: async () => {
849
903
  await this.remove(model);
850
904
  },
@@ -876,10 +930,10 @@ class BaseTableComponent extends BaseComponent {
876
930
  return FxUtils.getTagClass(tag, true);
877
931
  }
878
932
  capitalize(label) {
879
- return _.capitalize(label);
933
+ return label ? label.charAt(0).toUpperCase() + label.slice(1).toLowerCase() : label;
880
934
  }
881
935
  value(model, key, defaultValue = '---') {
882
- return _.get(model, key, defaultValue);
936
+ return FxUtils.get(model, key, defaultValue);
883
937
  }
884
938
  toggleExpand(element) {
885
939
  this.expandedElement = this.expandedElement === element ? null : element;
@@ -887,7 +941,7 @@ class BaseTableComponent extends BaseComponent {
887
941
  async updateStatus(params) {
888
942
  try {
889
943
  await this.api.updateStatus(params);
890
- this.toastr.success(_.get(this.config, 'updateStatus.message', 'Update Success'));
944
+ this.toastr.success(this.config?.updateStatus?.message ?? 'Update Success');
891
945
  }
892
946
  catch (err) {
893
947
  this.toastr.error(FxUtils.parseError(err));
@@ -896,18 +950,15 @@ class BaseTableComponent extends BaseComponent {
896
950
  await this.refresh();
897
951
  }
898
952
  }
899
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseTableComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
900
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: BaseTableComponent, isStandalone: true, viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "table", first: true, predicate: MatTable, descendants: true }], usesInheritance: true, ngImport: i0 });
953
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BaseTableComponent, deps: [{ token: i0.Injector }, { token: HttpWrapper }, { token: i1.MatDialog }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
954
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.2.20", type: BaseTableComponent, isStandalone: true, viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], usesInheritance: true, ngImport: i0 });
901
955
  }
902
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseTableComponent, decorators: [{
956
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BaseTableComponent, decorators: [{
903
957
  type: Directive
904
- }], ctorParameters: () => [{ type: i0.Injector }, { type: HttpWrapper }, { type: undefined }, { type: i0.ChangeDetectorRef }], propDecorators: { paginator: [{
958
+ }], ctorParameters: () => [{ type: i0.Injector }, { type: HttpWrapper }, { type: i1.MatDialog }, { type: i0.ChangeDetectorRef }], propDecorators: { paginator: [{
905
959
  type: ViewChild,
906
960
  args: [MatPaginator]
907
- }], table: [{
908
- type: ViewChild,
909
- args: [MatTable]
910
- }] } });
961
+ }], table: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatTable), { isSignal: true }] }] } });
911
962
 
912
963
  /**
913
964
  * List + detail-pane counterpart of BaseTableComponent: the page keeps a
@@ -989,12 +1040,12 @@ class BaseMasterDetailComponent extends BaseTableComponent {
989
1040
  this.ref.detectChanges();
990
1041
  });
991
1042
  }
992
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseMasterDetailComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
993
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: BaseMasterDetailComponent, isStandalone: true, usesInheritance: true, ngImport: i0 });
1043
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BaseMasterDetailComponent, deps: [{ token: i0.Injector }, { token: HttpWrapper }, { token: i1.MatDialog }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
1044
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.20", type: BaseMasterDetailComponent, isStandalone: true, usesInheritance: true, ngImport: i0 });
994
1045
  }
995
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseMasterDetailComponent, decorators: [{
1046
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BaseMasterDetailComponent, decorators: [{
996
1047
  type: Directive
997
- }], ctorParameters: () => [{ type: i0.Injector }, { type: HttpWrapper }, { type: undefined }, { type: i0.ChangeDetectorRef }] });
1048
+ }], ctorParameters: () => [{ type: i0.Injector }, { type: HttpWrapper }, { type: i1.MatDialog }, { type: i0.ChangeDetectorRef }] });
998
1049
 
999
1050
  class BaseDialogComponent extends BaseComponent {
1000
1051
  ref;
@@ -1002,7 +1053,7 @@ class BaseDialogComponent extends BaseComponent {
1002
1053
  toastr;
1003
1054
  api;
1004
1055
  dialog;
1005
- ngForm;
1056
+ ngForm = viewChild('f', ...(ngDevMode ? [{ debugName: "ngForm" }] : /* istanbul ignore next */ []));
1006
1057
  method;
1007
1058
  title;
1008
1059
  model;
@@ -1021,12 +1072,12 @@ class BaseDialogComponent extends BaseComponent {
1021
1072
  this.dialog = dialog;
1022
1073
  // Deep clone: a shallow clone let dialog edits mutate nested fields of
1023
1074
  // the live table row even when the user cancelled.
1024
- this.model = _.cloneDeep(_.get(bindings, 'data'));
1025
- this.method = _.get(bindings, 'method');
1026
- this.title = _.get(bindings, 'title');
1027
- this.disabled = _.get(bindings, 'disabled');
1028
- this.message = _.get(bindings, 'message');
1029
- this.resolve = _.get(bindings, 'resolve');
1075
+ this.model = FxUtils.cloneDeep(bindings?.['data']);
1076
+ this.method = bindings?.['method'];
1077
+ this.title = bindings?.['title'];
1078
+ this.disabled = bindings?.['disabled'];
1079
+ this.message = bindings?.['message'];
1080
+ this.resolve = bindings?.['resolve'];
1030
1081
  }
1031
1082
  // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method -- subclasses across host apps call super lifecycle methods; removing these breaks them at runtime
1032
1083
  ngAfterViewInit() { }
@@ -1108,18 +1159,15 @@ class BaseDialogComponent extends BaseComponent {
1108
1159
  validate() {
1109
1160
  return true;
1110
1161
  }
1111
- 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 });
1112
- 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 });
1162
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BaseDialogComponent, deps: [{ token: i1.MatDialogRef }, { token: MAT_DIALOG_DATA }, { token: FxToastrService }, { token: HttpWrapper }, { token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Directive });
1163
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.2.20", type: BaseDialogComponent, isStandalone: true, viewQueries: [{ propertyName: "ngForm", first: true, predicate: ["f"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0 });
1113
1164
  }
1114
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BaseDialogComponent, decorators: [{
1165
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BaseDialogComponent, decorators: [{
1115
1166
  type: Directive
1116
- }], ctorParameters: () => [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
1167
+ }], ctorParameters: () => [{ type: i1.MatDialogRef }, { type: undefined, decorators: [{
1117
1168
  type: Inject,
1118
1169
  args: [MAT_DIALOG_DATA]
1119
- }] }, { type: FxToastrService }, { type: HttpWrapper }, { type: i1$2.MatDialog }], propDecorators: { ngForm: [{
1120
- type: ViewChild,
1121
- args: ['f', { static: true }]
1122
- }] } });
1170
+ }] }, { type: FxToastrService }, { type: HttpWrapper }, { type: i1.MatDialog }], propDecorators: { ngForm: [{ type: i0.ViewChild, args: ['f', { isSignal: true }] }] } });
1123
1171
 
1124
1172
  class FxLoadingService {
1125
1173
  listener = new EventEmitter();
@@ -1136,10 +1184,10 @@ class FxLoadingService {
1136
1184
  stopAction() {
1137
1185
  this.listenerAction.emit(false);
1138
1186
  }
1139
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxLoadingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1140
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxLoadingService, providedIn: 'root' });
1187
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxLoadingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1188
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxLoadingService, providedIn: 'root' });
1141
1189
  }
1142
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxLoadingService, decorators: [{
1190
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxLoadingService, decorators: [{
1143
1191
  type: Injectable,
1144
1192
  args: [{
1145
1193
  providedIn: 'root'
@@ -1169,10 +1217,10 @@ class FxStorageService {
1169
1217
  remove(key) {
1170
1218
  localStorage.removeItem(key);
1171
1219
  }
1172
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1173
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, providedIn: 'root' });
1220
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1221
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxStorageService, providedIn: 'root' });
1174
1222
  }
1175
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxStorageService, decorators: [{
1223
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxStorageService, decorators: [{
1176
1224
  type: Injectable,
1177
1225
  args: [{
1178
1226
  providedIn: 'root',
@@ -1401,7 +1449,7 @@ const TONE_BADGE = {
1401
1449
  information: 'bg-information/10 text-information',
1402
1450
  };
1403
1451
  function hasVal(v) {
1404
- if (_.isNil(v))
1452
+ if (v == null)
1405
1453
  return false;
1406
1454
  const s = String(v).trim();
1407
1455
  return s !== '' && s !== '-' && s !== '--';
@@ -1420,7 +1468,7 @@ function severityTone(value) {
1420
1468
  */
1421
1469
  function scoreTone(score) {
1422
1470
  let n = Number(score);
1423
- if (!_.isFinite(n) || n <= 0)
1471
+ if (!Number.isFinite(n) || n <= 0)
1424
1472
  return null;
1425
1473
  if (n > 10)
1426
1474
  n = n / 10;
@@ -1440,7 +1488,7 @@ function scoreTone(score) {
1440
1488
  */
1441
1489
  function countTone(count, positiveTone = 'danger') {
1442
1490
  const n = Number(count);
1443
- if (!_.isFinite(n))
1491
+ if (!Number.isFinite(n))
1444
1492
  return null;
1445
1493
  return n > 0 ? positiveTone : 'success';
1446
1494
  }
@@ -1604,11 +1652,11 @@ class TranslationModule {
1604
1652
  providers: []
1605
1653
  };
1606
1654
  }
1607
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1608
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: TranslationModule, imports: [TranslateModule], exports: [TranslateModule] });
1609
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationModule, imports: [TranslateModule, TranslateModule] });
1655
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TranslationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1656
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.20", ngImport: i0, type: TranslationModule, imports: [TranslateModule], exports: [TranslateModule] });
1657
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TranslationModule, imports: [TranslateModule, TranslateModule] });
1610
1658
  }
1611
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationModule, decorators: [{
1659
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TranslationModule, decorators: [{
1612
1660
  type: NgModule,
1613
1661
  args: [{
1614
1662
  imports: [TranslateModule],
@@ -1652,13 +1700,13 @@ class TranslationService {
1652
1700
  onLanguageChange(callback) {
1653
1701
  this.currentLang$.subscribe(callback);
1654
1702
  }
1655
- 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 });
1656
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, providedIn: 'root' });
1703
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TranslationService, deps: [{ token: i1$1.TranslateService }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
1704
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TranslationService, providedIn: 'root' });
1657
1705
  }
1658
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TranslationService, decorators: [{
1706
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TranslationService, decorators: [{
1659
1707
  type: Injectable,
1660
1708
  args: [{ providedIn: 'root' }]
1661
- }], ctorParameters: () => [{ type: i1$3.TranslateService }, { type: i2.HttpClient }] });
1709
+ }], ctorParameters: () => [{ type: i1$1.TranslateService }, { type: i2.HttpClient }] });
1662
1710
 
1663
1711
  class PermissionService {
1664
1712
  permissions = [];
@@ -1666,15 +1714,15 @@ class PermissionService {
1666
1714
  this.permissions = perms;
1667
1715
  }
1668
1716
  hasPermission(requiredPermissions) {
1669
- return _.some(requiredPermissions, permission => this.permissions.includes(permission));
1717
+ return requiredPermissions.some((permission) => this.permissions.includes(permission));
1670
1718
  }
1671
1719
  getPermissions() {
1672
1720
  return [...this.permissions];
1673
1721
  }
1674
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1675
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionService, providedIn: 'root' });
1722
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: PermissionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1723
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: PermissionService, providedIn: 'root' });
1676
1724
  }
1677
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionService, decorators: [{
1725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: PermissionService, decorators: [{
1678
1726
  type: Injectable,
1679
1727
  args: [{
1680
1728
  providedIn: 'root'
@@ -1691,16 +1739,16 @@ class HasPermissionDirective {
1691
1739
  this.permissionService = permissionService;
1692
1740
  }
1693
1741
  set hasPermission(required) {
1694
- const requiredPermissions = _.isArray(required) ? required : [required];
1742
+ const requiredPermissions = Array.isArray(required) ? required : [required];
1695
1743
  this.viewContainerRef.clear();
1696
1744
  if (this.permissionService.hasPermission(requiredPermissions)) {
1697
1745
  this.viewContainerRef.createEmbeddedView(this.templateRef);
1698
1746
  }
1699
1747
  }
1700
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HasPermissionDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: PermissionService }], target: i0.ɵɵFactoryTarget.Directive });
1701
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: HasPermissionDirective, isStandalone: true, selector: "[hasPermission]", inputs: { hasPermission: "hasPermission" }, ngImport: i0 });
1748
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: HasPermissionDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: PermissionService }], target: i0.ɵɵFactoryTarget.Directive });
1749
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.20", type: HasPermissionDirective, isStandalone: true, selector: "[hasPermission]", inputs: { hasPermission: "hasPermission" }, ngImport: i0 });
1702
1750
  }
1703
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: HasPermissionDirective, decorators: [{
1751
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: HasPermissionDirective, decorators: [{
1704
1752
  type: Directive,
1705
1753
  args: [{
1706
1754
  // eslint-disable-next-line @angular-eslint/directive-selector -- renaming is a breaking change for all host-app templates
@@ -1712,18 +1760,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
1712
1760
 
1713
1761
  class TrimOnBlurDirective {
1714
1762
  el;
1715
- ngControl;
1716
- collapseWhitespace = false;
1717
- constructor(el, ngControl) {
1763
+ collapseWhitespace = input(false, { ...(ngDevMode ? { debugName: "collapseWhitespace" } : /* istanbul ignore next */ {}), alias: "appTrimOnBlurCollapse" });
1764
+ /* Optional on purpose: the onBlur fallback below already handles the
1765
+ * no-form case, but the injection was required and crashed any unbound
1766
+ * input once the directive actually entered the compilation scope. */
1767
+ ngControl = inject(NgControl, { optional: true });
1768
+ constructor(el) {
1718
1769
  this.el = el;
1719
- this.ngControl = ngControl;
1720
1770
  }
1721
1771
  onBlur() {
1722
1772
  const native = this.el.nativeElement;
1723
1773
  if (!native)
1724
1774
  return;
1725
1775
  let value = native.value ?? '';
1726
- if (this.collapseWhitespace) {
1776
+ if (this.collapseWhitespace()) {
1727
1777
  value = value.replace(/\s+/g, ' ').trim();
1728
1778
  }
1729
1779
  else {
@@ -1740,19 +1790,16 @@ class TrimOnBlurDirective {
1740
1790
  native.dispatchEvent(ev);
1741
1791
  }
1742
1792
  }
1743
- 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 });
1744
- 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 });
1793
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TrimOnBlurDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
1794
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.20", type: TrimOnBlurDirective, isStandalone: true, selector: "[appTrimOnBlur]", inputs: { collapseWhitespace: { classPropertyName: "collapseWhitespace", publicName: "appTrimOnBlurCollapse", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "blur": "onBlur()" } }, ngImport: i0 });
1745
1795
  }
1746
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TrimOnBlurDirective, decorators: [{
1796
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TrimOnBlurDirective, decorators: [{
1747
1797
  type: Directive,
1748
1798
  args: [{
1749
1799
  // eslint-disable-next-line @angular-eslint/directive-selector -- renaming is a breaking change for all host-app templates
1750
1800
  selector: '[appTrimOnBlur]'
1751
1801
  }]
1752
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i2$1.NgControl }], propDecorators: { collapseWhitespace: [{
1753
- type: Input,
1754
- args: ['appTrimOnBlurCollapse']
1755
- }], onBlur: [{
1802
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { collapseWhitespace: [{ type: i0.Input, args: [{ isSignal: true, alias: "appTrimOnBlurCollapse", required: false }] }], onBlur: [{
1756
1803
  type: HostListener,
1757
1804
  args: ['blur']
1758
1805
  }] } });
@@ -1772,15 +1819,15 @@ class PermissionGuard {
1772
1819
  this.router.navigate(['/unauthorized']);
1773
1820
  return false;
1774
1821
  }
1775
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionGuard, deps: [{ token: PermissionService }, { token: i1$4.Router }], target: i0.ɵɵFactoryTarget.Injectable });
1776
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionGuard, providedIn: 'root' });
1822
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: PermissionGuard, deps: [{ token: PermissionService }, { token: i2$1.Router }], target: i0.ɵɵFactoryTarget.Injectable });
1823
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: PermissionGuard, providedIn: 'root' });
1777
1824
  }
1778
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PermissionGuard, decorators: [{
1825
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: PermissionGuard, decorators: [{
1779
1826
  type: Injectable,
1780
1827
  args: [{
1781
1828
  providedIn: 'root',
1782
1829
  }]
1783
- }], ctorParameters: () => [{ type: PermissionService }, { type: i1$4.Router }] });
1830
+ }], ctorParameters: () => [{ type: PermissionService }, { type: i2$1.Router }] });
1784
1831
 
1785
1832
  class AuthStateService {
1786
1833
  _isLoggedIn$ = new BehaviorSubject(null);
@@ -1797,10 +1844,10 @@ class AuthStateService {
1797
1844
  this.setLoggedIn(false);
1798
1845
  this.unauthorized$.next();
1799
1846
  }
1800
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1801
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthStateService, providedIn: 'root' });
1847
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: AuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1848
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: AuthStateService, providedIn: 'root' });
1802
1849
  }
1803
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthStateService, decorators: [{
1850
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: AuthStateService, decorators: [{
1804
1851
  type: Injectable,
1805
1852
  args: [{ providedIn: 'root' }]
1806
1853
  }], ctorParameters: () => [] });
@@ -1830,10 +1877,10 @@ class AuthInterceptor {
1830
1877
  return throwError(() => error);
1831
1878
  }));
1832
1879
  }
1833
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthInterceptor, deps: [{ token: AuthStateService }], target: i0.ɵɵFactoryTarget.Injectable });
1834
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthInterceptor });
1880
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: AuthInterceptor, deps: [{ token: AuthStateService }], target: i0.ɵɵFactoryTarget.Injectable });
1881
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: AuthInterceptor });
1835
1882
  }
1836
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AuthInterceptor, decorators: [{
1883
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: AuthInterceptor, decorators: [{
1837
1884
  type: Injectable
1838
1885
  }], ctorParameters: () => [{ type: AuthStateService }] });
1839
1886
 
@@ -1848,81 +1895,16 @@ class BreadcrumbService {
1848
1895
  clear() {
1849
1896
  this.breadcrumbs$.next([]);
1850
1897
  }
1851
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BreadcrumbService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1852
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BreadcrumbService, providedIn: 'root' });
1898
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BreadcrumbService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1899
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BreadcrumbService, providedIn: 'root' });
1853
1900
  }
1854
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: BreadcrumbService, decorators: [{
1901
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: BreadcrumbService, decorators: [{
1855
1902
  type: Injectable,
1856
1903
  args: [{
1857
1904
  providedIn: 'root'
1858
1905
  }]
1859
1906
  }] });
1860
1907
 
1861
- class QuillStyleLoaderService {
1862
- platformId;
1863
- loaded = false;
1864
- loadingPromise = null;
1865
- constructor(platformId) {
1866
- this.platformId = platformId;
1867
- }
1868
- /**
1869
- * Load Quill CSS (only in browser). Returns a promise that resolves when
1870
- * the CSS links have been appended.
1871
- */
1872
- load() {
1873
- if (!isPlatformBrowser(this.platformId)) {
1874
- // Server: do nothing and resolve immediately.
1875
- return Promise.resolve();
1876
- }
1877
- if (this.loaded)
1878
- return Promise.resolve();
1879
- if (this.loadingPromise)
1880
- return this.loadingPromise;
1881
- this.loadingPromise = new Promise((resolve) => {
1882
- const cssUrls = [
1883
- // Using CDN is simplest — no consumer angular.json edits needed.
1884
- 'https://cdn.jsdelivr.net/npm/quill/dist/quill.core.css',
1885
- 'https://cdn.jsdelivr.net/npm/quill/dist/quill.snow.css'
1886
- ];
1887
- let remaining = cssUrls.length;
1888
- const onLoad = () => {
1889
- remaining -= 1;
1890
- if (remaining === 0) {
1891
- this.loaded = true;
1892
- resolve();
1893
- }
1894
- };
1895
- cssUrls.forEach((href) => {
1896
- // Do not add duplicate links
1897
- if (document.querySelector(`link[href="${href}"]`)) {
1898
- onLoad();
1899
- return;
1900
- }
1901
- const link = document.createElement('link');
1902
- link.rel = 'stylesheet';
1903
- link.href = href;
1904
- link.onload = () => onLoad();
1905
- link.onerror = () => {
1906
- // still count it as loaded to avoid hanging if CDN fails
1907
- console.warn(`[QuillStyleLoader] failed to load: ${href}`);
1908
- onLoad();
1909
- };
1910
- document.head.appendChild(link);
1911
- });
1912
- });
1913
- return this.loadingPromise;
1914
- }
1915
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: QuillStyleLoaderService, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable });
1916
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: QuillStyleLoaderService, providedIn: 'root' });
1917
- }
1918
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: QuillStyleLoaderService, decorators: [{
1919
- type: Injectable,
1920
- args: [{ providedIn: 'root' }]
1921
- }], ctorParameters: () => [{ type: undefined, decorators: [{
1922
- type: Inject,
1923
- args: [PLATFORM_ID]
1924
- }] }] });
1925
-
1926
1908
  class ThemeService {
1927
1909
  renderer;
1928
1910
  lightClass = 'light_theme';
@@ -1967,10 +1949,10 @@ class ThemeService {
1967
1949
  getLogoPath() {
1968
1950
  return 'assets/images/logo.png';
1969
1951
  }
1970
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ThemeService, deps: [{ token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
1971
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ThemeService, providedIn: 'root' });
1952
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ThemeService, deps: [{ token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
1953
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ThemeService, providedIn: 'root' });
1972
1954
  }
1973
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ThemeService, decorators: [{
1955
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ThemeService, decorators: [{
1974
1956
  type: Injectable,
1975
1957
  args: [{ providedIn: 'root' }]
1976
1958
  }], ctorParameters: () => [{ type: i0.RendererFactory2 }] });
@@ -2192,482 +2174,115 @@ class NotificationService {
2192
2174
  getConnectionId() {
2193
2175
  return this.hubConnection?.connectionId ?? null;
2194
2176
  }
2195
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2196
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: NotificationService, providedIn: 'root' });
2177
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2178
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: NotificationService, providedIn: 'root' });
2197
2179
  }
2198
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: NotificationService, decorators: [{
2180
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: NotificationService, decorators: [{
2199
2181
  type: Injectable,
2200
2182
  args: [{
2201
2183
  providedIn: 'root'
2202
2184
  }]
2203
2185
  }] });
2204
2186
 
2205
- const MATERIAL_MODULE = [
2206
- MatSelectModule,
2207
- MatRadioModule,
2208
- MatButtonModule,
2209
- MatIconModule,
2210
- MatPaginatorModule,
2211
- MatTableModule,
2212
- MatSnackBarModule,
2213
- MatDialogModule,
2214
- MatCheckboxModule,
2215
- MatCardModule,
2216
- MatDatepickerModule,
2217
- MatTimepickerModule,
2218
- MatBadgeModule,
2219
- MatExpansionModule,
2220
- MatFormFieldModule,
2221
- MatMenuModule,
2222
- MatTooltipModule,
2223
- DragDropModule,
2224
- ];
2225
-
2226
2187
  class ButtonComponent {
2227
2188
  label;
2228
- disabled = false;
2229
- buttonVariant = 'alternative';
2189
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
2190
+ buttonVariant = input('alternative', ...(ngDevMode ? [{ debugName: "buttonVariant" }] : /* istanbul ignore next */ []));
2230
2191
  icon;
2231
- class;
2232
- loading = false;
2192
+ class = input(...(ngDevMode ? [undefined, { debugName: "class" }] : /* istanbul ignore next */ []));
2193
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
2233
2194
  /** Native button type. Defaults to 'button' so it never implicitly submits a form. */
2234
- type = 'button';
2195
+ type = input('button', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
2235
2196
  /** Accessible name for icon-only usage (icon set, no label). */
2236
- ariaLabel = '';
2237
- clicked = new EventEmitter();
2197
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
2198
+ clicked = output();
2238
2199
  onClick() {
2239
- if (!this.disabled)
2200
+ if (!this.disabled())
2240
2201
  this.clicked.emit();
2241
2202
  }
2242
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2243
- 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", type: "type", ariaLabel: "ariaLabel" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n [attr.type]=\"type\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-busy]=\"loading || null\"\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\" aria-hidden=\"true\">\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"] }] });
2203
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2204
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ButtonComponent, isStandalone: true, selector: "fx-ui-button", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, buttonVariant: { classPropertyName: "buttonVariant", publicName: "buttonVariant", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: false, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n [attr.type]=\"type()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-busy]=\"loading() || null\"\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\" aria-hidden=\"true\">\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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2244
2205
  }
2245
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ButtonComponent, decorators: [{
2206
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ButtonComponent, decorators: [{
2246
2207
  type: Component,
2247
- args: [{ selector: 'fx-ui-button', standalone: false, template: "<button\n [attr.type]=\"type\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-busy]=\"loading || null\"\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\" aria-hidden=\"true\">\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" }]
2208
+ args: [{ selector: 'fx-ui-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass, HeroIconComponent], template: "<button\n [attr.type]=\"type()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-busy]=\"loading() || null\"\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\" aria-hidden=\"true\">\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" }]
2248
2209
  }], propDecorators: { label: [{
2249
2210
  type: Input
2250
- }], disabled: [{
2251
- type: Input
2252
- }], buttonVariant: [{
2253
- type: Input
2254
- }], icon: [{
2255
- type: Input
2256
- }], class: [{
2257
- type: Input
2258
- }], loading: [{
2259
- type: Input
2260
- }], type: [{
2211
+ }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], buttonVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonVariant", required: false }] }], icon: [{
2261
2212
  type: Input
2262
- }], ariaLabel: [{
2263
- type: Input
2264
- }], clicked: [{
2265
- type: Output
2266
- }] } });
2213
+ }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
2267
2214
 
2268
- class ChartComponent {
2215
+ class ConfirmationDialogComponent {
2269
2216
  ref;
2270
- cdr;
2271
- /* ================= INPUTS ================= */
2272
- type = 'auto';
2273
- data;
2274
- options;
2275
- palette;
2276
- height = '400px';
2217
+ bindings;
2277
2218
  loading = false;
2278
- // pie controls
2279
- pieLegendAlign = '10%';
2280
- pieLegendPosition = 'middle';
2281
- showPieLabel = true;
2282
- mobileWidth = 350;
2283
- labelFontFamily = 'Roboto';
2284
- emptyText = 'No data available';
2285
- /* ================= OUTPUTS ================= */
2286
- chartClick = new EventEmitter();
2287
- chartInit = new EventEmitter();
2288
- /* ================= INTERNAL ================= */
2289
- chartOptions = {};
2290
- isEmpty = false;
2291
- labelFontSize = 12;
2292
- chartInstance;
2293
- resizeObserver;
2294
- intersectionObserver;
2295
- canInit = false;
2296
- isMobile = false;
2297
- containerWidth = 0;
2298
- constructor(ref, cdr) {
2219
+ title = '';
2220
+ message = '';
2221
+ cancelLabel = 'Cancel';
2222
+ confirmLabel = 'Submit';
2223
+ constructor(ref, bindings) {
2299
2224
  this.ref = ref;
2300
- this.cdr = cdr;
2301
- }
2302
- /* ================= LIFECYCLE ================= */
2303
- ngAfterViewInit() {
2304
- // Only initialize when visible (tab-safe)
2305
- this.intersectionObserver = new IntersectionObserver(([entry]) => {
2306
- if (entry.isIntersecting && !this.canInit) {
2307
- this.canInit = true;
2308
- this.updateResponsiveState();
2309
- this.rebuildChart();
2310
- this.cdr.detectChanges();
2311
- }
2312
- }, { threshold: 0.1 });
2313
- this.intersectionObserver.observe(this.ref.nativeElement);
2314
- // Resize-safe (tabs, flex, async layout)
2315
- this.resizeObserver = new ResizeObserver(() => {
2316
- if (!this.canInit)
2317
- return;
2318
- this.updateResponsiveState();
2319
- this.forceMediaRecalc();
2320
- });
2321
- this.resizeObserver.observe(this.ref.nativeElement);
2322
- }
2323
- ngOnChanges() {
2324
- if (this.canInit) {
2325
- this.updateResponsiveState();
2326
- this.rebuildChart();
2327
- }
2328
- }
2329
- ngOnDestroy() {
2330
- this.resizeObserver?.disconnect();
2331
- this.intersectionObserver?.disconnect();
2332
- }
2333
- onThemeChange() {
2334
- if (!this.canInit)
2335
- return;
2336
- requestAnimationFrame(() => this.rebuildChart());
2337
- }
2338
- /* ================= EVENTS ================= */
2339
- onChartClick(event) {
2340
- this.chartClick.emit(event);
2341
- }
2342
- onChartInit(chart) {
2343
- this.chartInstance = chart;
2344
- this.chartInit.emit(chart);
2345
- requestAnimationFrame(() => this.forceMediaRecalc());
2346
- }
2347
- /* ================= CORE FIX ================= */
2348
- updateResponsiveState() {
2349
- const { width } = this.ref.nativeElement.getBoundingClientRect();
2350
- if (width > 0) {
2351
- this.containerWidth = width;
2352
- this.isMobile = width < this.mobileWidth;
2353
- }
2354
- }
2355
- forceMediaRecalc(retry = 0) {
2356
- if (!this.chartInstance)
2357
- return;
2358
- const { width, height } = this.ref.nativeElement.getBoundingClientRect();
2359
- if ((width === 0 || height === 0) && retry < 10) {
2360
- requestAnimationFrame(() => this.forceMediaRecalc(retry + 1));
2361
- return;
2362
- }
2363
- this.rebuildChart();
2364
- this.chartInstance.resize();
2365
- }
2366
- rebuildChart() {
2367
- this.isEmpty = this.checkEmpty();
2368
- if (this.isEmpty) {
2369
- if (this.chartInstance) {
2370
- this.chartInstance.clear();
2371
- }
2372
- return;
2373
- }
2374
- this.chartOptions = this.buildOptions();
2375
- if (this.chartInstance) {
2376
- this.chartInstance.clear();
2377
- this.chartInstance.setOption(this.chartOptions, true);
2378
- }
2379
- }
2380
- checkEmpty() {
2381
- const type = this.detectType();
2382
- if (type === 'bar') {
2383
- const categories = this.data?.categories;
2384
- const values = this.data?.values;
2385
- return !categories?.length || !values?.length;
2386
- }
2387
- if (type === 'pie') {
2388
- if (!Array.isArray(this.data) || this.data.length === 0)
2389
- return true;
2390
- const total = this.data.reduce((sum, d) => sum + (d.value || 0), 0);
2391
- return total === 0;
2392
- }
2393
- return false;
2225
+ this.bindings = bindings;
2226
+ this.title = bindings?.['title'];
2227
+ this.message = bindings?.['message'];
2228
+ this.cancelLabel = bindings?.['cancelLabel'];
2229
+ this.confirmLabel = bindings?.['confirmLabel'];
2394
2230
  }
2395
- /* ================= REGISTRY ================= */
2396
- registry = {
2397
- bar: (data, colors) => ({
2398
- color: colors,
2399
- tooltip: { trigger: 'axis' },
2400
- grid: { left: '5%', right: '5%', bottom: '10%', containLabel: true },
2401
- xAxis: {
2402
- type: 'category',
2403
- data: data?.categories || [],
2404
- axisLabel: {
2405
- interval: 0,
2406
- width: 80,
2407
- overflow: 'truncate',
2408
- ellipsis: '…',
2409
- fontFamily: this.labelFontFamily,
2410
- fontSize: this.labelFontSize,
2411
- color: FxUtils.convertColorFromVariable('--text-secondary'),
2412
- },
2413
- axisLine: {
2414
- lineStyle: {
2415
- color: FxUtils.convertColorFromVariable('--border-strong'),
2416
- },
2417
- },
2418
- },
2419
- yAxis: {
2420
- type: 'value',
2421
- axisLabel: {
2422
- fontFamily: this.labelFontFamily,
2423
- fontSize: this.labelFontSize,
2424
- color: FxUtils.convertColorFromVariable('--text-secondary'),
2425
- },
2426
- axisLine: {
2427
- lineStyle: {
2428
- color: FxUtils.convertColorFromVariable('--border-strong'),
2429
- },
2430
- },
2431
- splitLine: {
2432
- lineStyle: {
2433
- color: FxUtils.convertColorFromVariable('--border-default'),
2434
- },
2435
- },
2436
- },
2437
- series: [
2438
- {
2439
- type: 'bar',
2440
- data: data?.values || [],
2441
- barMaxWidth: 70,
2442
- itemStyle: {
2443
- color: (p) => colors[p.dataIndex % colors.length],
2444
- },
2445
- label: {
2446
- show: true,
2447
- position: 'top',
2448
- fontFamily: this.labelFontFamily,
2449
- fontSize: this.labelFontSize,
2450
- color: FxUtils.convertColorFromVariable('--text-primary'),
2451
- },
2452
- },
2453
- ],
2454
- }),
2455
- pie: (data, colors) => {
2456
- const total = data.reduce((sum, d) => sum + d.value, 0);
2457
- const layout = this.calcPieLayout(data);
2458
- return {
2459
- color: colors,
2460
- tooltip: { trigger: 'item' },
2461
- legend: {
2462
- type: 'scroll',
2463
- orient: layout.legendOrient,
2464
- icon: 'circle',
2465
- itemGap: 12,
2466
- right: layout.legendRight,
2467
- top: layout.legendTop,
2468
- left: layout.legendLeft,
2469
- bottom: layout.legendBottom,
2470
- width: layout.legendWidth,
2471
- formatter: (name) => {
2472
- const item = data.find((d) => d.name === name);
2473
- return item ? `${name}: ${item.value}` : name;
2474
- },
2475
- textStyle: {
2476
- fontFamily: this.labelFontFamily,
2477
- fontSize: 13,
2478
- fontWeight: 500,
2479
- color: FxUtils.convertColorFromVariable('--text-primary'),
2480
- overflow: 'truncate',
2481
- },
2482
- },
2483
- series: [
2484
- {
2485
- type: 'pie',
2486
- radius: ['40%', '70%'],
2487
- center: layout.pieCenter,
2488
- data,
2489
- label: {
2490
- show: this.showPieLabel,
2491
- position: 'outside',
2492
- formatter: '{d}%',
2493
- fontSize: this.labelFontSize,
2494
- fontFamily: this.labelFontFamily,
2495
- color: FxUtils.convertColorFromVariable('--text-primary'),
2496
- textBorderWidth: 0,
2497
- textBorderColor: 'transparent',
2498
- },
2499
- labelLine: {
2500
- show: this.showPieLabel,
2501
- length: 7,
2502
- length2: 7,
2503
- },
2504
- },
2505
- ],
2506
- graphic: {
2507
- type: 'group',
2508
- left: layout.graphicLeft,
2509
- top: layout.graphicTop,
2510
- bounding: 'raw',
2511
- children: [
2512
- {
2513
- type: 'text',
2514
- style: {
2515
- text: total.toString(),
2516
- fontSize: 24,
2517
- fontWeight: 600,
2518
- fontFamily: this.labelFontFamily,
2519
- fill: FxUtils.convertColorFromVariable('--text-primary'),
2520
- align: 'center',
2521
- verticalAlign: 'middle',
2522
- },
2523
- },
2524
- ],
2525
- },
2526
- };
2527
- },
2528
- sunburst: (data, colors) => ({
2529
- color: colors,
2530
- series: [
2531
- {
2532
- type: 'sunburst',
2533
- data,
2534
- radius: ['15%', '90%'],
2535
- itemStyle: {
2536
- borderWidth: 1,
2537
- borderColor: FxUtils.convertColorFromVariable('--border-default'),
2538
- },
2539
- label: {
2540
- rotate: 'tangential',
2541
- fontSize: this.labelFontSize,
2542
- fontFamily: this.labelFontFamily,
2543
- color: FxUtils.convertColorFromVariable('--text-primary'),
2544
- textBorderWidth: 0,
2545
- textBorderColor: 'transparent',
2546
- },
2547
- },
2548
- ],
2549
- }),
2550
- };
2551
- /* ================= PIE LAYOUT ================= */
2552
- calcPieLayout(data) {
2553
- const cw = this.containerWidth || 400;
2554
- if (this.isMobile) {
2555
- return {
2556
- legendOrient: 'horizontal',
2557
- legendLeft: 'center',
2558
- legendRight: undefined,
2559
- legendTop: undefined,
2560
- legendBottom: 0,
2561
- legendWidth: undefined,
2562
- pieCenter: ['50%', '40%'],
2563
- graphicLeft: '50%',
2564
- graphicTop: '40%',
2565
- };
2231
+ async accept() {
2232
+ this.loading = true;
2233
+ if (this.bindings?.['callback']) {
2234
+ await this.bindings.callback();
2235
+ this.loading = false;
2566
2236
  }
2567
- // Estimate legend pixel width from longest formatted label
2568
- const CHAR_WIDTH = 7.5; // approx px per char at fontSize 13
2569
- const ICON_GAP = 30; // legend icon + padding
2570
- const longestLabel = data.reduce((max, d) => {
2571
- return Math.max(max, `${d.name}: ${d.value}`.length);
2572
- }, 0);
2573
- const rawLegendPx = longestLabel * CHAR_WIDTH + ICON_GAP;
2574
- // Clamp: min 100px, max 45% of container
2575
- const legendPx = Math.max(100, Math.min(rawLegendPx, cw * 0.45));
2576
- const legendPct = (legendPx / cw) * 100;
2577
- // Pie center: middle of the remaining space after legend
2578
- const pieCenterX = Math.round((100 - legendPct) / 2);
2579
- return {
2580
- legendOrient: 'vertical',
2581
- legendLeft: undefined,
2582
- legendRight: '2%',
2583
- legendTop: 'middle',
2584
- legendBottom: undefined,
2585
- legendWidth: Math.round(legendPx),
2586
- pieCenter: [`${pieCenterX}%`, '50%'],
2587
- graphicLeft: `${pieCenterX}%`,
2588
- graphicTop: '50%',
2589
- };
2590
- }
2591
- /* ================= BUILD ================= */
2592
- detectType() {
2593
- if (this.type !== 'auto')
2594
- return this.type;
2595
- if (this.data?.children)
2596
- return 'sunburst';
2597
- if (this.data?.categories && this.data?.values)
2598
- return 'bar';
2599
- if (Array.isArray(this.data))
2600
- return 'pie';
2601
- return 'bar';
2602
- }
2603
- buildOptions() {
2604
- const type = this.detectType();
2605
- const palette = this.resolvePalette();
2606
- const base = this.registry[type]?.(this.data, palette) || {};
2607
- return {
2608
- ...base,
2609
- ...this.options,
2610
- };
2237
+ this.ref.close(true);
2611
2238
  }
2612
- resolvePalette() {
2613
- const defaults = [
2614
- 'rgba(var(--success) / 1)',
2615
- 'rgba(var(--information) / 1)',
2616
- 'rgba(var(--critical) / 1)',
2617
- 'rgba(var(--danger) / 1)',
2618
- 'rgba(var(--warning) / 1)',
2619
- 'rgba(var(--discovery) / 1)',
2620
- ];
2621
- const palette = this.palette?.length ? this.palette : defaults;
2622
- return palette.map((raw) => {
2623
- if (!raw.includes('var('))
2624
- return raw;
2625
- const cssVar = raw.match(/var\((.*?)\)/)?.[1];
2626
- const rgb = getComputedStyle(document.body)
2627
- .getPropertyValue(cssVar || '')
2628
- .trim()
2629
- .replace(/\s+/g, ',');
2630
- return `rgba(${rgb},1)`;
2631
- });
2239
+ cancel() {
2240
+ this.ref.close(false);
2632
2241
  }
2633
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChartComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2634
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChartComponent, isStandalone: false, selector: "fx-ui-chart", inputs: { type: "type", data: "data", options: "options", palette: "palette", height: "height", loading: "loading", pieLegendAlign: "pieLegendAlign", pieLegendPosition: "pieLegendPosition", showPieLabel: "showPieLabel", mobileWidth: "mobileWidth", labelFontFamily: "labelFontFamily", emptyText: "emptyText" }, outputs: { chartClick: "chartClick", chartInit: "chartInit" }, host: { listeners: { "window:theme-changed": "onThemeChange()" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"chart-wrapper\" [style.height]=\"height\">\n @if (isEmpty) {\n <div class=\"chart-empty\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"chart-empty-icon\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z\" />\n </svg>\n <span class=\"chart-empty-text\">{{ emptyText }}</span>\n </div>\n } @else {\n <div\n echarts\n [options]=\"chartOptions\"\n [loading]=\"loading\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"fx-chart\"\n [style.height]=\"height\"\n ></div>\n }\n</div>\n", styles: [":host{display:block;width:100%}.chart-wrapper{position:relative;width:100%;height:100%}.chart-container{width:100%;height:100%}.chart-loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--bg-primary-hover)/.6);font-weight:500;font-size:1.1rem;z-index:2;border-radius:4px}.chart-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:12px;color:rgba(var(--text-secondary)/1)}.chart-empty-icon{width:48px;height:48px;opacity:.4}.chart-empty-text{font-size:14px;font-weight:500}\n"], dependencies: [{ kind: "directive", type: i1$5.NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
2242
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ConfirmationDialogComponent, deps: [{ token: i1.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
2243
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.20", type: ConfirmationDialogComponent, isStandalone: true, selector: "fx-ui-confirmation-dialog", ngImport: i0, template: "<div animate.enter=\"fade-in-animation\" class=\"dialog-container\">\n <h1 mat-dialog-title 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: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: ButtonComponent, selector: "fx-ui-button", inputs: ["label", "disabled", "buttonVariant", "icon", "class", "loading", "type", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2635
2244
  }
2636
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChartComponent, decorators: [{
2245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ConfirmationDialogComponent, decorators: [{
2637
2246
  type: Component,
2638
- args: [{ selector: 'fx-ui-chart', standalone: false, template: "<div class=\"chart-wrapper\" [style.height]=\"height\">\n @if (isEmpty) {\n <div class=\"chart-empty\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"chart-empty-icon\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z\" />\n </svg>\n <span class=\"chart-empty-text\">{{ emptyText }}</span>\n </div>\n } @else {\n <div\n echarts\n [options]=\"chartOptions\"\n [loading]=\"loading\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"fx-chart\"\n [style.height]=\"height\"\n ></div>\n }\n</div>\n", styles: [":host{display:block;width:100%}.chart-wrapper{position:relative;width:100%;height:100%}.chart-container{width:100%;height:100%}.chart-loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--bg-primary-hover)/.6);font-weight:500;font-size:1.1rem;z-index:2;border-radius:4px}.chart-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:12px;color:rgba(var(--text-secondary)/1)}.chart-empty-icon{width:48px;height:48px;opacity:.4}.chart-empty-text{font-size:14px;font-weight:500}\n"] }]
2639
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { type: [{
2640
- type: Input
2641
- }], data: [{
2642
- type: Input
2643
- }], options: [{
2644
- type: Input
2645
- }], palette: [{
2646
- type: Input
2647
- }], height: [{
2648
- type: Input
2649
- }], loading: [{
2650
- type: Input
2651
- }], pieLegendAlign: [{
2652
- type: Input
2653
- }], pieLegendPosition: [{
2654
- type: Input
2655
- }], showPieLabel: [{
2656
- type: Input
2657
- }], mobileWidth: [{
2658
- type: Input
2659
- }], labelFontFamily: [{
2660
- type: Input
2661
- }], emptyText: [{
2662
- type: Input
2663
- }], chartClick: [{
2664
- type: Output
2665
- }], chartInit: [{
2666
- type: Output
2667
- }], onThemeChange: [{
2668
- type: HostListener,
2669
- args: ['window:theme-changed']
2670
- }] } });
2247
+ args: [{ selector: 'fx-ui-confirmation-dialog', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
2248
+ MatDialogTitle,
2249
+ CdkScrollable,
2250
+ MatDialogContent,
2251
+ MatDialogActions,
2252
+ ButtonComponent,
2253
+ ], template: "<div animate.enter=\"fade-in-animation\" class=\"dialog-container\">\n <h1 mat-dialog-title 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" }]
2254
+ }], ctorParameters: () => [{ type: i1.MatDialogRef }, { type: undefined, decorators: [{
2255
+ type: Inject,
2256
+ args: [MAT_DIALOG_DATA]
2257
+ }] }] });
2258
+
2259
+ /**
2260
+ * Thin façade over MatDialog so app code never imports @angular/material
2261
+ * directly (behavior-layer rule, Playbook §5.1). Same semantics — the
2262
+ * returned ref is the Material one, typed through this service.
2263
+ */
2264
+ class FxDialogService {
2265
+ dialog = inject(MatDialog);
2266
+ open(component, config) {
2267
+ return this.dialog.open(component, config);
2268
+ }
2269
+ /** Standard confirmation flow — resolves true when the user confirms. */
2270
+ async confirm(options = {}) {
2271
+ // ConfirmationDialogComponent reads MAT_DIALOG_DATA as its bindings and
2272
+ // closes with true/false.
2273
+ const ref = this.dialog.open(ConfirmationDialogComponent, { data: { ...options } });
2274
+ return !!(await firstValueFrom(ref.afterClosed()));
2275
+ }
2276
+ closeAll() {
2277
+ this.dialog.closeAll();
2278
+ }
2279
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2280
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxDialogService, providedIn: 'root' });
2281
+ }
2282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxDialogService, decorators: [{
2283
+ type: Injectable,
2284
+ args: [{ providedIn: 'root' }]
2285
+ }] });
2671
2286
 
2672
2287
  class FxComponent {
2673
2288
  /**
@@ -2677,6 +2292,9 @@ class FxComponent {
2677
2292
  * bind to an ancestor's NgControl.
2678
2293
  */
2679
2294
  ngControl = inject(NgControl, { optional: true, self: true });
2295
+ /** With OnPush, programmatic writes (form.setValue / setDisabledState) must
2296
+ * mark the view — CVA calls come from outside the component's own events. */
2297
+ cdr = inject(ChangeDetectorRef);
2680
2298
  disabled = false;
2681
2299
  value;
2682
2300
  onChange = () => undefined;
@@ -2701,6 +2319,7 @@ class FxComponent {
2701
2319
  // Pass through as-is. Coercing null to '' here broke boolean/number
2702
2320
  // controls; string controls that want '' as their empty value override.
2703
2321
  this.value = value;
2322
+ this.cdr.markForCheck();
2704
2323
  }
2705
2324
  registerOnChange(fn) {
2706
2325
  this.onChange = fn;
@@ -2710,6 +2329,7 @@ class FxComponent {
2710
2329
  }
2711
2330
  setDisabledState(isDisabled) {
2712
2331
  this.disabled = isDisabled;
2332
+ this.cdr.markForCheck();
2713
2333
  }
2714
2334
  get invalid() {
2715
2335
  return !!(this.ngControl?.invalid && this.ngControl?.touched);
@@ -2763,10 +2383,10 @@ class FxComponent {
2763
2383
  const firstKey = Object.keys(this.errors)[0];
2764
2384
  return messages[firstKey] || `Invalid ${label ?? 'value'}`;
2765
2385
  }
2766
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2767
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: FxComponent, isStandalone: true, inputs: { disabled: "disabled" }, ngImport: i0 });
2386
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2387
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.20", type: FxComponent, isStandalone: true, inputs: { disabled: "disabled" }, ngImport: i0 });
2768
2388
  }
2769
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FxComponent, decorators: [{
2389
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FxComponent, decorators: [{
2770
2390
  type: Directive
2771
2391
  }], ctorParameters: () => [], propDecorators: { disabled: [{
2772
2392
  type: Input
@@ -2775,8 +2395,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
2775
2395
  class CheckboxComponent extends FxComponent {
2776
2396
  ref;
2777
2397
  label = '';
2778
- rounded;
2779
- valueChange = new EventEmitter();
2398
+ rounded = input(...(ngDevMode ? [undefined, { debugName: "rounded" }] : /* istanbul ignore next */ []));
2399
+ valueChange = output();
2780
2400
  constructor(ref) {
2781
2401
  super();
2782
2402
  this.ref = ref;
@@ -2796,59 +2416,63 @@ class CheckboxComponent extends FxComponent {
2796
2416
  markTouched() {
2797
2417
  this.onTouched();
2798
2418
  }
2799
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CheckboxComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2800
- 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 <!-- sr-only (not `hidden`): keeps the input focusable and in the a11y tree -->\n <input\n type=\"checkbox\"\n class=\"peer sr-only\"\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 peer-focus-visible:ring-2 peer-focus-visible:ring-primary/50\"\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"] }] });
2419
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CheckboxComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2420
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: CheckboxComponent, isStandalone: true, selector: "fx-ui-checkbox", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null } }, 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 <!-- sr-only (not `hidden`): keeps the input focusable and in the a11y tree -->\n <input\n type=\"checkbox\"\n class=\"peer sr-only\"\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 peer-focus-visible:ring-2 peer-focus-visible:ring-primary/50\"\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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2801
2421
  }
2802
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CheckboxComponent, decorators: [{
2422
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CheckboxComponent, decorators: [{
2803
2423
  type: Component,
2804
- 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 <!-- sr-only (not `hidden`): keeps the input focusable and in the a11y tree -->\n <input\n type=\"checkbox\"\n class=\"peer sr-only\"\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 peer-focus-visible:ring-2 peer-focus-visible:ring-primary/50\"\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" }]
2424
+ args: [{ selector: 'fx-ui-checkbox', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass], 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 <!-- sr-only (not `hidden`): keeps the input focusable and in the a11y tree -->\n <input\n type=\"checkbox\"\n class=\"peer sr-only\"\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 peer-focus-visible:ring-2 peer-focus-visible:ring-primary/50\"\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" }]
2805
2425
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
2806
2426
  type: Input
2807
- }], rounded: [{
2808
- type: Input
2809
- }], valueChange: [{
2810
- type: Output
2811
- }] } });
2427
+ }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
2812
2428
 
2813
2429
  class CircleProgressBar {
2814
- percent = 0;
2815
- showPercent = false;
2430
+ percent = input(0, ...(ngDevMode ? [{ debugName: "percent" }] : /* istanbul ignore next */ []));
2431
+ showPercent = input(false, ...(ngDevMode ? [{ debugName: "showPercent" }] : /* istanbul ignore next */ []));
2816
2432
  radius = 35;
2817
2433
  stroke = 10;
2818
2434
  normalizedRadius = this.radius - this.stroke / 2;
2819
2435
  circumference = 2 * Math.PI * this.normalizedRadius;
2820
2436
  get dashOffset() {
2821
- const clamped = Math.max(0, Math.min(100, this.percent));
2437
+ const clamped = Math.max(0, Math.min(100, this.percent()));
2822
2438
  return this.circumference - (clamped / 100) * this.circumference;
2823
2439
  }
2824
2440
  get ariaLabel() {
2825
- return `${Math.round(this.percent)}%`;
2441
+ return `${Math.round(this.percent())}%`;
2826
2442
  }
2827
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CircleProgressBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
2828
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: CircleProgressBar, isStandalone: false, selector: "fx-ui-circle-progress-bar", inputs: { percent: "percent", showPercent: "showPercent" }, ngImport: i0, template: "<div class=\"flex items-center justify-center w-full h-full\">\n <svg\n class=\"transform -rotate-90 block\"\n [attr.viewBox]=\"'0 0 ' + radius * 2 + ' ' + radius * 2\"\n width=\"100%\"\n height=\"100%\"\n >\n <circle\n class=\"opacity-20\"\n [attr.cx]=\"radius\"\n [attr.cy]=\"radius\"\n [attr.r]=\"normalizedRadius\"\n [attr.stroke-width]=\"stroke\"\n fill=\"transparent\"\n stroke=\"currentColor\"\n ></circle>\n\n <circle\n class=\"stroke-current\"\n [attr.cx]=\"radius\"\n [attr.cy]=\"radius\"\n [attr.r]=\"normalizedRadius\"\n [attr.stroke-width]=\"stroke\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n [attr.stroke-dasharray]=\"circumference\"\n [attr.stroke-dashoffset]=\"dashOffset\"\n style=\"transition: stroke-dashoffset 300ms linear\"\n ></circle>\n\n @if(showPercent){\n <text\n [attr.x]=\"radius\"\n [attr.y]=\"radius\"\n dominant-baseline=\"central\"\n text-anchor=\"middle\"\n class=\"text-xs font-medium\"\n fill=\"currentColor\"\n >\n {{ percent }}%\n </text>\n }\n </svg>\n</div>\n", styles: [""] });
2443
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CircleProgressBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
2444
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: CircleProgressBar, isStandalone: true, selector: "fx-ui-circle-progress-bar", inputs: { percent: { classPropertyName: "percent", publicName: "percent", isSignal: true, isRequired: false, transformFunction: null }, showPercent: { classPropertyName: "showPercent", publicName: "showPercent", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"flex items-center justify-center w-full h-full\">\n <svg\n class=\"transform -rotate-90 block\"\n [attr.viewBox]=\"'0 0 ' + radius * 2 + ' ' + radius * 2\"\n width=\"100%\"\n height=\"100%\"\n >\n <circle\n class=\"opacity-20\"\n [attr.cx]=\"radius\"\n [attr.cy]=\"radius\"\n [attr.r]=\"normalizedRadius\"\n [attr.stroke-width]=\"stroke\"\n fill=\"transparent\"\n stroke=\"currentColor\"\n ></circle>\n\n <circle\n class=\"stroke-current\"\n [attr.cx]=\"radius\"\n [attr.cy]=\"radius\"\n [attr.r]=\"normalizedRadius\"\n [attr.stroke-width]=\"stroke\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n [attr.stroke-dasharray]=\"circumference\"\n [attr.stroke-dashoffset]=\"dashOffset\"\n style=\"transition: stroke-dashoffset 300ms linear\"\n ></circle>\n\n @if(showPercent()){\n <text\n [attr.x]=\"radius\"\n [attr.y]=\"radius\"\n dominant-baseline=\"central\"\n text-anchor=\"middle\"\n class=\"text-xs font-medium\"\n fill=\"currentColor\"\n >\n {{ percent() }}%\n </text>\n }\n </svg>\n</div>\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2829
2445
  }
2830
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CircleProgressBar, decorators: [{
2446
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CircleProgressBar, decorators: [{
2831
2447
  type: Component,
2832
- args: [{ selector: 'fx-ui-circle-progress-bar', standalone: false, template: "<div class=\"flex items-center justify-center w-full h-full\">\n <svg\n class=\"transform -rotate-90 block\"\n [attr.viewBox]=\"'0 0 ' + radius * 2 + ' ' + radius * 2\"\n width=\"100%\"\n height=\"100%\"\n >\n <circle\n class=\"opacity-20\"\n [attr.cx]=\"radius\"\n [attr.cy]=\"radius\"\n [attr.r]=\"normalizedRadius\"\n [attr.stroke-width]=\"stroke\"\n fill=\"transparent\"\n stroke=\"currentColor\"\n ></circle>\n\n <circle\n class=\"stroke-current\"\n [attr.cx]=\"radius\"\n [attr.cy]=\"radius\"\n [attr.r]=\"normalizedRadius\"\n [attr.stroke-width]=\"stroke\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n [attr.stroke-dasharray]=\"circumference\"\n [attr.stroke-dashoffset]=\"dashOffset\"\n style=\"transition: stroke-dashoffset 300ms linear\"\n ></circle>\n\n @if(showPercent){\n <text\n [attr.x]=\"radius\"\n [attr.y]=\"radius\"\n dominant-baseline=\"central\"\n text-anchor=\"middle\"\n class=\"text-xs font-medium\"\n fill=\"currentColor\"\n >\n {{ percent }}%\n </text>\n }\n </svg>\n</div>\n" }]
2833
- }], propDecorators: { percent: [{
2834
- type: Input
2835
- }], showPercent: [{
2836
- type: Input
2837
- }] } });
2448
+ args: [{ selector: 'fx-ui-circle-progress-bar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex items-center justify-center w-full h-full\">\n <svg\n class=\"transform -rotate-90 block\"\n [attr.viewBox]=\"'0 0 ' + radius * 2 + ' ' + radius * 2\"\n width=\"100%\"\n height=\"100%\"\n >\n <circle\n class=\"opacity-20\"\n [attr.cx]=\"radius\"\n [attr.cy]=\"radius\"\n [attr.r]=\"normalizedRadius\"\n [attr.stroke-width]=\"stroke\"\n fill=\"transparent\"\n stroke=\"currentColor\"\n ></circle>\n\n <circle\n class=\"stroke-current\"\n [attr.cx]=\"radius\"\n [attr.cy]=\"radius\"\n [attr.r]=\"normalizedRadius\"\n [attr.stroke-width]=\"stroke\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n [attr.stroke-dasharray]=\"circumference\"\n [attr.stroke-dashoffset]=\"dashOffset\"\n style=\"transition: stroke-dashoffset 300ms linear\"\n ></circle>\n\n @if(showPercent()){\n <text\n [attr.x]=\"radius\"\n [attr.y]=\"radius\"\n dominant-baseline=\"central\"\n text-anchor=\"middle\"\n class=\"text-xs font-medium\"\n fill=\"currentColor\"\n >\n {{ percent() }}%\n </text>\n }\n </svg>\n</div>\n" }]
2449
+ }], propDecorators: { percent: [{ type: i0.Input, args: [{ isSignal: true, alias: "percent", required: false }] }], showPercent: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPercent", required: false }] }] } });
2838
2450
 
2839
2451
  let nextPickerId = 0;
2452
+ const pad = (n) => String(n).padStart(2, '0');
2453
+ /**
2454
+ * Date/time field backed by first-party Material pickers (mat-datepicker +
2455
+ * mat-timepicker, the latter first-party since Material 19) — replaces the
2456
+ * former @danielmoncada/angular-datetime-picker + moment adapter stack.
2457
+ *
2458
+ * The public contract is unchanged: the CVA value is a plain string
2459
+ * ('YYYY-MM-DD HH:mm' for type 'both', 'YYYY-MM-DD' for 'calendar',
2460
+ * 'HH:mm' for 'timer'), so existing forms keep working as-is.
2461
+ */
2840
2462
  class DatetimePicker extends FxComponent {
2841
2463
  ref;
2842
2464
  label;
2843
- placeholder = 'Select date and time';
2844
- required = false;
2845
- type = 'both';
2846
- minDate;
2847
- maxDate;
2465
+ placeholder = input('Select date and time', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
2466
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
2467
+ /** 'both' | 'calendar' | 'timer' — same values the Owl picker accepted. */
2468
+ type = input('both', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
2469
+ minDate = input(...(ngDevMode ? [undefined, { debugName: "minDate" }] : /* istanbul ignore next */ []));
2470
+ maxDate = input(...(ngDevMode ? [undefined, { debugName: "maxDate" }] : /* istanbul ignore next */ []));
2848
2471
  errorMessages = {};
2849
- validateFn;
2472
+ validateFn = input(...(ngDevMode ? [undefined, { debugName: "validateFn" }] : /* istanbul ignore next */ []));
2850
2473
  fieldId = `fx-datetime-${nextPickerId++}`;
2851
- startAt;
2474
+ /** Internal Date the Material pickers operate on; `value` stays a string. */
2475
+ dateValue = null;
2852
2476
  constructor(ref) {
2853
2477
  super();
2854
2478
  this.ref = ref;
@@ -2858,65 +2482,119 @@ class DatetimePicker extends FxComponent {
2858
2482
  this.ref.detectChanges();
2859
2483
  });
2860
2484
  }
2485
+ get showDate() {
2486
+ return this.type() !== 'timer';
2487
+ }
2488
+ get showTime() {
2489
+ return this.type() !== 'calendar';
2490
+ }
2491
+ get min() {
2492
+ return this.toDate(this.minDate());
2493
+ }
2494
+ get max() {
2495
+ return this.toDate(this.maxDate());
2496
+ }
2861
2497
  onBlur() {
2862
2498
  this.onTouched();
2863
- this.validate(this.validateFn);
2499
+ this.validate(this.validateFn());
2864
2500
  }
2865
2501
  writeValue(value) {
2866
2502
  this.value = value ?? '';
2867
- this.startAt = value ?? '';
2503
+ this.dateValue = this.toDate(value);
2868
2504
  this.ref.markForCheck();
2869
2505
  }
2870
- onValueChange(date) {
2506
+ onDateChange(date) {
2871
2507
  if (this.disabled)
2872
2508
  return;
2873
- this.value = date;
2874
- this.onChange(date);
2509
+ const next = date ? new Date(date) : null;
2510
+ // Keep the already-picked time when only the calendar part changes.
2511
+ if (next && this.dateValue) {
2512
+ next.setHours(this.dateValue.getHours(), this.dateValue.getMinutes(), 0, 0);
2513
+ }
2514
+ this.commit(next);
2515
+ }
2516
+ onTimeChange(time) {
2517
+ if (this.disabled || !time)
2518
+ return;
2519
+ const next = this.dateValue ? new Date(this.dateValue) : new Date();
2520
+ next.setHours(time.getHours(), time.getMinutes(), 0, 0);
2521
+ this.commit(next);
2522
+ }
2523
+ commit(next) {
2524
+ this.dateValue = next;
2525
+ this.value = this.format(next);
2526
+ this.onChange(this.value);
2875
2527
  this.onTouched();
2528
+ this.ref.markForCheck();
2876
2529
  }
2877
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DatetimePicker, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2878
- 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\" [attr.for]=\"fieldId\">\n {{ label }}\n <span *ngIf=\"required\" class=\"txt-required\" aria-hidden=\"true\">*</span>\n </label>\n }\n\n <div class=\"relative\">\n <input\n [id]=\"fieldId\"\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: ["@charset \"UTF-8\";@layer properties;::ng-deep .owl-dt-container{border-radius:.75rem;border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 10px 10px -5px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),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){background-color:rgb(var(--bg-primary-hover))}::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-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-strong));background-color:rgb(var(--bg-primary));color:rgb(var(--text-primary))}::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{--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgb(var(--text-primary))}::ng-deep .owl-dt-control-arrow-button .owl-dt-control-button-content{color:rgb(var(--text-primary))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header{color:rgb(var(--text-secondary))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-weekdays th{--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgb(var(--text-secondary))}::ng-deep .owl-dt-inline-container,::ng-deep .owl-dt-popup-container{border-radius:.75rem;border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-strong));--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-font-weight: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\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 });
2530
+ toDate(value) {
2531
+ if (!value)
2532
+ return null;
2533
+ if (value instanceof Date)
2534
+ return isNaN(value.getTime()) ? null : value;
2535
+ // Accepted string shapes: 'YYYY-MM-DD', 'YYYY-MM-DD HH:mm[:ss]', 'HH:mm'.
2536
+ const s = String(value).trim();
2537
+ if (/^\d{2}:\d{2}/.test(s)) {
2538
+ const d = new Date();
2539
+ d.setHours(+s.slice(0, 2), +s.slice(3, 5), 0, 0);
2540
+ return d;
2541
+ }
2542
+ const d = new Date(s.replace(' ', 'T'));
2543
+ return isNaN(d.getTime()) ? null : d;
2544
+ }
2545
+ format(d) {
2546
+ if (!d)
2547
+ return '';
2548
+ const date = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
2549
+ const time = `${pad(d.getHours())}:${pad(d.getMinutes())}`;
2550
+ const type = this.type();
2551
+ if (type === 'calendar')
2552
+ return date;
2553
+ if (type === 'timer')
2554
+ return time;
2555
+ return `${date} ${time}`;
2556
+ }
2557
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DatetimePicker, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DatetimePicker, isStandalone: true, selector: "fx-ui-datetime-picker", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: false, isRequired: false, transformFunction: null }, validateFn: { classPropertyName: "validateFn", publicName: "validateFn", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
2559
+ provideNativeDateAdapter(),
2560
+ // en-GB display ⇒ DD/MM/YYYY + 24h — matches FxUtils.formatDateTime.
2561
+ { provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
2562
+ ], 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\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required()) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"flex gap-normal\">\n @if (showDate) {\n <div class=\"relative flex-1\">\n <input\n [id]=\"fieldId\"\n [matDatepicker]=\"datePicker\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled\"\n [min]=\"min\"\n [max]=\"max\"\n [value]=\"dateValue\"\n (dateChange)=\"onDateChange($event.value)\"\n (click)=\"!disabled && datePicker.open()\"\n (blur)=\"onBlur()\"\n readonly\n class=\"input-default pr-9\"\n />\n <span\n (click)=\"!disabled && datePicker.open()\"\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 <mat-datepicker #datePicker></mat-datepicker>\n </div>\n }\n @if (showTime) {\n <div class=\"relative\" [class.flex-1]=\"!showDate\" [class.w-32]=\"showDate\">\n <input\n [matTimepicker]=\"timePicker\"\n placeholder=\"HH:mm\"\n [disabled]=\"disabled\"\n [value]=\"dateValue\"\n (valueChange)=\"onTimeChange($event)\"\n (click)=\"!disabled && timePicker.open()\"\n (blur)=\"onBlur()\"\n readonly\n class=\"input-default pr-9\"\n />\n <span\n (click)=\"!disabled && timePicker.open()\"\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=\"clock\" [size]=\"20\" class=\"text-text-primary\"></fx-ui-hero-icon>\n </span>\n <mat-timepicker #timePicker></mat-timepicker>\n </div>\n }\n </div>\n @if (invalid) {\n <div class=\"txt-invalid\">{{ getErrorMessage(label) }}</div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";@layer properties;::ng-deep .mat-datepicker-content,::ng-deep mat-timepicker .mat-timepicker-panel,::ng-deep .mat-timepicker-panel{border-radius:.75rem;border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 10px 10px -5px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);color:rgb(var(--text-primary));--mat-datepicker-calendar-container-background-color: rgb(var(--bg-primary));--mat-datepicker-calendar-container-text-color: rgb(var(--text-primary));--mat-datepicker-calendar-date-text-color: rgb(var(--text-primary));--mat-datepicker-calendar-date-selected-state-background-color: rgb(var(--primary));--mat-datepicker-calendar-date-selected-state-text-color: #fff;--mat-datepicker-calendar-date-today-outline-color: rgb(var(--primary));--mat-datepicker-calendar-date-hover-state-background-color: rgb(var(--bg-primary-hover));--mat-datepicker-calendar-header-text-color: rgb(var(--text-secondary));--mat-datepicker-calendar-period-button-text-color: rgb(var(--text-primary));--mat-datepicker-calendar-navigation-button-icon-color: rgb(var(--text-primary));--mat-datepicker-calendar-date-disabled-state-text-color: rgb(var(--text-placeholder));--mat-timepicker-container-background-color: rgb(var(--bg-primary))}::ng-deep .mat-timepicker-panel .mat-mdc-option{color:rgb(var(--text-primary))}::ng-deep .mat-timepicker-panel .mat-mdc-option:hover:not(.mdc-list-item--disabled){background-color:rgb(var(--bg-primary-hover))}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i1$2.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i1$2.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "ngmodule", type: MatTimepickerModule }, { kind: "component", type: i2$2.MatTimepicker, selector: "mat-timepicker", inputs: ["interval", "options", "disableRipple", "aria-label", "aria-labelledby", "panelClass"], outputs: ["selected", "opened", "closed"], exportAs: ["matTimepicker"] }, { kind: "directive", type: i2$2.MatTimepickerInput, selector: "input[matTimepicker]", inputs: ["value", "matTimepicker", "matTimepickerMin", "matTimepickerMax", "matTimepickerOpenOnClick", "disabled"], outputs: ["valueChange"], exportAs: ["matTimepickerInput"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2879
2563
  }
2880
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DatetimePicker, decorators: [{
2564
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DatetimePicker, decorators: [{
2881
2565
  type: Component,
2882
- 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\" [attr.for]=\"fieldId\">\n {{ label }}\n <span *ngIf=\"required\" class=\"txt-required\" aria-hidden=\"true\">*</span>\n </label>\n }\n\n <div class=\"relative\">\n <input\n [id]=\"fieldId\"\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: ["@charset \"UTF-8\";@layer properties;::ng-deep .owl-dt-container{border-radius:.75rem;border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 10px 10px -5px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),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){background-color:rgb(var(--bg-primary-hover))}::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-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-strong));background-color:rgb(var(--bg-primary));color:rgb(var(--text-primary))}::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{--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgb(var(--text-primary))}::ng-deep .owl-dt-control-arrow-button .owl-dt-control-button-content{color:rgb(var(--text-primary))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header{color:rgb(var(--text-secondary))}::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-weekdays th{--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgb(var(--text-secondary))}::ng-deep .owl-dt-inline-container,::ng-deep .owl-dt-popup-container{border-radius:.75rem;border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-strong));--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-font-weight: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
2566
+ args: [{ selector: 'fx-ui-datetime-picker', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatDatepickerModule, MatTimepickerModule, HeroIconComponent], providers: [
2567
+ provideNativeDateAdapter(),
2568
+ // en-GB display ⇒ DD/MM/YYYY + 24h — matches FxUtils.formatDateTime.
2569
+ { provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
2570
+ ], template: "<div class=\"flex flex-col mb-4 w-full text-left\">\n @if (label) {\n <label class=\"txt-field-label\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required()) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"flex gap-normal\">\n @if (showDate) {\n <div class=\"relative flex-1\">\n <input\n [id]=\"fieldId\"\n [matDatepicker]=\"datePicker\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled\"\n [min]=\"min\"\n [max]=\"max\"\n [value]=\"dateValue\"\n (dateChange)=\"onDateChange($event.value)\"\n (click)=\"!disabled && datePicker.open()\"\n (blur)=\"onBlur()\"\n readonly\n class=\"input-default pr-9\"\n />\n <span\n (click)=\"!disabled && datePicker.open()\"\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 <mat-datepicker #datePicker></mat-datepicker>\n </div>\n }\n @if (showTime) {\n <div class=\"relative\" [class.flex-1]=\"!showDate\" [class.w-32]=\"showDate\">\n <input\n [matTimepicker]=\"timePicker\"\n placeholder=\"HH:mm\"\n [disabled]=\"disabled\"\n [value]=\"dateValue\"\n (valueChange)=\"onTimeChange($event)\"\n (click)=\"!disabled && timePicker.open()\"\n (blur)=\"onBlur()\"\n readonly\n class=\"input-default pr-9\"\n />\n <span\n (click)=\"!disabled && timePicker.open()\"\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=\"clock\" [size]=\"20\" class=\"text-text-primary\"></fx-ui-hero-icon>\n </span>\n <mat-timepicker #timePicker></mat-timepicker>\n </div>\n }\n </div>\n @if (invalid) {\n <div class=\"txt-invalid\">{{ getErrorMessage(label) }}</div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";@layer properties;::ng-deep .mat-datepicker-content,::ng-deep mat-timepicker .mat-timepicker-panel,::ng-deep .mat-timepicker-panel{border-radius:.75rem;border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 10px 10px -5px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);color:rgb(var(--text-primary));--mat-datepicker-calendar-container-background-color: rgb(var(--bg-primary));--mat-datepicker-calendar-container-text-color: rgb(var(--text-primary));--mat-datepicker-calendar-date-text-color: rgb(var(--text-primary));--mat-datepicker-calendar-date-selected-state-background-color: rgb(var(--primary));--mat-datepicker-calendar-date-selected-state-text-color: #fff;--mat-datepicker-calendar-date-today-outline-color: rgb(var(--primary));--mat-datepicker-calendar-date-hover-state-background-color: rgb(var(--bg-primary-hover));--mat-datepicker-calendar-header-text-color: rgb(var(--text-secondary));--mat-datepicker-calendar-period-button-text-color: rgb(var(--text-primary));--mat-datepicker-calendar-navigation-button-icon-color: rgb(var(--text-primary));--mat-datepicker-calendar-date-disabled-state-text-color: rgb(var(--text-placeholder));--mat-timepicker-container-background-color: rgb(var(--bg-primary))}::ng-deep .mat-timepicker-panel .mat-mdc-option{color:rgb(var(--text-primary))}::ng-deep .mat-timepicker-panel .mat-mdc-option:hover:not(.mdc-list-item--disabled){background-color:rgb(var(--bg-primary-hover))}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
2883
2571
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
2884
2572
  type: Input
2885
- }], placeholder: [{
2886
- type: Input
2887
- }], required: [{
2888
- type: Input
2889
- }], type: [{
2890
- type: Input
2891
- }], minDate: [{
2892
- type: Input
2893
- }], maxDate: [{
2894
- type: Input
2895
- }], errorMessages: [{
2896
- type: Input
2897
- }], validateFn: [{
2573
+ }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], errorMessages: [{
2898
2574
  type: Input
2899
- }] } });
2575
+ }], validateFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "validateFn", required: false }] }] } });
2900
2576
 
2901
2577
  class DndUploadComponent {
2902
- multiple = false;
2578
+ cdr = inject(ChangeDetectorRef);
2579
+ multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
2903
2580
  accept = '';
2904
- maxSizeMB = 10;
2905
- strictSize = true;
2581
+ maxSizeMB = input(10, ...(ngDevMode ? [{ debugName: "maxSizeMB" }] : /* istanbul ignore next */ []));
2582
+ strictSize = input(true, ...(ngDevMode ? [{ debugName: "strictSize" }] : /* istanbul ignore next */ []));
2906
2583
  /** Icon name from heroicons (outline). Default: 'arrow-up-tray' */
2907
- icon = 'arrow-up-tray';
2584
+ icon = input('arrow-up-tray', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
2908
2585
  /** CSS color value for accent (border, icon, link). Default uses --gradient-primary-start */
2909
- accentColor = '';
2910
- fileDrop = new EventEmitter();
2911
- fileClick = new EventEmitter();
2912
- uploadComplete = new EventEmitter();
2913
- uploadError = new EventEmitter();
2586
+ accentColor = input('', ...(ngDevMode ? [{ debugName: "accentColor" }] : /* istanbul ignore next */ []));
2587
+ fileDrop = output();
2588
+ fileClick = output();
2589
+ uploadComplete = output();
2590
+ uploadError = output();
2914
2591
  isDragOver = false;
2915
2592
  isOpening = false;
2916
2593
  get accentStyle() {
2917
- if (!this.accentColor)
2594
+ const accentColor = this.accentColor();
2595
+ if (!accentColor)
2918
2596
  return {};
2919
- return { '--dnd-accent': this.accentColor };
2597
+ return { '--dnd-accent': accentColor };
2920
2598
  }
2921
2599
  onDragOver(event) {
2922
2600
  event.preventDefault();
@@ -2943,6 +2621,7 @@ class DndUploadComponent {
2943
2621
  setTimeout(() => {
2944
2622
  inputEl?.click();
2945
2623
  this.isOpening = false;
2624
+ this.cdr.markForCheck();
2946
2625
  }, 0);
2947
2626
  }
2948
2627
  onFileSelected(event) {
@@ -2961,10 +2640,10 @@ class DndUploadComponent {
2961
2640
  .filter((t) => t);
2962
2641
  for (const file of files) {
2963
2642
  const sizeMB = file.size / 1024 / 1024;
2964
- if (this.strictSize && sizeMB > this.maxSizeMB) {
2643
+ if (this.strictSize() && sizeMB > this.maxSizeMB()) {
2965
2644
  this.uploadError.emit({
2966
2645
  file,
2967
- reason: `File too large: ${sizeMB.toFixed(2)} MB > ${this.maxSizeMB} MB`,
2646
+ reason: `File too large: ${sizeMB.toFixed(2)} MB > ${this.maxSizeMB()} MB`,
2968
2647
  });
2969
2648
  continue;
2970
2649
  }
@@ -2998,63 +2677,15 @@ class DndUploadComponent {
2998
2677
  return a === fileType;
2999
2678
  });
3000
2679
  }
3001
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DndUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3002
- 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"] }] });
2680
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DndUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2681
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DndUploadComponent, isStandalone: true, selector: "fx-ui-dnd-upload", inputs: { multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: false, isRequired: false, transformFunction: null }, maxSizeMB: { classPropertyName: "maxSizeMB", publicName: "maxSizeMB", isSignal: true, isRequired: false, transformFunction: null }, strictSize: { classPropertyName: "strictSize", publicName: "strictSize", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, accentColor: { classPropertyName: "accentColor", publicName: "accentColor", isSignal: true, isRequired: false, transformFunction: null } }, 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: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3003
2682
  }
3004
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DndUploadComponent, decorators: [{
2683
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DndUploadComponent, decorators: [{
3005
2684
  type: Component,
3006
- 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"] }]
3007
- }], propDecorators: { multiple: [{
3008
- type: Input
3009
- }], accept: [{
3010
- type: Input
3011
- }], maxSizeMB: [{
2685
+ args: [{ selector: 'fx-ui-dnd-upload', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle, HeroIconComponent], 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"] }]
2686
+ }], propDecorators: { multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], accept: [{
3012
2687
  type: Input
3013
- }], strictSize: [{
3014
- type: Input
3015
- }], icon: [{
3016
- type: Input
3017
- }], accentColor: [{
3018
- type: Input
3019
- }], fileDrop: [{
3020
- type: Output
3021
- }], fileClick: [{
3022
- type: Output
3023
- }], uploadComplete: [{
3024
- type: Output
3025
- }], uploadError: [{
3026
- type: Output
3027
- }] } });
3028
-
3029
- class FlowConnection {
3030
- nodes = [];
3031
- edges = [];
3032
- backgroundColor = '--bg-hover-primary';
3033
- view = ['100%', '400px'];
3034
- handleConnection(connection) {
3035
- this.edges = [
3036
- ...this.edges,
3037
- {
3038
- id: `${connection.source} -> ${connection.target}`,
3039
- ...connection,
3040
- },
3041
- ];
3042
- }
3043
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FlowConnection, deps: [], target: i0.ɵɵFactoryTarget.Component });
3044
- 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: i39.VflowComponent, selector: "vflow", inputs: ["view", "minZoom", "maxZoom", "background", "optimization", "entitiesSelectable", "keyboardShortcuts", "connection", "snapGrid", "elevateNodesOnSelect", "elevateEdgesOnSelect", "nodes", "alignmentHelper", "edges"], outputs: ["onComponentNodeEvent"] }, { kind: "directive", type: i39.ConnectionControllerDirective, selector: "[onConnect], [onReconnect], [connect], [reconnect]", outputs: ["onConnect", "connect", "onReconnect", "reconnect"] }] });
3045
- }
3046
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FlowConnection, decorators: [{
3047
- type: Component,
3048
- args: [{ selector: 'fx-ui-flow-connection', standalone: false, 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" }]
3049
- }], propDecorators: { nodes: [{
3050
- type: Input
3051
- }], edges: [{
3052
- type: Input
3053
- }], backgroundColor: [{
3054
- type: Input
3055
- }], view: [{
3056
- type: Input
3057
- }] } });
2688
+ }], maxSizeMB: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSizeMB", required: false }] }], strictSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "strictSize", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], accentColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "accentColor", required: false }] }], fileDrop: [{ type: i0.Output, args: ["fileDrop"] }], fileClick: [{ type: i0.Output, args: ["fileClick"] }], uploadComplete: [{ type: i0.Output, args: ["uploadComplete"] }], uploadError: [{ type: i0.Output, args: ["uploadError"] }] } });
3058
2689
 
3059
2690
  let nextInputId = 0;
3060
2691
  class InputComponent extends FxComponent {
@@ -3062,18 +2693,18 @@ class InputComponent extends FxComponent {
3062
2693
  label = '';
3063
2694
  tooltip = '';
3064
2695
  type = 'text';
3065
- placeholder = '';
2696
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
3066
2697
  errorMessages = {};
3067
- required = false;
2698
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
3068
2699
  suffixIcon;
3069
- class;
3070
- maxlength;
3071
- validateFn;
3072
- blurred = new EventEmitter();
3073
- focused = new EventEmitter();
3074
- suffixClick = new EventEmitter();
2700
+ class = input(...(ngDevMode ? [undefined, { debugName: "class" }] : /* istanbul ignore next */ []));
2701
+ maxlength = input(...(ngDevMode ? [undefined, { debugName: "maxlength" }] : /* istanbul ignore next */ []));
2702
+ validateFn = input(...(ngDevMode ? [undefined, { debugName: "validateFn" }] : /* istanbul ignore next */ []));
2703
+ blurred = output();
2704
+ focused = output();
2705
+ suffixClick = output();
3075
2706
  /** Accessible name for the suffix icon button (it renders no text). */
3076
- suffixAriaLabel = '';
2707
+ suffixAriaLabel = input('', ...(ngDevMode ? [{ debugName: "suffixAriaLabel" }] : /* istanbul ignore next */ []));
3077
2708
  fieldId = `fx-input-${nextInputId++}`;
3078
2709
  showPassword = false;
3079
2710
  validateError = null;
@@ -3090,8 +2721,9 @@ class InputComponent extends FxComponent {
3090
2721
  onInput(event) {
3091
2722
  const input = event.target;
3092
2723
  let newValue = input.value;
3093
- if (this.maxlength && newValue.length > this.maxlength) {
3094
- newValue = newValue.slice(0, this.maxlength);
2724
+ const maxlength = this.maxlength();
2725
+ if (maxlength && newValue.length > maxlength) {
2726
+ newValue = newValue.slice(0, maxlength);
3095
2727
  input.value = newValue;
3096
2728
  }
3097
2729
  this.value = newValue;
@@ -3104,9 +2736,10 @@ class InputComponent extends FxComponent {
3104
2736
  onBlur() {
3105
2737
  this.onTouched();
3106
2738
  this.blurred.emit();
3107
- if (this.validateFn) {
3108
- this.validateError = this.validateFn(this.value);
3109
- this.validate(this.validateFn);
2739
+ const validateFn = this.validateFn();
2740
+ if (validateFn) {
2741
+ this.validateError = validateFn(this.value);
2742
+ this.validate(validateFn);
3110
2743
  }
3111
2744
  }
3112
2745
  togglePassword() {
@@ -3127,54 +2760,38 @@ class InputComponent extends FxComponent {
3127
2760
  return 'number';
3128
2761
  return this.type;
3129
2762
  }
3130
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3131
- 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", suffixAriaLabel: "suffixAriaLabel" }, 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\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 [id]=\"fieldId\"\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 [attr.aria-invalid]=\"invalid || null\"\n [attr.aria-describedby]=\"invalid ? fieldId + '-error' : null\"\n [attr.aria-required]=\"required ? true : null\"\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 [attr.aria-label]=\"\n type === 'password'\n ? (showPassword ? 'Hide password' : 'Show password')\n : (suffixAriaLabel || null)\n \"\n [attr.aria-pressed]=\"type === 'password' ? showPassword : null\"\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 aria-hidden=\"true\"\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 aria-hidden=\"true\"\n ></fx-ui-hero-icon>\n }\n </button>\n }\n </div>\n\n @if (invalid) {\n <div class=\"txt-invalid\" role=\"alert\" [id]=\"fieldId + '-error'\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: TrimOnBlurDirective, selector: "[appTrimOnBlur]", inputs: ["appTrimOnBlurCollapse"] }, { kind: "directive", type: i57.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"] }] });
2763
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: InputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2764
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: InputComponent, isStandalone: true, selector: "fx-ui-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: false, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, suffixIcon: { classPropertyName: "suffixIcon", publicName: "suffixIcon", isSignal: false, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, maxlength: { classPropertyName: "maxlength", publicName: "maxlength", isSignal: true, isRequired: false, transformFunction: null }, validateFn: { classPropertyName: "validateFn", publicName: "validateFn", isSignal: true, isRequired: false, transformFunction: null }, suffixAriaLabel: { classPropertyName: "suffixAriaLabel", publicName: "suffixAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, 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\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required()) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 [id]=\"fieldId\"\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 [attr.aria-invalid]=\"invalid || null\"\n [attr.aria-describedby]=\"invalid ? fieldId + '-error' : null\"\n [attr.aria-required]=\"required() ? true : null\"\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 [attr.aria-label]=\"\n type === 'password'\n ? (showPassword ? 'Hide password' : 'Show password')\n : (suffixAriaLabel() || null)\n \"\n [attr.aria-pressed]=\"type === 'password' ? showPassword : null\"\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 aria-hidden=\"true\"\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 aria-hidden=\"true\"\n ></fx-ui-hero-icon>\n }\n </button>\n }\n </div>\n\n @if (invalid) {\n <div class=\"txt-invalid\" role=\"alert\" [id]=\"fieldId + '-error'\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: TrimOnBlurDirective, selector: "[appTrimOnBlur]", inputs: ["appTrimOnBlurCollapse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3132
2765
  }
3133
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InputComponent, decorators: [{
2766
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: InputComponent, decorators: [{
3134
2767
  type: Component,
3135
- 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\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 [id]=\"fieldId\"\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 [attr.aria-invalid]=\"invalid || null\"\n [attr.aria-describedby]=\"invalid ? fieldId + '-error' : null\"\n [attr.aria-required]=\"required ? true : null\"\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 [attr.aria-label]=\"\n type === 'password'\n ? (showPassword ? 'Hide password' : 'Show password')\n : (suffixAriaLabel || null)\n \"\n [attr.aria-pressed]=\"type === 'password' ? showPassword : null\"\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 aria-hidden=\"true\"\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 aria-hidden=\"true\"\n ></fx-ui-hero-icon>\n }\n </button>\n }\n </div>\n\n @if (invalid) {\n <div class=\"txt-invalid\" role=\"alert\" [id]=\"fieldId + '-error'\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n" }]
2768
+ args: [{ selector: 'fx-ui-input', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
2769
+ HeroIconComponent,
2770
+ MatTooltip,
2771
+ TrimOnBlurDirective,
2772
+ ], template: "<div class=\"mb-4 text-left w-full text-text-primary\" [class]=\"class()\">\n @if (label) {\n <label class=\"block txt-field-label\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required()) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 [id]=\"fieldId\"\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 [attr.aria-invalid]=\"invalid || null\"\n [attr.aria-describedby]=\"invalid ? fieldId + '-error' : null\"\n [attr.aria-required]=\"required() ? true : null\"\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 [attr.aria-label]=\"\n type === 'password'\n ? (showPassword ? 'Hide password' : 'Show password')\n : (suffixAriaLabel() || null)\n \"\n [attr.aria-pressed]=\"type === 'password' ? showPassword : null\"\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 aria-hidden=\"true\"\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 aria-hidden=\"true\"\n ></fx-ui-hero-icon>\n }\n </button>\n }\n </div>\n\n @if (invalid) {\n <div class=\"txt-invalid\" role=\"alert\" [id]=\"fieldId + '-error'\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n" }]
3136
2773
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
3137
2774
  type: Input
3138
2775
  }], tooltip: [{
3139
2776
  type: Input
3140
2777
  }], type: [{
3141
2778
  type: Input
3142
- }], placeholder: [{
3143
- type: Input
3144
- }], errorMessages: [{
3145
- type: Input
3146
- }], required: [{
3147
- type: Input
3148
- }], suffixIcon: [{
2779
+ }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessages: [{
3149
2780
  type: Input
3150
- }], class: [{
2781
+ }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], suffixIcon: [{
3151
2782
  type: Input
3152
- }], maxlength: [{
3153
- type: Input
3154
- }], validateFn: [{
3155
- type: Input
3156
- }], blurred: [{
3157
- type: Output
3158
- }], focused: [{
3159
- type: Output
3160
- }], suffixClick: [{
3161
- type: Output
3162
- }], suffixAriaLabel: [{
3163
- type: Input
3164
- }] } });
2783
+ }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], maxlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxlength", required: false }] }], validateFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "validateFn", required: false }] }], blurred: [{ type: i0.Output, args: ["blurred"] }], focused: [{ type: i0.Output, args: ["focused"] }], suffixClick: [{ type: i0.Output, args: ["suffixClick"] }], suffixAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffixAriaLabel", required: false }] }] } });
3165
2784
 
3166
2785
  class LoadingPanel {
3167
- show = false;
2786
+ show = input(false, ...(ngDevMode ? [{ debugName: "show" }] : /* istanbul ignore next */ []));
3168
2787
  message = "Loading";
3169
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LoadingPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
3170
- 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"] }] });
2788
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: LoadingPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
2789
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: LoadingPanel, isStandalone: true, selector: "fx-ui-loading-panel", inputs: { show: { classPropertyName: "show", publicName: "show", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: false, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- Full-screen glass overlay -->\n@if (show()) {\n <div\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 <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 @if (message) {\n <div class=\"text-sm text-text-primary text-center\">\n {{ message }}\n </div>\n }\n </div>\n </div>\n}\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3171
2790
  }
3172
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LoadingPanel, decorators: [{
2791
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: LoadingPanel, decorators: [{
3173
2792
  type: Component,
3174
- args: [{ selector: 'fx-ui-loading-panel', standalone: false, template: "<!-- Full-screen glass overlay -->\n<div\n *ngIf=\"show\"\n class=\"fixed inset-0 z-50 flex items-center justify-center\"\n aria-hidden=\"false\"\n role=\"alert\"\n aria-busy=\"true\"\n>\n <div class=\"absolute inset-0 bg-bg-primary/30 backdrop-blur-xl\" aria-hidden=\"true\"></div>\n\n <div\n class=\"relative z-10 flex flex-col items-center gap-4 p-6 rounded-2xl shadow-xl bg-bg-primary/70 border border-border-strong backdrop-bg-primary/70\"\n style=\"min-width: 220px; max-width: 90%\"\n >\n <svg fill=\"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" }]
3175
- }], propDecorators: { show: [{
3176
- type: Input
3177
- }], message: [{
2793
+ args: [{ selector: 'fx-ui-loading-panel', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Full-screen glass overlay -->\n@if (show()) {\n <div\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 <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 @if (message) {\n <div class=\"text-sm text-text-primary text-center\">\n {{ message }}\n </div>\n }\n </div>\n </div>\n}\n" }]
2794
+ }], propDecorators: { show: [{ type: i0.Input, args: [{ isSignal: true, alias: "show", required: false }] }], message: [{
3178
2795
  type: Input
3179
2796
  }] } });
3180
2797
 
@@ -3183,10 +2800,10 @@ class RadioButtonToggleComponent extends FxComponent {
3183
2800
  ref;
3184
2801
  groupId = `fx-radio-toggle-${nextToggleGroupId++}`;
3185
2802
  label;
3186
- required = false;
3187
- options = [];
2803
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
2804
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
3188
2805
  errorMessages = {};
3189
- class;
2806
+ class = input(...(ngDevMode ? [undefined, { debugName: "class" }] : /* istanbul ignore next */ []));
3190
2807
  constructor(ref) {
3191
2808
  super();
3192
2809
  this.ref = ref;
@@ -3201,23 +2818,17 @@ class RadioButtonToggleComponent extends FxComponent {
3201
2818
  this.onChange(value);
3202
2819
  this.onTouched();
3203
2820
  }
3204
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonToggleComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3205
- 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 <!-- A radiogroup has no single control a <label> could point at \u2014 name it via aria-labelledby. -->\n @if(label){<span class=\"txt-field-label\" [id]=\"groupId + '-label'\">\n {{ label }}\n @if(required) {<span class=\"txt-required\" aria-hidden=\"true\">*</span>} </span\n >}\n\n <div\n class=\"inline-flex w-full rounded-lg overflow-hidden\"\n role=\"radiogroup\"\n [attr.aria-labelledby]=\"label ? groupId + '-label' : null\"\n >\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"] }] });
2821
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: RadioButtonToggleComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2822
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: RadioButtonToggleComponent, isStandalone: true, selector: "fx-ui-radio-toggle, [fx-ui-radio-toggle]", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: false, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<div class=\"flex flex-col text-left mb-4 w-full\" [class]=\"class()\">\n <!-- A radiogroup has no single control a <label> could point at \u2014 name it via aria-labelledby. -->\n @if(label){<span class=\"txt-field-label\" [id]=\"groupId + '-label'\">\n {{ label }}\n @if(required()) {<span class=\"txt-required\" aria-hidden=\"true\">*</span>} </span\n >}\n\n <div\n class=\"inline-flex w-full rounded-lg overflow-hidden\"\n role=\"radiogroup\"\n [attr.aria-labelledby]=\"label ? groupId + '-label' : null\"\n >\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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3206
2823
  }
3207
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonToggleComponent, decorators: [{
2824
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: RadioButtonToggleComponent, decorators: [{
3208
2825
  type: Component,
3209
- 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 <!-- A radiogroup has no single control a <label> could point at \u2014 name it via aria-labelledby. -->\n @if(label){<span class=\"txt-field-label\" [id]=\"groupId + '-label'\">\n {{ label }}\n @if(required) {<span class=\"txt-required\" aria-hidden=\"true\">*</span>} </span\n >}\n\n <div\n class=\"inline-flex w-full rounded-lg overflow-hidden\"\n role=\"radiogroup\"\n [attr.aria-labelledby]=\"label ? groupId + '-label' : null\"\n >\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" }]
2826
+ args: [{ selector: 'fx-ui-radio-toggle, [fx-ui-radio-toggle]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass], template: "<div class=\"flex flex-col text-left mb-4 w-full\" [class]=\"class()\">\n <!-- A radiogroup has no single control a <label> could point at \u2014 name it via aria-labelledby. -->\n @if(label){<span class=\"txt-field-label\" [id]=\"groupId + '-label'\">\n {{ label }}\n @if(required()) {<span class=\"txt-required\" aria-hidden=\"true\">*</span>} </span\n >}\n\n <div\n class=\"inline-flex w-full rounded-lg overflow-hidden\"\n role=\"radiogroup\"\n [attr.aria-labelledby]=\"label ? groupId + '-label' : null\"\n >\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" }]
3210
2827
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
3211
2828
  type: Input
3212
- }], required: [{
2829
+ }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], errorMessages: [{
3213
2830
  type: Input
3214
- }], options: [{
3215
- type: Input
3216
- }], errorMessages: [{
3217
- type: Input
3218
- }], class: [{
3219
- type: Input
3220
- }] } });
2831
+ }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3221
2832
 
3222
2833
  let nextRadioGroupId = 0;
3223
2834
  class RadioButtonComponent extends FxComponent {
@@ -3225,10 +2836,10 @@ class RadioButtonComponent extends FxComponent {
3225
2836
  groupId = `fx-radio-${nextRadioGroupId++}`;
3226
2837
  label;
3227
2838
  tooltip = '';
3228
- required = false;
3229
- options = [];
2839
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
2840
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
3230
2841
  errorMessages = {};
3231
- class;
2842
+ class = input(...(ngDevMode ? [undefined, { debugName: "class" }] : /* istanbul ignore next */ []));
3232
2843
  constructor(ref) {
3233
2844
  super();
3234
2845
  this.ref = ref;
@@ -3243,122 +2854,29 @@ class RadioButtonComponent extends FxComponent {
3243
2854
  this.onChange(value);
3244
2855
  this.onTouched();
3245
2856
  }
3246
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3247
- 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\n class=\"w-full rounded-lg overflow-hidden\"\n [class]=\"class\"\n role=\"radiogroup\"\n [attr.aria-labelledby]=\"label ? groupId + '-label' : null\"\n>\n <!-- A radiogroup has no single control a <label> could point at \u2014 name it via aria-labelledby. -->\n @if (label) {\n <span class=\"txt-field-label block\" [id]=\"groupId + '-label'\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 </span>\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: i57.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"] }] });
2857
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: RadioButtonComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2858
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: RadioButtonComponent, isStandalone: true, selector: "fx-ui-radio", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: false, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<div\n class=\"w-full rounded-lg overflow-hidden\"\n [class]=\"class()\"\n role=\"radiogroup\"\n [attr.aria-labelledby]=\"label ? groupId + '-label' : null\"\n >\n <!-- A radiogroup has no single control a <label> could point at \u2014 name it via aria-labelledby. -->\n @if (label) {\n <span class=\"txt-field-label block\" [id]=\"groupId + '-label'\">\n {{ label }}\n @if (required()) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 </span>\n }\n\n @for (opt of options(); track opt) {\n <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 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 <span class=\"txt-default mb-0\">{{ opt.label }}</span>\n </button>\n }\n @if (invalid) {\n <div class=\"txt-invalid\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3248
2859
  }
3249
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RadioButtonComponent, decorators: [{
2860
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: RadioButtonComponent, decorators: [{
3250
2861
  type: Component,
3251
- args: [{ selector: 'fx-ui-radio', standalone: false, template: "<div\n class=\"w-full rounded-lg overflow-hidden\"\n [class]=\"class\"\n role=\"radiogroup\"\n [attr.aria-labelledby]=\"label ? groupId + '-label' : null\"\n>\n <!-- A radiogroup has no single control a <label> could point at \u2014 name it via aria-labelledby. -->\n @if (label) {\n <span class=\"txt-field-label block\" [id]=\"groupId + '-label'\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 </span>\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" }]
2862
+ args: [{ selector: 'fx-ui-radio', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
2863
+ HeroIconComponent,
2864
+ MatTooltip,
2865
+ NgClass,
2866
+ ], template: "<div\n class=\"w-full rounded-lg overflow-hidden\"\n [class]=\"class()\"\n role=\"radiogroup\"\n [attr.aria-labelledby]=\"label ? groupId + '-label' : null\"\n >\n <!-- A radiogroup has no single control a <label> could point at \u2014 name it via aria-labelledby. -->\n @if (label) {\n <span class=\"txt-field-label block\" [id]=\"groupId + '-label'\">\n {{ label }}\n @if (required()) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 </span>\n }\n\n @for (opt of options(); track opt) {\n <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 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 <span class=\"txt-default mb-0\">{{ opt.label }}</span>\n </button>\n }\n @if (invalid) {\n <div class=\"txt-invalid\">\n {{ getErrorMessage(label) }}\n </div>\n }\n</div>\n" }]
3252
2867
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
3253
2868
  type: Input
3254
2869
  }], tooltip: [{
3255
2870
  type: Input
3256
- }], required: [{
3257
- type: Input
3258
- }], options: [{
3259
- type: Input
3260
- }], errorMessages: [{
3261
- type: Input
3262
- }], class: [{
3263
- type: Input
3264
- }] } });
3265
-
3266
- class RichTextAreaComponent extends FxComponent {
3267
- cdr;
3268
- styleLoader;
3269
- platformId;
3270
- editorContainer;
3271
- placeholder = 'Write something...';
3272
- toolbarOptions = [
3273
- // ['undo', 'redo'],
3274
- [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
3275
- [{ 'font': [] }],
3276
- [{ 'size': ['small', false, 'large', 'huge'] }],
3277
- [{ 'align': [] }],
3278
- [{ 'color': [] }, { 'background': [] }],
3279
- ['bold', 'italic', 'underline', 'strike'],
3280
- ['blockquote', 'code-block'],
3281
- [{ 'list': 'ordered' }, { 'list': 'bullet' }],
3282
- [{ 'indent': '-1' }, { 'indent': '+1' }],
3283
- ['link', 'image'],
3284
- ['clean']
3285
- ];
3286
- contentChange = new EventEmitter();
3287
- quillInstance;
3288
- constructor(cdr, styleLoader, platformId) {
3289
- super();
3290
- this.cdr = cdr;
3291
- this.styleLoader = styleLoader;
3292
- this.platformId = platformId;
3293
- }
3294
- async ngAfterViewInit() {
3295
- if (!isPlatformBrowser(this.platformId))
3296
- return;
3297
- await this.styleLoader.load();
3298
- const QuillModule = await import('quill');
3299
- const Quill = QuillModule.default || QuillModule;
3300
- const icons = Quill.import('ui/icons');
3301
- // icons['undo'] = `<svg viewBox="0 0 18 18"><path d="M6.4 5.2H3L6.8 1l3.8 4.2H7.9C10.2 5.4 12 7.4 12 9.8c0 2.7-2.2 4.9-4.9 4.9S2.2 12.5 2.2 9.8H0c0 3.8 3.1 6.9 6.9 6.9s6.9-3.1 6.9-6.9S10.7 3 7 3v2.2z"></path></svg>`;
3302
- // icons['redo'] = `<svg viewBox="0 0 18 18"><path d="M11.6 5.2H15L11.2 1 7.4 5.2h2.7C7.8 5.4 6 7.4 6 9.8c0 2.7 2.2 4.9 4.9 4.9s4.9-2.2 4.9-4.9H18c0 3.8-3.1 6.9-6.9 6.9S4.2 13.6 4.2 9.8 7.3 3 11 3v2.2z"></path></svg>`;
3303
- this.quillInstance = new Quill(this.editorContainer.nativeElement, {
3304
- theme: 'snow',
3305
- placeholder: this.placeholder,
3306
- modules: {
3307
- history: true,
3308
- toolbar: this.toolbarOptions,
3309
- }
3310
- });
3311
- this.quillInstance.root.style.color = FxUtils.convertColorFromVariable('--text-primary');
3312
- const toolbar = this.quillInstance.getModule('toolbar');
3313
- toolbar.addHandler('undo', () => this.quillInstance.history.undo());
3314
- toolbar.addHandler('redo', () => this.quillInstance.history.redo());
3315
- if (this.value) {
3316
- this.quillInstance.root.innerHTML = this.value;
3317
- }
3318
- this.quillInstance.on('text-change', () => {
3319
- const html = this.quillInstance.root.innerHTML || '';
3320
- this.value = html;
3321
- this.onChange(html);
3322
- this.contentChange.emit(html);
3323
- });
3324
- }
3325
- writeValue(value) {
3326
- this.value = value || '';
3327
- if (this.quillInstance) {
3328
- this.quillInstance.root.innerHTML = this.value;
3329
- }
3330
- }
3331
- setDisabledState(isDisabled) {
3332
- this.disabled = isDisabled;
3333
- if (this.quillInstance) {
3334
- this.quillInstance.enable(!isDisabled);
3335
- }
3336
- }
3337
- 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 });
3338
- 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: ["@charset \"UTF-8\";@layer properties;:host{display:block}.ql-toolbar{border-top-left-radius:.25rem;border-top-right-radius:.25rem;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgb(var(--border-default));padding:calc(var(--spacing, .25rem) * 2)}.ql-container{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.ql-editor{min-height:200px;padding:calc(var(--spacing, .25rem) * 3);font-size:1rem;line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ))}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] });
3339
- }
3340
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RichTextAreaComponent, decorators: [{
3341
- type: Component,
3342
- 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: ["@charset \"UTF-8\";@layer properties;:host{display:block}.ql-toolbar{border-top-left-radius:.25rem;border-top-right-radius:.25rem;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgb(var(--border-default));padding:calc(var(--spacing, .25rem) * 2)}.ql-container{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.ql-editor{min-height:200px;padding:calc(var(--spacing, .25rem) * 3);font-size:1rem;line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ))}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
3343
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: QuillStyleLoaderService }, { type: undefined, decorators: [{
3344
- type: Inject,
3345
- args: [PLATFORM_ID]
3346
- }] }], propDecorators: { editorContainer: [{
3347
- type: ViewChild,
3348
- args: ['editorContainer', { static: true }]
3349
- }], placeholder: [{
3350
- type: Input
3351
- }], toolbarOptions: [{
2871
+ }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], errorMessages: [{
3352
2872
  type: Input
3353
- }], contentChange: [{
3354
- type: Output
3355
- }] } });
2873
+ }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3356
2874
 
3357
2875
  class SearchBarComponent extends FxComponent {
3358
2876
  ref;
3359
- placeholder = 'Search...';
3360
- search = new EventEmitter();
3361
- valueChange = new EventEmitter();
2877
+ placeholder = input('Search...', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
2878
+ search = output();
2879
+ valueChange = output();
3362
2880
  constructor(ref) {
3363
2881
  super();
3364
2882
  this.ref = ref;
@@ -3384,35 +2902,29 @@ class SearchBarComponent extends FxComponent {
3384
2902
  this.valueChange.emit('');
3385
2903
  this.search.emit('');
3386
2904
  }
3387
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SearchBarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3388
- 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"] }] });
2905
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SearchBarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2906
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SearchBarComponent, isStandalone: true, selector: "fx-ui-search-bar", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, 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 @if (value && !disabled) {\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)=\"clear()\"\n aria-label=\"Clear\"\n >\n <i class=\"material-symbols-outlined text-lg select-none\">close</i>\n </button>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3389
2907
  }
3390
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SearchBarComponent, decorators: [{
2908
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SearchBarComponent, decorators: [{
3391
2909
  type: Component,
3392
- 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" }]
3393
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { placeholder: [{
3394
- type: Input
3395
- }], search: [{
3396
- type: Output
3397
- }], valueChange: [{
3398
- type: Output
3399
- }] } });
2910
+ args: [{ selector: 'fx-ui-search-bar', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HeroIconComponent], 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 @if (value && !disabled) {\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)=\"clear()\"\n aria-label=\"Clear\"\n >\n <i class=\"material-symbols-outlined text-lg select-none\">close</i>\n </button>\n }\n</div>\n" }]
2911
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], search: [{ type: i0.Output, args: ["search"] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
3400
2912
 
3401
2913
  let nextSelectId = 0;
3402
2914
  class SelectComponent extends FxComponent {
3403
2915
  ref;
3404
2916
  label = '';
3405
2917
  tooltip = '';
3406
- placeholder = '';
3407
- options = [];
3408
- multiple = false;
2918
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
2919
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
2920
+ multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
3409
2921
  errorMessages = {};
3410
- required = false;
3411
- class;
3412
- enableSearch = false;
3413
- searchFn;
2922
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
2923
+ class = input(...(ngDevMode ? [undefined, { debugName: "class" }] : /* istanbul ignore next */ []));
2924
+ enableSearch = input(false, ...(ngDevMode ? [{ debugName: "enableSearch" }] : /* istanbul ignore next */ []));
2925
+ searchFn = input(...(ngDevMode ? [undefined, { debugName: "searchFn" }] : /* istanbul ignore next */ []));
3414
2926
  /** Emits the current value when the select panel closes (useful for multiple mode). */
3415
- closed = new EventEmitter();
2927
+ closed = output();
3416
2928
  fieldId = `fx-select-${nextSelectId++}`;
3417
2929
  searchTerm = '';
3418
2930
  filteredOptions = [];
@@ -3427,7 +2939,7 @@ class SelectComponent extends FxComponent {
3427
2939
  this.value = value ?? '';
3428
2940
  }
3429
2941
  ngOnInit() {
3430
- this.filteredOptions = this.options;
2942
+ this.filteredOptions = this.options();
3431
2943
  this.search$
3432
2944
  .pipe(debounceTime(300), distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))
3433
2945
  .subscribe((term) => this.performSearch(term));
@@ -3436,7 +2948,7 @@ class SelectComponent extends FxComponent {
3436
2948
  // Sync the rendered list when options arrive/refresh asynchronously
3437
2949
  // (ngOnInit captures the initial — often empty — array only).
3438
2950
  if (changes['options']) {
3439
- this.filteredOptions = this.options ?? [];
2951
+ this.filteredOptions = this.options() ?? [];
3440
2952
  this.ref?.detectChanges();
3441
2953
  }
3442
2954
  }
@@ -3445,8 +2957,8 @@ class SelectComponent extends FxComponent {
3445
2957
  }
3446
2958
  onOpened(open) {
3447
2959
  if (open) {
3448
- this.filteredOptions = this.options;
3449
- if (this.enableSearch)
2960
+ this.filteredOptions = this.options();
2961
+ if (this.enableSearch())
3450
2962
  this.searchTerm = '';
3451
2963
  }
3452
2964
  else {
@@ -3454,19 +2966,20 @@ class SelectComponent extends FxComponent {
3454
2966
  }
3455
2967
  }
3456
2968
  onSearchChange(value) {
3457
- if (!this.enableSearch)
2969
+ if (!this.enableSearch())
3458
2970
  return;
3459
2971
  this.search$.next(value);
3460
2972
  }
3461
2973
  async performSearch(term) {
3462
- if (!this.enableSearch)
2974
+ if (!this.enableSearch())
3463
2975
  return;
3464
- if (!this.searchFn) {
3465
- this.filteredOptions = this.options.filter((o) => o.label?.toLowerCase().includes(term.toLowerCase()));
2976
+ const searchFn = this.searchFn();
2977
+ if (!searchFn) {
2978
+ this.filteredOptions = this.options().filter((o) => o.label?.toLowerCase().includes(term.toLowerCase()));
3466
2979
  this.ref.detectChanges();
3467
2980
  return;
3468
2981
  }
3469
- const result = await this.searchFn(term);
2982
+ const result = await searchFn(term);
3470
2983
  this.filteredOptions = result;
3471
2984
  Promise.resolve().then(() => this.ref.detectChanges());
3472
2985
  }
@@ -3480,60 +2993,47 @@ class SelectComponent extends FxComponent {
3480
2993
  }
3481
2994
  return this.value === value;
3482
2995
  }
3483
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SelectComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3484
- 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\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 [id]=\"fieldId\"\n [required]=\"!!required\"\n [attr.aria-invalid]=\"invalid || null\"\n [attr.aria-describedby]=\"invalid ? fieldId + '-error' : null\"\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 aria-label=\"Search\"\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 focus-visible:ring-2 focus-visible:ring-primary/50 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\" role=\"alert\" [id]=\"fieldId + '-error'\">\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: i57.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"] }] });
2996
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SelectComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2997
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SelectComponent, isStandalone: true, selector: "fx-ui-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, enableSearch: { classPropertyName: "enableSearch", publicName: "enableSearch", isSignal: true, isRequired: false, transformFunction: null }, searchFn: { classPropertyName: "searchFn", publicName: "searchFn", isSignal: true, isRequired: false, transformFunction: null } }, 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\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required()) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 [id]=\"fieldId\"\n [required]=\"!!required()\"\n [attr.aria-invalid]=\"invalid || null\"\n [attr.aria-describedby]=\"invalid ? fieldId + '-error' : null\"\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 aria-label=\"Search\"\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 focus-visible:ring-2 focus-visible:ring-primary/50 text-sm text-text-primary tracking-normal ring-0 transition-colors duration-500 ease-in-out\"\n />\n </div>\n }\n @for (option of filteredOptions; track option) {\n <mat-option [value]=\"option.value\">\n <span class=\"txt-default\">{{ option.label }}</span>\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n @if (invalid) {\n <div class=\"txt-invalid text-left\" role=\"alert\" [id]=\"fieldId + '-error'\">\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: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: 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: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3485
2998
  }
3486
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SelectComponent, decorators: [{
2999
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SelectComponent, decorators: [{
3487
3000
  type: Component,
3488
- 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\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 [id]=\"fieldId\"\n [required]=\"!!required\"\n [attr.aria-invalid]=\"invalid || null\"\n [attr.aria-describedby]=\"invalid ? fieldId + '-error' : null\"\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 aria-label=\"Search\"\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 focus-visible:ring-2 focus-visible:ring-primary/50 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\" role=\"alert\" [id]=\"fieldId + '-error'\">\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"] }]
3001
+ args: [{ selector: 'fx-ui-select', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
3002
+ HeroIconComponent,
3003
+ MatTooltip,
3004
+ MatFormField,
3005
+ MatSelect,
3006
+ FormsModule,
3007
+ MatOption,
3008
+ ], template: "<div class=\"mb-4 text-left w-full\" [class]=\"class()\">\n @if (label) {\n <label class=\"block txt-field-label\" [attr.for]=\"fieldId\">\n {{ label }}\n @if (required()) {\n <span class=\"txt-required\" aria-hidden=\"true\">*</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 [id]=\"fieldId\"\n [required]=\"!!required()\"\n [attr.aria-invalid]=\"invalid || null\"\n [attr.aria-describedby]=\"invalid ? fieldId + '-error' : null\"\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 aria-label=\"Search\"\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 focus-visible:ring-2 focus-visible:ring-primary/50 text-sm text-text-primary tracking-normal ring-0 transition-colors duration-500 ease-in-out\"\n />\n </div>\n }\n @for (option of filteredOptions; track option) {\n <mat-option [value]=\"option.value\">\n <span class=\"txt-default\">{{ option.label }}</span>\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n @if (invalid) {\n <div class=\"txt-invalid text-left\" role=\"alert\" [id]=\"fieldId + '-error'\">\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"] }]
3489
3009
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
3490
3010
  type: Input
3491
3011
  }], tooltip: [{
3492
3012
  type: Input
3493
- }], placeholder: [{
3494
- type: Input
3495
- }], options: [{
3496
- type: Input
3497
- }], multiple: [{
3498
- type: Input
3499
- }], errorMessages: [{
3500
- type: Input
3501
- }], required: [{
3502
- type: Input
3503
- }], class: [{
3504
- type: Input
3505
- }], enableSearch: [{
3013
+ }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], errorMessages: [{
3506
3014
  type: Input
3507
- }], searchFn: [{
3508
- type: Input
3509
- }], closed: [{
3510
- type: Output
3511
- }] } });
3015
+ }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], enableSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSearch", required: false }] }], searchFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchFn", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
3512
3016
 
3513
3017
  class SkeletonTableLoadingComponent {
3514
- columns = 5;
3515
- rows = 5;
3516
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonTableLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3517
- 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"] }] });
3018
+ columns = input(5, ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
3019
+ rows = input(5, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
3020
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SkeletonTableLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3021
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SkeletonTableLoadingComponent, isStandalone: true, selector: "fx-ui-skeleton-table-loading", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null } }, 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: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3518
3022
  }
3519
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonTableLoadingComponent, decorators: [{
3023
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SkeletonTableLoadingComponent, decorators: [{
3520
3024
  type: Component,
3521
- args: [{ selector: 'fx-ui-skeleton-table-loading', standalone: false, 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" }]
3522
- }], propDecorators: { columns: [{
3523
- type: Input
3524
- }], rows: [{
3525
- type: Input
3526
- }] } });
3025
+ args: [{ selector: 'fx-ui-skeleton-table-loading', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle], 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" }]
3026
+ }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }] } });
3527
3027
 
3528
3028
  class SliderComponent extends FxComponent {
3529
3029
  ref;
3530
- trackRef;
3531
- thumbRef;
3532
- min = 0;
3533
- max = 100;
3534
- step = 1;
3535
- vertical = false;
3536
- valueChange = new EventEmitter();
3030
+ trackRef = viewChild.required('track');
3031
+ thumbRef = viewChild.required('thumb');
3032
+ min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
3033
+ max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
3034
+ step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
3035
+ vertical = input(false, ...(ngDevMode ? [{ debugName: "vertical" }] : /* istanbul ignore next */ []));
3036
+ valueChange = output();
3537
3037
  dragging = false;
3538
3038
  constructor(ref) {
3539
3039
  super();
@@ -3548,15 +3048,15 @@ class SliderComponent extends FxComponent {
3548
3048
  this.ref.markForCheck();
3549
3049
  }
3550
3050
  writeValue(value) {
3551
- this.value = this._normalizeValue(value ?? this.min);
3051
+ this.value = this._normalizeValue(value ?? this.min());
3552
3052
  this.ref.markForCheck();
3553
3053
  }
3554
3054
  _normalizeValue(v) {
3555
3055
  if (!Number.isFinite(v))
3556
- v = this.min;
3557
- const clamped = clamp(v, this.min, this.max);
3558
- const stepped = Math.round((clamped - this.min) / this.step) * this.step + this.min;
3559
- const precision = Math.max(0, this._decimalPlaces(this.step));
3056
+ v = this.min();
3057
+ const clamped = Math.min(this.max(), Math.max(this.min(), v));
3058
+ const stepped = Math.round((clamped - this.min()) / this.step()) * this.step() + this.min();
3059
+ const precision = Math.max(0, this._decimalPlaces(this.step()));
3560
3060
  return parseFloat(stepped.toFixed(precision));
3561
3061
  }
3562
3062
  _decimalPlaces(n) {
@@ -3595,12 +3095,12 @@ class SliderComponent extends FxComponent {
3595
3095
  this._applyValue(newVal);
3596
3096
  }
3597
3097
  _coordToValue(clientX, clientY) {
3598
- const rect = this.trackRef.nativeElement.getBoundingClientRect();
3599
- let ratio = this.vertical
3098
+ const rect = this.trackRef().nativeElement.getBoundingClientRect();
3099
+ let ratio = this.vertical()
3600
3100
  ? 1 - (clientY - rect.top) / rect.height
3601
3101
  : (clientX - rect.left) / rect.width;
3602
- ratio = clamp(ratio, 0, 1);
3603
- const raw = this.min + ratio * (this.max - this.min);
3102
+ ratio = Math.min(1, Math.max(0, ratio));
3103
+ const raw = this.min() + ratio * (this.max() - this.min());
3604
3104
  return this._normalizeValue(raw);
3605
3105
  }
3606
3106
  onTrackClick(event) {
@@ -3614,20 +3114,20 @@ class SliderComponent extends FxComponent {
3614
3114
  if (this.disabled)
3615
3115
  return;
3616
3116
  const key = ev.key;
3617
- const largeStep = (this.max - this.min) / 10;
3117
+ const largeStep = (this.max() - this.min()) / 10;
3618
3118
  let delta = 0;
3619
3119
  if (key === 'ArrowLeft' || key === 'ArrowDown')
3620
- delta = -this.step;
3120
+ delta = -this.step();
3621
3121
  else if (key === 'ArrowRight' || key === 'ArrowUp')
3622
- delta = this.step;
3122
+ delta = this.step();
3623
3123
  else if (key === 'PageDown')
3624
3124
  delta = -largeStep;
3625
3125
  else if (key === 'PageUp')
3626
3126
  delta = largeStep;
3627
3127
  else if (key === 'Home')
3628
- return this._applyValue(this.min);
3128
+ return this._applyValue(this.min());
3629
3129
  else if (key === 'End')
3630
- return this._applyValue(this.max);
3130
+ return this._applyValue(this.max());
3631
3131
  if (delta !== 0) {
3632
3132
  this._applyValue(this.value + delta);
3633
3133
  ev.preventDefault();
@@ -3643,54 +3143,39 @@ class SliderComponent extends FxComponent {
3643
3143
  }
3644
3144
  }
3645
3145
  get percent() {
3646
- if (this.max === this.min)
3146
+ const min = this.min();
3147
+ const max = this.max();
3148
+ if (max === min)
3647
3149
  return 0;
3648
- return ((this.value - this.min) / (this.max - this.min)) * 100;
3150
+ return ((this.value - min) / (max - min)) * 100;
3649
3151
  }
3650
3152
  thumbStyle() {
3651
- return this.vertical
3153
+ return this.vertical()
3652
3154
  ? { bottom: `${this.percent}%`, transform: 'translateY(50%)' }
3653
3155
  : { left: `${this.percent}%`, transform: 'translateX(-50%)' };
3654
3156
  }
3655
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SliderComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3656
- 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 <!-- Track click is a pointer shortcut; the thumb button below owns keyboard/focus. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\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 aria-label=\"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"] }] });
3157
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SliderComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3158
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SliderComponent, isStandalone: true, selector: "fx-ui-slider", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, vertical: { classPropertyName: "vertical", publicName: "vertical", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, host: { listeners: { "keydown": "onKeydown($event)" } }, viewQueries: [{ propertyName: "trackRef", first: true, predicate: ["track"], descendants: true, isSignal: true }, { propertyName: "thumbRef", first: true, predicate: ["thumb"], descendants: true, isSignal: 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 <!-- Track click is a pointer shortcut; the thumb button below owns keyboard/focus. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\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 @if (!vertical()) {\n <div\n class=\"absolute left-0 top-0 h-full rounded-full bg-primary\"\n [style.width.%]=\"percent\"\n ></div>\n }\n\n @if (vertical()) {\n <div\n class=\"absolute bottom-0 left-0 w-full rounded-full bg-primary\"\n [style.height.%]=\"percent\"\n style=\"transform-origin: bottom;\"\n ></div>\n }\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 aria-label=\"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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3657
3159
  }
3658
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SliderComponent, decorators: [{
3160
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SliderComponent, decorators: [{
3659
3161
  type: Component,
3660
- 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 <!-- Track click is a pointer shortcut; the thumb button below owns keyboard/focus. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\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 aria-label=\"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" }]
3661
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { trackRef: [{
3662
- type: ViewChild,
3663
- args: ['track', { static: true }]
3664
- }], thumbRef: [{
3665
- type: ViewChild,
3666
- args: ['thumb', { static: true }]
3667
- }], min: [{
3668
- type: Input
3669
- }], max: [{
3670
- type: Input
3671
- }], step: [{
3672
- type: Input
3673
- }], vertical: [{
3674
- type: Input
3675
- }], valueChange: [{
3676
- type: Output
3677
- }], onKeydown: [{
3162
+ args: [{ selector: 'fx-ui-slider', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
3163
+ NgClass,
3164
+ NgStyle,
3165
+ InputComponent,
3166
+ ], template: "<div\n class=\"w-full select-none\"\n [class.cursor-not-allowed]=\"disabled\"\n [class.opacity-60]=\"disabled\"\n role=\"group\"\n >\n <!-- Track click is a pointer shortcut; the thumb button below owns keyboard/focus. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\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 @if (!vertical()) {\n <div\n class=\"absolute left-0 top-0 h-full rounded-full bg-primary\"\n [style.width.%]=\"percent\"\n ></div>\n }\n\n @if (vertical()) {\n <div\n class=\"absolute bottom-0 left-0 w-full rounded-full bg-primary\"\n [style.height.%]=\"percent\"\n style=\"transform-origin: bottom;\"\n ></div>\n }\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 aria-label=\"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" }]
3167
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { trackRef: [{ type: i0.ViewChild, args: ['track', { isSignal: true }] }], thumbRef: [{ type: i0.ViewChild, args: ['thumb', { isSignal: true }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], vertical: [{ type: i0.Input, args: [{ isSignal: true, alias: "vertical", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], onKeydown: [{
3678
3168
  type: HostListener,
3679
3169
  args: ['keydown', ['$event']]
3680
3170
  }] } });
3681
3171
 
3682
3172
  class SwitchComponent extends FxComponent {
3683
- cdr;
3684
- onSwitch = new EventEmitter();
3173
+ onSwitch = output();
3685
3174
  /** Accessible name — the switch renders no visible text of its own. */
3686
- ariaLabel = '';
3175
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
3687
3176
  ngAfterViewInit() {
3688
3177
  this.cdr.detectChanges();
3689
3178
  }
3690
- constructor(cdr) {
3691
- super();
3692
- this.cdr = cdr;
3693
- }
3694
3179
  writeValue(value) {
3695
3180
  this.value = value ?? false;
3696
3181
  }
@@ -3702,43 +3187,35 @@ class SwitchComponent extends FxComponent {
3702
3187
  this.onChange(this.value);
3703
3188
  this.onTouched();
3704
3189
  }
3705
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SwitchComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3706
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SwitchComponent, isStandalone: false, selector: "fx-ui-switch", inputs: { ariaLabel: "ariaLabel" }, outputs: { onSwitch: "onSwitch" }, usesInheritance: true, ngImport: i0, template: "<button\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"!!value\"\n [attr.aria-label]=\"ariaLabel || null\"\n [disabled]=\"disabled\"\n class=\"relative flex items-center w-10 h-5 rounded-full transition-colors duration-300 cursor-pointer disabled:cursor-not-allowed focus-visible:ring-2 focus-visible:ring-primary/50\"\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\" aria-hidden=\"true\">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\" aria-hidden=\"true\">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</button>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
3190
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SwitchComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
3191
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SwitchComponent, isStandalone: true, selector: "fx-ui-switch", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSwitch: "onSwitch" }, usesInheritance: true, ngImport: i0, template: "<button\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"!!value\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [disabled]=\"disabled\"\n class=\"relative flex items-center w-10 h-5 rounded-full transition-colors duration-300 cursor-pointer disabled:cursor-not-allowed focus-visible:ring-2 focus-visible:ring-primary/50\"\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\" aria-hidden=\"true\">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\" aria-hidden=\"true\">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</button>\n", styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3707
3192
  }
3708
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SwitchComponent, decorators: [{
3193
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SwitchComponent, decorators: [{
3709
3194
  type: Component,
3710
- args: [{ selector: 'fx-ui-switch', standalone: false, template: "<button\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"!!value\"\n [attr.aria-label]=\"ariaLabel || null\"\n [disabled]=\"disabled\"\n class=\"relative flex items-center w-10 h-5 rounded-full transition-colors duration-300 cursor-pointer disabled:cursor-not-allowed focus-visible:ring-2 focus-visible:ring-primary/50\"\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\" aria-hidden=\"true\">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\" aria-hidden=\"true\">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</button>\n" }]
3711
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { onSwitch: [{
3712
- type: Output
3713
- }], ariaLabel: [{
3714
- type: Input
3715
- }] } });
3195
+ args: [{ selector: 'fx-ui-switch', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass], template: "<button\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"!!value\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [disabled]=\"disabled\"\n class=\"relative flex items-center w-10 h-5 rounded-full transition-colors duration-300 cursor-pointer disabled:cursor-not-allowed focus-visible:ring-2 focus-visible:ring-primary/50\"\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\" aria-hidden=\"true\">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\" aria-hidden=\"true\">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</button>\n" }]
3196
+ }], propDecorators: { onSwitch: [{ type: i0.Output, args: ["onSwitch"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
3716
3197
 
3717
3198
  class TabComponent {
3718
- label;
3199
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
3719
3200
  icon;
3720
- content;
3721
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3722
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: TabComponent, isStandalone: false, selector: "fx-ui-tab", inputs: { label: "label", icon: "icon" }, viewQueries: [{ propertyName: "content", first: true, predicate: TemplateRef, descendants: true, static: true }], ngImport: i0, template: "<ng-template><ng-content></ng-content></ng-template>\n" });
3201
+ content = viewChild.required(TemplateRef);
3202
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3203
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.20", type: TabComponent, isStandalone: true, selector: "fx-ui-tab", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: false, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "content", first: true, predicate: TemplateRef, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template><ng-content></ng-content></ng-template>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
3723
3204
  }
3724
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabComponent, decorators: [{
3205
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TabComponent, decorators: [{
3725
3206
  type: Component,
3726
- args: [{ selector: 'fx-ui-tab', standalone: false, template: "<ng-template><ng-content></ng-content></ng-template>\n" }]
3727
- }], propDecorators: { label: [{
3207
+ args: [{ selector: 'fx-ui-tab', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template><ng-content></ng-content></ng-template>\n" }]
3208
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], icon: [{
3728
3209
  type: Input
3729
- }], icon: [{
3730
- type: Input
3731
- }], content: [{
3732
- type: ViewChild,
3733
- args: [TemplateRef, { static: true }]
3734
- }] } });
3210
+ }], content: [{ type: i0.ViewChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }] } });
3735
3211
 
3736
3212
  class TabGroupComponent {
3737
3213
  renderer;
3738
- tabs;
3214
+ cdr = inject(ChangeDetectorRef);
3215
+ tabs = contentChildren(TabComponent, ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
3739
3216
  activeIndex = 0;
3740
- tabListRef;
3741
- underlineRef;
3217
+ tabListRef = viewChild.required('tabList');
3218
+ underlineRef = viewChild.required('underline');
3742
3219
  canScrollLeft = false;
3743
3220
  canScrollRight = false;
3744
3221
  animateDelay = 50;
@@ -3752,6 +3229,7 @@ class TabGroupComponent {
3752
3229
  this.updateScrollButtons();
3753
3230
  this.updateUnderlinePosition();
3754
3231
  this.scrollToActiveTab(false);
3232
+ this.cdr.markForCheck();
3755
3233
  }, 0);
3756
3234
  }
3757
3235
  selectTab(index) {
@@ -3760,7 +3238,7 @@ class TabGroupComponent {
3760
3238
  }
3761
3239
  /** Roving tablist keyboard nav: arrows move AND activate (selection follows focus). */
3762
3240
  onTabKeydown(event, index) {
3763
- const count = this.tabs.length;
3241
+ const count = this.tabs().length;
3764
3242
  if (!count)
3765
3243
  return;
3766
3244
  let next;
@@ -3782,12 +3260,12 @@ class TabGroupComponent {
3782
3260
  }
3783
3261
  event.preventDefault();
3784
3262
  this.selectTab(next);
3785
- const buttons = this.tabListRef.nativeElement.querySelectorAll('.tab-btn');
3263
+ const buttons = this.tabListRef().nativeElement.querySelectorAll('.tab-btn');
3786
3264
  buttons[next]?.focus();
3787
3265
  }
3788
3266
  updateUnderlinePosition() {
3789
- const tabListEl = this.tabListRef.nativeElement;
3790
- const underlineEl = this.underlineRef.nativeElement;
3267
+ const tabListEl = this.tabListRef().nativeElement;
3268
+ const underlineEl = this.underlineRef().nativeElement;
3791
3269
  const tabButtons = tabListEl.querySelectorAll('.tab-btn');
3792
3270
  const activeTab = tabButtons[this.activeIndex];
3793
3271
  if (!activeTab || !underlineEl)
@@ -3800,7 +3278,7 @@ class TabGroupComponent {
3800
3278
  this.renderer.setStyle(underlineEl, 'transform', `translateX(${translateX}px)`);
3801
3279
  }
3802
3280
  scrollToActiveTab(updateUnderlineAfter = true) {
3803
- const tabListEl = this.tabListRef.nativeElement;
3281
+ const tabListEl = this.tabListRef().nativeElement;
3804
3282
  const tabButtons = tabListEl.querySelectorAll('.tab-btn');
3805
3283
  const activeTab = tabButtons[this.activeIndex];
3806
3284
  if (!activeTab)
@@ -3819,15 +3297,17 @@ class TabGroupComponent {
3819
3297
  setTimeout(() => {
3820
3298
  this.updateScrollButtons();
3821
3299
  this.updateUnderlinePosition();
3300
+ this.cdr.markForCheck();
3822
3301
  }, updateUnderlineAfter ? this.animateDelay : 0);
3823
3302
  }
3824
3303
  scroll(direction) {
3825
- const tabListEl = this.tabListRef.nativeElement;
3304
+ const tabListEl = this.tabListRef().nativeElement;
3826
3305
  const delta = direction === 'left' ? -this.scrollAmount : this.scrollAmount;
3827
3306
  tabListEl.scrollBy({ left: delta, behavior: 'smooth' });
3828
3307
  setTimeout(() => {
3829
3308
  this.updateScrollButtons();
3830
3309
  this.updateUnderlinePosition();
3310
+ this.cdr.markForCheck();
3831
3311
  }, this.animateDelay);
3832
3312
  }
3833
3313
  onScroll() {
@@ -3835,7 +3315,7 @@ class TabGroupComponent {
3835
3315
  this.updateUnderlinePosition();
3836
3316
  }
3837
3317
  updateScrollButtons() {
3838
- const el = this.tabListRef.nativeElement;
3318
+ const el = this.tabListRef().nativeElement;
3839
3319
  const scrollLeft = el.scrollLeft;
3840
3320
  const maxScrollLeft = el.scrollWidth - el.clientWidth;
3841
3321
  this.canScrollLeft = scrollLeft > 2;
@@ -3844,80 +3324,66 @@ class TabGroupComponent {
3844
3324
  onResize() {
3845
3325
  this.updateUnderlinePosition();
3846
3326
  }
3847
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabGroupComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
3848
- 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 aria-label=\"Scroll tabs left\"\n (click)=\"scroll('left')\"\n [style.opacity]=\"canScrollLeft ? 1 : 0\"\n [style.pointerEvents]=\"canScrollLeft ? 'auto' : 'none'\"\n [attr.tabindex]=\"canScrollLeft ? null : -1\"\n [attr.aria-hidden]=\"!canScrollLeft\"\n >\n <svg\n aria-hidden=\"true\"\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 role=\"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 type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"i === activeIndex\"\n [tabindex]=\"i === activeIndex ? 0 : -1\"\n (click)=\"selectTab(i)\"\n (keydown)=\"onTabKeydown($event, 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 aria-label=\"Scroll tabs right\"\n (click)=\"scroll('right')\"\n [style.opacity]=\"canScrollRight ? 1 : 0\"\n [style.pointerEvents]=\"canScrollRight ? 'auto' : 'none'\"\n [attr.tabindex]=\"canScrollRight ? null : -1\"\n [attr.aria-hidden]=\"!canScrollRight\"\n >\n <svg\n aria-hidden=\"true\"\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\" role=\"tabpanel\" class=\"animate-fadeIn\">\n <ng-container *ngTemplateOutlet=\"tab.content\"></ng-container>\n </div>\n </ng-container>\n</div>\n", styles: ["@charset \"UTF-8\";@layer properties;@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;top:0;left:0;z-index:10;display:flex;height:100%;align-items:center;background-color:rgb(var(--bg-primary));padding-inline:.5rem;transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}.right-scroll-button{position:absolute;top:0;right:0;z-index:10;display:flex;height:100%;align-items:center;background-color:rgb(var(--bg-primary));padding-inline:.5rem;transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}.tab-bar-btn{position:relative;padding-inline:1rem;padding-block:.5rem;font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));white-space:nowrap;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}@property --tw-duration{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-duration: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\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"] }] });
3327
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TabGroupComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
3328
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: TabGroupComponent, isStandalone: true, selector: "fx-ui-tab-group", inputs: { activeIndex: "activeIndex" }, host: { listeners: { "window:resize": "onResize()" } }, queries: [{ propertyName: "tabs", predicate: TabComponent, isSignal: true }], viewQueries: [{ propertyName: "tabListRef", first: true, predicate: ["tabList"], descendants: true, isSignal: true }, { propertyName: "underlineRef", first: true, predicate: ["underline"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"relative\">\n <!-- Left scroll button -->\n <button\n class=\"left-scroll-button\"\n type=\"button\"\n aria-label=\"Scroll tabs left\"\n (click)=\"scroll('left')\"\n [style.opacity]=\"canScrollLeft ? 1 : 0\"\n [style.pointerEvents]=\"canScrollLeft ? 'auto' : 'none'\"\n [attr.tabindex]=\"canScrollLeft ? null : -1\"\n [attr.aria-hidden]=\"!canScrollLeft\"\n >\n <svg\n aria-hidden=\"true\"\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 role=\"tablist\"\n class=\"relative flex overflow-x-auto no-scrollbar scroll-smooth\"\n (scroll)=\"onScroll()\"\n >\n @for (tab of tabs(); track tab; let i = $index) {\n <button\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"i === activeIndex\"\n [tabindex]=\"i === activeIndex ? 0 : -1\"\n (click)=\"selectTab(i)\"\n (keydown)=\"onTabKeydown($event, 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\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 aria-label=\"Scroll tabs right\"\n (click)=\"scroll('right')\"\n [style.opacity]=\"canScrollRight ? 1 : 0\"\n [style.pointerEvents]=\"canScrollRight ? 'auto' : 'none'\"\n [attr.tabindex]=\"canScrollRight ? null : -1\"\n [attr.aria-hidden]=\"!canScrollRight\"\n >\n <svg\n aria-hidden=\"true\"\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 @for (tab of tabs(); track tab; let i = $index) {\n @if (i === activeIndex) {\n <div role=\"tabpanel\" class=\"animate-fadeIn\">\n <ng-container *ngTemplateOutlet=\"tab.content()\"></ng-container>\n </div>\n }\n }\n</div>\n", styles: ["@charset \"UTF-8\";@layer properties;@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;top:0;left:0;z-index:10;display:flex;height:100%;align-items:center;background-color:rgb(var(--bg-primary));padding-inline:.5rem;transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}.right-scroll-button{position:absolute;top:0;right:0;z-index:10;display:flex;height:100%;align-items:center;background-color:rgb(var(--bg-primary));padding-inline:.5rem;transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}.tab-bar-btn{position:relative;padding-inline:1rem;padding-block:.5rem;font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));white-space:nowrap;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}@property --tw-duration{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-duration: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3849
3329
  }
3850
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TabGroupComponent, decorators: [{
3330
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TabGroupComponent, decorators: [{
3851
3331
  type: Component,
3852
- args: [{ selector: 'fx-ui-tab-group', standalone: false, template: "<div class=\"relative\">\n <!-- Left scroll button -->\n <button\n class=\"left-scroll-button\"\n type=\"button\"\n aria-label=\"Scroll tabs left\"\n (click)=\"scroll('left')\"\n [style.opacity]=\"canScrollLeft ? 1 : 0\"\n [style.pointerEvents]=\"canScrollLeft ? 'auto' : 'none'\"\n [attr.tabindex]=\"canScrollLeft ? null : -1\"\n [attr.aria-hidden]=\"!canScrollLeft\"\n >\n <svg\n aria-hidden=\"true\"\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 role=\"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 type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"i === activeIndex\"\n [tabindex]=\"i === activeIndex ? 0 : -1\"\n (click)=\"selectTab(i)\"\n (keydown)=\"onTabKeydown($event, 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 aria-label=\"Scroll tabs right\"\n (click)=\"scroll('right')\"\n [style.opacity]=\"canScrollRight ? 1 : 0\"\n [style.pointerEvents]=\"canScrollRight ? 'auto' : 'none'\"\n [attr.tabindex]=\"canScrollRight ? null : -1\"\n [attr.aria-hidden]=\"!canScrollRight\"\n >\n <svg\n aria-hidden=\"true\"\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\" role=\"tabpanel\" class=\"animate-fadeIn\">\n <ng-container *ngTemplateOutlet=\"tab.content\"></ng-container>\n </div>\n </ng-container>\n</div>\n", styles: ["@charset \"UTF-8\";@layer properties;@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;top:0;left:0;z-index:10;display:flex;height:100%;align-items:center;background-color:rgb(var(--bg-primary));padding-inline:.5rem;transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}.right-scroll-button{position:absolute;top:0;right:0;z-index:10;display:flex;height:100%;align-items:center;background-color:rgb(var(--bg-primary));padding-inline:.5rem;transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}.tab-bar-btn{position:relative;padding-inline:1rem;padding-block:.5rem;font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));white-space:nowrap;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}@property --tw-duration{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-duration: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
3853
- }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { tabs: [{
3854
- type: ContentChildren,
3855
- args: [TabComponent]
3856
- }], activeIndex: [{
3857
- type: Input
3858
- }], tabListRef: [{
3859
- type: ViewChild,
3860
- args: ['tabList', { static: true }]
3861
- }], underlineRef: [{
3862
- type: ViewChild,
3863
- args: ['underline', { static: true }]
3864
- }], onResize: [{
3332
+ args: [{ selector: 'fx-ui-tab-group', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
3333
+ HeroIconComponent,
3334
+ NgClass,
3335
+ NgTemplateOutlet,
3336
+ InputComponent,
3337
+ ], template: "<div class=\"relative\">\n <!-- Left scroll button -->\n <button\n class=\"left-scroll-button\"\n type=\"button\"\n aria-label=\"Scroll tabs left\"\n (click)=\"scroll('left')\"\n [style.opacity]=\"canScrollLeft ? 1 : 0\"\n [style.pointerEvents]=\"canScrollLeft ? 'auto' : 'none'\"\n [attr.tabindex]=\"canScrollLeft ? null : -1\"\n [attr.aria-hidden]=\"!canScrollLeft\"\n >\n <svg\n aria-hidden=\"true\"\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 role=\"tablist\"\n class=\"relative flex overflow-x-auto no-scrollbar scroll-smooth\"\n (scroll)=\"onScroll()\"\n >\n @for (tab of tabs(); track tab; let i = $index) {\n <button\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"i === activeIndex\"\n [tabindex]=\"i === activeIndex ? 0 : -1\"\n (click)=\"selectTab(i)\"\n (keydown)=\"onTabKeydown($event, 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\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 aria-label=\"Scroll tabs right\"\n (click)=\"scroll('right')\"\n [style.opacity]=\"canScrollRight ? 1 : 0\"\n [style.pointerEvents]=\"canScrollRight ? 'auto' : 'none'\"\n [attr.tabindex]=\"canScrollRight ? null : -1\"\n [attr.aria-hidden]=\"!canScrollRight\"\n >\n <svg\n aria-hidden=\"true\"\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 @for (tab of tabs(); track tab; let i = $index) {\n @if (i === activeIndex) {\n <div role=\"tabpanel\" class=\"animate-fadeIn\">\n <ng-container *ngTemplateOutlet=\"tab.content()\"></ng-container>\n </div>\n }\n }\n</div>\n", styles: ["@charset \"UTF-8\";@layer properties;@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;top:0;left:0;z-index:10;display:flex;height:100%;align-items:center;background-color:rgb(var(--bg-primary));padding-inline:.5rem;transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}.right-scroll-button{position:absolute;top:0;right:0;z-index:10;display:flex;height:100%;align-items:center;background-color:rgb(var(--bg-primary));padding-inline:.5rem;transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}.tab-bar-btn{position:relative;padding-inline:1rem;padding-block:.5rem;font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));white-space:nowrap;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s}@property --tw-duration{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-duration: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
3338
+ }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { tabs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TabComponent), { isSignal: true }] }], activeIndex: [{
3339
+ type: Input
3340
+ }], tabListRef: [{ type: i0.ViewChild, args: ['tabList', { isSignal: true }] }], underlineRef: [{ type: i0.ViewChild, args: ['underline', { isSignal: true }] }], onResize: [{
3865
3341
  type: HostListener,
3866
3342
  args: ['window:resize']
3867
3343
  }] } });
3868
3344
 
3869
3345
  class TableCell {
3870
- loading;
3871
- skeletonClass = 'h-4 w-full';
3872
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TableCell, deps: [], target: i0.ɵɵFactoryTarget.Component });
3873
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: TableCell, isStandalone: false, selector: "fx-ui-table-cell", inputs: { loading: "loading", skeletonClass: "skeletonClass" }, ngImport: i0, template: "@if (!loading) {\n <div animate.enter=\"fade-in-animation\" class=\"inline-block my-normal\">\n <ng-content />\n </div>\n} @else {\n <div animate.enter=\"fade-in-animation\" class=\"skeleton-load my-semi\" [class]=\"skeletonClass\"></div>\n}\n", styles: [""] });
3346
+ loading = input.required(...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
3347
+ skeletonClass = input('h-4 w-full', ...(ngDevMode ? [{ debugName: "skeletonClass" }] : /* istanbul ignore next */ []));
3348
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TableCell, deps: [], target: i0.ɵɵFactoryTarget.Component });
3349
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: TableCell, isStandalone: true, selector: "fx-ui-table-cell", inputs: { loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: true, transformFunction: null }, skeletonClass: { classPropertyName: "skeletonClass", publicName: "skeletonClass", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!loading()) {\n <div animate.enter=\"fade-in-animation\" class=\"inline-block my-normal\">\n <ng-content />\n </div>\n} @else {\n <div animate.enter=\"fade-in-animation\" class=\"skeleton-load my-semi\" [class]=\"skeletonClass()\"></div>\n}\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3874
3350
  }
3875
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TableCell, decorators: [{
3351
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TableCell, decorators: [{
3876
3352
  type: Component,
3877
- args: [{ selector: 'fx-ui-table-cell', standalone: false, template: "@if (!loading) {\n <div animate.enter=\"fade-in-animation\" class=\"inline-block my-normal\">\n <ng-content />\n </div>\n} @else {\n <div animate.enter=\"fade-in-animation\" class=\"skeleton-load my-semi\" [class]=\"skeletonClass\"></div>\n}\n" }]
3878
- }], propDecorators: { loading: [{
3879
- type: Input,
3880
- args: [{ required: true }]
3881
- }], skeletonClass: [{
3882
- type: Input
3883
- }] } });
3353
+ args: [{ selector: 'fx-ui-table-cell', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!loading()) {\n <div animate.enter=\"fade-in-animation\" class=\"inline-block my-normal\">\n <ng-content />\n </div>\n} @else {\n <div animate.enter=\"fade-in-animation\" class=\"skeleton-load my-semi\" [class]=\"skeletonClass()\"></div>\n}\n" }]
3354
+ }], propDecorators: { loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: true }] }], skeletonClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "skeletonClass", required: false }] }] } });
3884
3355
 
3885
3356
  class TagComponent {
3886
- label;
3887
- type = 'default';
3888
- rounded = true;
3357
+ label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
3358
+ type = input('default', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
3359
+ rounded = input(true, ...(ngDevMode ? [{ debugName: "rounded" }] : /* istanbul ignore next */ []));
3889
3360
  icon;
3890
- solid = false;
3361
+ solid = input(false, ...(ngDevMode ? [{ debugName: "solid" }] : /* istanbul ignore next */ []));
3362
+ /* EventEmitter (not output()) on purpose: the template branches on
3363
+ * `clicked.observed` to only expose button semantics when someone listens —
3364
+ * OutputEmitterRef has no equivalent. */
3891
3365
  clicked = new EventEmitter();
3892
3366
  onClick() {
3893
3367
  this.clicked.emit();
3894
3368
  }
3895
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3896
- 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: "<!-- Interactive semantics only when a (clicked) listener is attached. -->\n<div\n (click)=\"onClick()\"\n (keydown.enter)=\"onClick()\"\n (keydown.space)=\"$event.preventDefault(); onClick()\"\n [attr.role]=\"clicked.observed ? 'button' : null\"\n [attr.tabindex]=\"clicked.observed ? 0 : null\"\n [class]=\"\n `flex flex-row gap-small ${rounded ? 'tag-round' : 'tag-square'} tag-${type}${solid ? '-solid' : ''}${clicked.observed ? ' cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50' : ''}`\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"] }] });
3369
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3370
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: TagComponent, isStandalone: true, selector: "fx-ui-tag", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: false, isRequired: false, transformFunction: null }, solid: { classPropertyName: "solid", publicName: "solid", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<!-- Interactive semantics only when a (clicked) listener is attached. -->\n<div\n (click)=\"onClick()\"\n (keydown.enter)=\"onClick()\"\n (keydown.space)=\"$event.preventDefault(); onClick()\"\n [attr.role]=\"clicked.observed ? 'button' : null\"\n [attr.tabindex]=\"clicked.observed ? 0 : null\"\n [class]=\"\n `flex flex-row gap-small ${rounded() ? 'tag-round' : 'tag-square'} tag-${type()}${solid() ? '-solid' : ''}${clicked.observed ? ' cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50' : ''}`\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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3897
3371
  }
3898
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TagComponent, decorators: [{
3372
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TagComponent, decorators: [{
3899
3373
  type: Component,
3900
- args: [{ selector: 'fx-ui-tag', standalone: false, template: "<!-- Interactive semantics only when a (clicked) listener is attached. -->\n<div\n (click)=\"onClick()\"\n (keydown.enter)=\"onClick()\"\n (keydown.space)=\"$event.preventDefault(); onClick()\"\n [attr.role]=\"clicked.observed ? 'button' : null\"\n [attr.tabindex]=\"clicked.observed ? 0 : null\"\n [class]=\"\n `flex flex-row gap-small ${rounded ? 'tag-round' : 'tag-square'} tag-${type}${solid ? '-solid' : ''}${clicked.observed ? ' cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50' : ''}`\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" }]
3901
- }], propDecorators: { label: [{
3902
- type: Input
3903
- }], type: [{
3904
- type: Input
3905
- }], rounded: [{
3906
- type: Input
3907
- }], icon: [{
3908
- type: Input
3909
- }], solid: [{
3374
+ args: [{ selector: 'fx-ui-tag', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HeroIconComponent], template: "<!-- Interactive semantics only when a (clicked) listener is attached. -->\n<div\n (click)=\"onClick()\"\n (keydown.enter)=\"onClick()\"\n (keydown.space)=\"$event.preventDefault(); onClick()\"\n [attr.role]=\"clicked.observed ? 'button' : null\"\n [attr.tabindex]=\"clicked.observed ? 0 : null\"\n [class]=\"\n `flex flex-row gap-small ${rounded() ? 'tag-round' : 'tag-square'} tag-${type()}${solid() ? '-solid' : ''}${clicked.observed ? ' cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50' : ''}`\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" }]
3375
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], icon: [{
3910
3376
  type: Input
3911
- }], clicked: [{
3377
+ }], solid: [{ type: i0.Input, args: [{ isSignal: true, alias: "solid", required: false }] }], clicked: [{
3912
3378
  type: Output
3913
3379
  }] } });
3914
3380
 
3915
3381
  class TreeDiagram {
3916
3382
  zone;
3917
3383
  cdr;
3918
- data;
3919
- container;
3920
- root;
3384
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
3385
+ container = viewChild.required('container');
3386
+ root = viewChild.required('root');
3921
3387
  children;
3922
3388
  lines = [];
3923
3389
  svgWidth = 0;
@@ -3936,7 +3402,7 @@ class TreeDiagram {
3936
3402
  return;
3937
3403
  this.scheduleDraw();
3938
3404
  });
3939
- this.resizeObserver.observe(this.container.nativeElement);
3405
+ this.resizeObserver.observe(this.container().nativeElement);
3940
3406
  setTimeout(() => this.scheduleDraw(), 50);
3941
3407
  setTimeout(() => this.scheduleDraw(), 150);
3942
3408
  });
@@ -3955,13 +3421,14 @@ class TreeDiagram {
3955
3421
  });
3956
3422
  }
3957
3423
  drawLines() {
3958
- if (!this.root || !this.children.length)
3424
+ const root = this.root();
3425
+ if (!root || !this.children.length)
3959
3426
  return;
3960
- const containerEl = this.container.nativeElement;
3427
+ const containerEl = this.container().nativeElement;
3961
3428
  const rect = containerEl.getBoundingClientRect();
3962
3429
  if (rect.width === 0 || rect.height === 0)
3963
3430
  return;
3964
- const rootRect = this.root.nativeElement.getBoundingClientRect();
3431
+ const rootRect = root.nativeElement.getBoundingClientRect();
3965
3432
  const rootX = rootRect.left + rootRect.width / 2 - rect.left;
3966
3433
  const rootBottomY = rootRect.bottom - rect.top;
3967
3434
  const childRects = this.children.map(c => c.nativeElement.getBoundingClientRect());
@@ -3996,34 +3463,26 @@ class TreeDiagram {
3996
3463
  });
3997
3464
  this.cdr.detectChanges();
3998
3465
  }
3999
- 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 });
4000
- 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"] }] });
3466
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TreeDiagram, deps: [{ token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3467
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: TreeDiagram, isStandalone: true, selector: "fx-ui-tree-diagram", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "root", first: true, predicate: ["root"], descendants: true, isSignal: 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 @for (child of data().children; track child) {\n <div\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 }\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 @for (line of lines; track line) {\n <line\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 }\n </svg>\n\n</div>\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4001
3468
  }
4002
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TreeDiagram, decorators: [{
3469
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TreeDiagram, decorators: [{
4003
3470
  type: Component,
4004
- args: [{ selector: 'fx-ui-tree-diagram', standalone: false, 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" }]
4005
- }], ctorParameters: () => [{ type: i0.NgZone }, { type: i0.ChangeDetectorRef }], propDecorators: { data: [{
4006
- type: Input
4007
- }], container: [{
4008
- type: ViewChild,
4009
- args: ['container']
4010
- }], root: [{
4011
- type: ViewChild,
4012
- args: ['root']
4013
- }], children: [{
3471
+ args: [{ selector: 'fx-ui-tree-diagram', changeDetection: ChangeDetectionStrategy.OnPush, 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 @for (child of data().children; track child) {\n <div\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 }\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 @for (line of lines; track line) {\n <line\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 }\n </svg>\n\n</div>\n" }]
3472
+ }], ctorParameters: () => [{ type: i0.NgZone }, { type: i0.ChangeDetectorRef }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], container: [{ type: i0.ViewChild, args: ['container', { isSignal: true }] }], root: [{ type: i0.ViewChild, args: ['root', { isSignal: true }] }], children: [{
4014
3473
  type: ViewChildren,
4015
3474
  args: ['child']
4016
3475
  }] } });
4017
3476
 
4018
3477
  class KanbanBoardComponent {
4019
- columns = [];
3478
+ columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
4020
3479
  itemTemplate;
4021
- columnChanged = new EventEmitter();
3480
+ columnChanged = output();
4022
3481
  /**
4023
3482
  * Get all column IDs for connecting drop lists
4024
3483
  */
4025
3484
  getColumnIds() {
4026
- return this.columns.map((col) => col.id);
3485
+ return this.columns().map((col) => col.id);
4027
3486
  }
4028
3487
  /**
4029
3488
  * Handle drop event when item is moved
@@ -4049,28 +3508,30 @@ class KanbanBoardComponent {
4049
3508
  currentIndex: event.currentIndex,
4050
3509
  });
4051
3510
  }
4052
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: KanbanBoardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4053
- 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: ["@charset \"UTF-8\";@layer properties;.kanban-board{height:100%;width:100%;overflow-x:auto}.kanban-columns{display:flex;min-height:100%;gap:calc(var(--spacing, .25rem) * 4);padding:calc(var(--spacing, .25rem) * 4)}.kanban-column{display:flex;min-width:300px;flex-direction:column;border-radius:.5rem;background-color:var(--color-gray-50, oklch(98.5% .002 247.839));flex-shrink:0}@media (prefers-color-scheme: dark){.kanban-column{background-color:var(--color-gray-800, oklch(27.8% .033 256.848))}}.kanban-column-header{display:flex;align-items:center;justify-content:space-between;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-gray-200, oklch(92.8% .006 264.531));padding:calc(var(--spacing, .25rem) * 4)}@media (prefers-color-scheme: dark){.kanban-column-header{border-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}.kanban-column-title{margin:0;font-size:var(--text-lg, 1.125rem);line-height:var(--tw-leading, var(--text-lg--line-height, calc(1.75 / 1.125)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:var(--color-gray-900, oklch(21% .034 264.665))}@media (prefers-color-scheme: dark){.kanban-column-title{color:var(--color-gray-100, oklch(96.7% .003 264.542))}}.kanban-column-count{border-radius:calc(infinity * 1px);background-color:var(--color-gray-200, oklch(92.8% .006 264.531));padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:var(--spacing, .25rem);font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:var(--color-gray-700, oklch(37.3% .034 259.733))}@media (prefers-color-scheme: dark){.kanban-column-count{background-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}@media (prefers-color-scheme: dark){.kanban-column-count{color:var(--color-gray-300, oklch(87.2% .01 258.338))}}.kanban-column-content{flex:1;overflow-y:auto;padding:calc(var(--spacing, .25rem) * 4);min-height:200px}:where(.kanban-column-content>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(calc(var(--spacing, .25rem) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing, .25rem) * 3) * calc(1 - var(--tw-space-y-reverse)))}.kanban-item{border-radius:.5rem;border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-gray-200, oklch(92.8% .006 264.531));background-color:var(--color-white, #fff);--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);transition-property:box-shadow;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s;cursor:move}@media (prefers-color-scheme: dark){.kanban-item{border-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}@media (prefers-color-scheme: dark){.kanban-item{background-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}.kanban-item:hover{--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.kanban-item-default{padding:calc(var(--spacing, .25rem) * 4);color:var(--color-gray-900, oklch(21% .034 264.665))}@media (prefers-color-scheme: dark){.kanban-item-default{color:var(--color-gray-100, oklch(96.7% .003 264.542))}}.kanban-item-placeholder{border-radius:.5rem;border-style:var(--tw-border-style);border-width:2px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-gray-400, oklch(70.7% .022 261.325));background-color:var(--color-gray-200, oklch(92.8% .006 264.531));opacity:50%;min-height:60px}@media (prefers-color-scheme: dark){.kanban-item-placeholder{border-color:var(--color-gray-500, oklch(55.1% .027 264.364))}}@media (prefers-color-scheme: dark){.kanban-item-placeholder{background-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}.kanban-column-empty{display:flex;height:calc(var(--spacing, .25rem) * 32);align-items:center;justify-content:center;font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-gray-400, oklch(70.7% .022 261.325));border-radius:.5rem;border-style:var(--tw-border-style);border-width:2px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-gray-300, oklch(87.2% .01 258.338))}@media (prefers-color-scheme: dark){.kanban-column-empty{color:var(--color-gray-500, oklch(55.1% .027 264.364))}}@media (prefers-color-scheme: dark){.kanban-column-empty{border-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}.cdk-drag-preview{border-radius:.5rem;opacity:80%;--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),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)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-space-y-reverse{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-duration{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-font-weight: initial;--tw-space-y-reverse: 0;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-duration: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\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"] }] });
3511
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: KanbanBoardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3512
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: KanbanBoardComponent, isStandalone: true, selector: "fx-ui-kanban-board", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: false, isRequired: false, transformFunction: null } }, 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: ["@charset \"UTF-8\";@layer properties;.kanban-board{height:100%;width:100%;overflow-x:auto}.kanban-columns{display:flex;min-height:100%;gap:calc(var(--spacing, .25rem) * 4);padding:calc(var(--spacing, .25rem) * 4)}.kanban-column{display:flex;min-width:300px;flex-direction:column;border-radius:.5rem;background-color:var(--color-gray-50, oklch(98.5% .002 247.839));flex-shrink:0}@media(prefers-color-scheme:dark){.kanban-column{background-color:var(--color-gray-800, oklch(27.8% .033 256.848))}}.kanban-column-header{display:flex;align-items:center;justify-content:space-between;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-gray-200, oklch(92.8% .006 264.531));padding:calc(var(--spacing, .25rem) * 4)}@media(prefers-color-scheme:dark){.kanban-column-header{border-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}.kanban-column-title{margin:0;font-size:var(--text-lg, 1.125rem);line-height:var(--tw-leading, var(--text-lg--line-height, calc(1.75 / 1.125)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:var(--color-gray-900, oklch(21% .034 264.665))}@media(prefers-color-scheme:dark){.kanban-column-title{color:var(--color-gray-100, oklch(96.7% .003 264.542))}}.kanban-column-count{border-radius:calc(infinity * 1px);background-color:var(--color-gray-200, oklch(92.8% .006 264.531));padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:var(--spacing, .25rem);font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:var(--color-gray-700, oklch(37.3% .034 259.733))}@media(prefers-color-scheme:dark){.kanban-column-count{background-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}@media(prefers-color-scheme:dark){.kanban-column-count{color:var(--color-gray-300, oklch(87.2% .01 258.338))}}.kanban-column-content{flex:1;overflow-y:auto;padding:calc(var(--spacing, .25rem) * 4);min-height:200px}:where(.kanban-column-content>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(calc(var(--spacing, .25rem) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing, .25rem) * 3) * calc(1 - var(--tw-space-y-reverse)))}.kanban-item{border-radius:.5rem;border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-gray-200, oklch(92.8% .006 264.531));background-color:var(--color-white, #fff);--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);transition-property:box-shadow;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s;cursor:move}@media(prefers-color-scheme:dark){.kanban-item{border-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}@media(prefers-color-scheme:dark){.kanban-item{background-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}.kanban-item:hover{--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.kanban-item-default{padding:calc(var(--spacing, .25rem) * 4);color:var(--color-gray-900, oklch(21% .034 264.665))}@media(prefers-color-scheme:dark){.kanban-item-default{color:var(--color-gray-100, oklch(96.7% .003 264.542))}}.kanban-item-placeholder{border-radius:.5rem;border-style:var(--tw-border-style);border-width:2px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-gray-400, oklch(70.7% .022 261.325));background-color:var(--color-gray-200, oklch(92.8% .006 264.531));opacity:50%;min-height:60px}@media(prefers-color-scheme:dark){.kanban-item-placeholder{border-color:var(--color-gray-500, oklch(55.1% .027 264.364))}}@media(prefers-color-scheme:dark){.kanban-item-placeholder{background-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}.kanban-column-empty{display:flex;height:calc(var(--spacing, .25rem) * 32);align-items:center;justify-content:center;font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-gray-400, oklch(70.7% .022 261.325));border-radius:.5rem;border-style:var(--tw-border-style);border-width:2px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-gray-300, oklch(87.2% .01 258.338))}@media(prefers-color-scheme:dark){.kanban-column-empty{color:var(--color-gray-500, oklch(55.1% .027 264.364))}}@media(prefers-color-scheme:dark){.kanban-column-empty{border-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}.cdk-drag-preview{border-radius:.5rem;opacity:80%;--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),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)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-space-y-reverse{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-duration{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-font-weight: initial;--tw-space-y-reverse: 0;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-duration: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "directive", type: 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: 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: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4054
3513
  }
4055
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: KanbanBoardComponent, decorators: [{
3514
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: KanbanBoardComponent, decorators: [{
4056
3515
  type: Component,
4057
- 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: ["@charset \"UTF-8\";@layer properties;.kanban-board{height:100%;width:100%;overflow-x:auto}.kanban-columns{display:flex;min-height:100%;gap:calc(var(--spacing, .25rem) * 4);padding:calc(var(--spacing, .25rem) * 4)}.kanban-column{display:flex;min-width:300px;flex-direction:column;border-radius:.5rem;background-color:var(--color-gray-50, oklch(98.5% .002 247.839));flex-shrink:0}@media (prefers-color-scheme: dark){.kanban-column{background-color:var(--color-gray-800, oklch(27.8% .033 256.848))}}.kanban-column-header{display:flex;align-items:center;justify-content:space-between;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-gray-200, oklch(92.8% .006 264.531));padding:calc(var(--spacing, .25rem) * 4)}@media (prefers-color-scheme: dark){.kanban-column-header{border-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}.kanban-column-title{margin:0;font-size:var(--text-lg, 1.125rem);line-height:var(--tw-leading, var(--text-lg--line-height, calc(1.75 / 1.125)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:var(--color-gray-900, oklch(21% .034 264.665))}@media (prefers-color-scheme: dark){.kanban-column-title{color:var(--color-gray-100, oklch(96.7% .003 264.542))}}.kanban-column-count{border-radius:calc(infinity * 1px);background-color:var(--color-gray-200, oklch(92.8% .006 264.531));padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:var(--spacing, .25rem);font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:var(--color-gray-700, oklch(37.3% .034 259.733))}@media (prefers-color-scheme: dark){.kanban-column-count{background-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}@media (prefers-color-scheme: dark){.kanban-column-count{color:var(--color-gray-300, oklch(87.2% .01 258.338))}}.kanban-column-content{flex:1;overflow-y:auto;padding:calc(var(--spacing, .25rem) * 4);min-height:200px}:where(.kanban-column-content>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(calc(var(--spacing, .25rem) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing, .25rem) * 3) * calc(1 - var(--tw-space-y-reverse)))}.kanban-item{border-radius:.5rem;border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-gray-200, oklch(92.8% .006 264.531));background-color:var(--color-white, #fff);--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);transition-property:box-shadow;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s;cursor:move}@media (prefers-color-scheme: dark){.kanban-item{border-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}@media (prefers-color-scheme: dark){.kanban-item{background-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}.kanban-item:hover{--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.kanban-item-default{padding:calc(var(--spacing, .25rem) * 4);color:var(--color-gray-900, oklch(21% .034 264.665))}@media (prefers-color-scheme: dark){.kanban-item-default{color:var(--color-gray-100, oklch(96.7% .003 264.542))}}.kanban-item-placeholder{border-radius:.5rem;border-style:var(--tw-border-style);border-width:2px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-gray-400, oklch(70.7% .022 261.325));background-color:var(--color-gray-200, oklch(92.8% .006 264.531));opacity:50%;min-height:60px}@media (prefers-color-scheme: dark){.kanban-item-placeholder{border-color:var(--color-gray-500, oklch(55.1% .027 264.364))}}@media (prefers-color-scheme: dark){.kanban-item-placeholder{background-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}.kanban-column-empty{display:flex;height:calc(var(--spacing, .25rem) * 32);align-items:center;justify-content:center;font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-gray-400, oklch(70.7% .022 261.325));border-radius:.5rem;border-style:var(--tw-border-style);border-width:2px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-gray-300, oklch(87.2% .01 258.338))}@media (prefers-color-scheme: dark){.kanban-column-empty{color:var(--color-gray-500, oklch(55.1% .027 264.364))}}@media (prefers-color-scheme: dark){.kanban-column-empty{border-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}.cdk-drag-preview{border-radius:.5rem;opacity:80%;--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),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)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-space-y-reverse{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-duration{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-font-weight: initial;--tw-space-y-reverse: 0;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-duration: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
4058
- }], propDecorators: { columns: [{
4059
- type: Input
4060
- }], itemTemplate: [{
4061
- type: Input
4062
- }], columnChanged: [{
4063
- type: Output
4064
- }] } });
3516
+ args: [{ selector: 'fx-ui-kanban-board', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
3517
+ CdkDropList,
3518
+ CdkDrag,
3519
+ CdkDragPlaceholder,
3520
+ NgTemplateOutlet,
3521
+ ], 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: ["@charset \"UTF-8\";@layer properties;.kanban-board{height:100%;width:100%;overflow-x:auto}.kanban-columns{display:flex;min-height:100%;gap:calc(var(--spacing, .25rem) * 4);padding:calc(var(--spacing, .25rem) * 4)}.kanban-column{display:flex;min-width:300px;flex-direction:column;border-radius:.5rem;background-color:var(--color-gray-50, oklch(98.5% .002 247.839));flex-shrink:0}@media(prefers-color-scheme:dark){.kanban-column{background-color:var(--color-gray-800, oklch(27.8% .033 256.848))}}.kanban-column-header{display:flex;align-items:center;justify-content:space-between;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-gray-200, oklch(92.8% .006 264.531));padding:calc(var(--spacing, .25rem) * 4)}@media(prefers-color-scheme:dark){.kanban-column-header{border-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}.kanban-column-title{margin:0;font-size:var(--text-lg, 1.125rem);line-height:var(--tw-leading, var(--text-lg--line-height, calc(1.75 / 1.125)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:var(--color-gray-900, oklch(21% .034 264.665))}@media(prefers-color-scheme:dark){.kanban-column-title{color:var(--color-gray-100, oklch(96.7% .003 264.542))}}.kanban-column-count{border-radius:calc(infinity * 1px);background-color:var(--color-gray-200, oklch(92.8% .006 264.531));padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:var(--spacing, .25rem);font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:var(--color-gray-700, oklch(37.3% .034 259.733))}@media(prefers-color-scheme:dark){.kanban-column-count{background-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}@media(prefers-color-scheme:dark){.kanban-column-count{color:var(--color-gray-300, oklch(87.2% .01 258.338))}}.kanban-column-content{flex:1;overflow-y:auto;padding:calc(var(--spacing, .25rem) * 4);min-height:200px}:where(.kanban-column-content>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(calc(var(--spacing, .25rem) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing, .25rem) * 3) * calc(1 - var(--tw-space-y-reverse)))}.kanban-item{border-radius:.5rem;border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-gray-200, oklch(92.8% .006 264.531));background-color:var(--color-white, #fff);--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);transition-property:box-shadow;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .2s;transition-duration:.2s;cursor:move}@media(prefers-color-scheme:dark){.kanban-item{border-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}@media(prefers-color-scheme:dark){.kanban-item{background-color:var(--color-gray-700, oklch(37.3% .034 259.733))}}.kanban-item:hover{--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.kanban-item-default{padding:calc(var(--spacing, .25rem) * 4);color:var(--color-gray-900, oklch(21% .034 264.665))}@media(prefers-color-scheme:dark){.kanban-item-default{color:var(--color-gray-100, oklch(96.7% .003 264.542))}}.kanban-item-placeholder{border-radius:.5rem;border-style:var(--tw-border-style);border-width:2px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-gray-400, oklch(70.7% .022 261.325));background-color:var(--color-gray-200, oklch(92.8% .006 264.531));opacity:50%;min-height:60px}@media(prefers-color-scheme:dark){.kanban-item-placeholder{border-color:var(--color-gray-500, oklch(55.1% .027 264.364))}}@media(prefers-color-scheme:dark){.kanban-item-placeholder{background-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}.kanban-column-empty{display:flex;height:calc(var(--spacing, .25rem) * 32);align-items:center;justify-content:center;font-size:.875rem;line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-gray-400, oklch(70.7% .022 261.325));border-radius:.5rem;border-style:var(--tw-border-style);border-width:2px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-gray-300, oklch(87.2% .01 258.338))}@media(prefers-color-scheme:dark){.kanban-column-empty{color:var(--color-gray-500, oklch(55.1% .027 264.364))}}@media(prefers-color-scheme:dark){.kanban-column-empty{border-color:var(--color-gray-600, oklch(44.6% .03 256.802))}}.cdk-drag-preview{border-radius:.5rem;opacity:80%;--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),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)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-space-y-reverse{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-duration{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-font-weight: initial;--tw-space-y-reverse: 0;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-duration: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
3522
+ }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], itemTemplate: [{
3523
+ type: Input
3524
+ }], columnChanged: [{ type: i0.Output, args: ["columnChanged"] }] } });
4065
3525
 
4066
3526
  class DrawerComponent {
4067
3527
  router;
4068
- items = [];
3528
+ cdr = inject(ChangeDetectorRef);
3529
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
4069
3530
  isExpanded = true;
4070
3531
  logo;
4071
3532
  version;
4072
- toggleExpanded = new EventEmitter();
4073
- itemClicked = new EventEmitter();
3533
+ toggleExpanded = output();
3534
+ itemClicked = output();
4074
3535
  expandedItems = new Set();
4075
3536
  currentRoute = '';
4076
3537
  destroy$ = new Subject();
@@ -4086,6 +3547,7 @@ class DrawerComponent {
4086
3547
  .subscribe((event) => {
4087
3548
  this.currentRoute = event.urlAfterRedirects || event.url;
4088
3549
  this.autoExpandActiveParents();
3550
+ this.cdr.markForCheck();
4089
3551
  });
4090
3552
  // Auto-expand parents of active route on init
4091
3553
  this.autoExpandActiveParents();
@@ -4157,7 +3619,7 @@ class DrawerComponent {
4157
3619
  }
4158
3620
  return false;
4159
3621
  };
4160
- expandParents(this.items);
3622
+ expandParents(this.items());
4161
3623
  }
4162
3624
  getAccordionState(itemId) {
4163
3625
  return this.isAccordionExpanded(itemId) ? 'expanded' : 'collapsed';
@@ -4165,8 +3627,8 @@ class DrawerComponent {
4165
3627
  getDrawerState() {
4166
3628
  return this.isExpanded ? 'expanded' : 'collapsed';
4167
3629
  }
4168
- 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 });
4169
- 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 alt=\"Home\"\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 [attr.aria-label]=\"isExpanded ? 'Collapse navigation' : 'Expand navigation'\"\n [attr.aria-expanded]=\"isExpanded\"\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\";@layer properties;:host{display:block;height:100%}.drawer-host-wrapper{position:relative;height:100%;border-right-style:var(--tw-border-style);border-right-width:1px;border-color:rgb(var(--border-default))}.drawer-container{display:flex;height:100%;flex-direction:column;overflow:auto;background-color:rgb(var(--bg-primary));padding-inline:calc(var(--spacing, .25rem) * 2);transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);right:-12px;transition:all .2s ease}.toggle-btn:hover{background-color:rgb(var(--bg-primary-hover));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.toggle-btn:active{transform:translateY(-50%) scale(.9)}.toggle-btn:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-nav{flex:1;overflow-x:hidden;overflow-y:auto;padding-block:calc(var(--spacing, .25rem) * 2)}.drawer-nav::-webkit-scrollbar{width:calc(var(--spacing, .25rem) * 1.5)}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:.125rem;background-color:rgb(var(--border-default))}.drawer-nav::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--text-placeholder))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;margin-top:var(--spacing, .25rem);display:flex;min-height:calc(var(--spacing, .25rem) * 8);width:100%;cursor:pointer;align-items:center;border-radius:.25rem;--tw-border-style: none;border-style:none;background-color:transparent;padding-inline:1rem;padding-block:calc(var(--spacing, .25rem) * 2);color:rgb(var(--text-primary));text-decoration-line:none;transition:all .2s ease;-webkit-tap-highlight-color:transparent;--tw-outline-style: none;outline-style:none}.drawer-item:hover{--tw-scale-x: 95%;--tw-scale-y: 95%;--tw-scale-z: 95%;scale:var(--tw-scale-x) var(--tw-scale-y);background-color:rgb(var(--bg-primary-hover));color:rgb(var(--text-primary))}.drawer-item.active{background-image:linear-gradient(135deg,rgb(var(--gradient-primary-start)),rgb(var(--gradient-primary-end)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:var(--color-white, #fff)}.drawer-item.active .item-icon{color:var(--color-white, #fff)}.drawer-item:active{transform:scale(.98)}.drawer-item:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.item-content{display:flex;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 3);overflow:hidden}.item-icon{flex-shrink:0;color:inherit}.item-label{flex:1;overflow:hidden;text-align:left;font-size:13px;--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);text-overflow:ellipsis;white-space:nowrap}.chevron-icon{margin-left:auto;flex-shrink:0;color:rgb(var(--text-primary));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;align-items:center;justify-content:center;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 3);font-size:11px;color:rgb(var(--text-placeholder));-webkit-user-select:none;user-select:none;font-family:Roboto,monospace}.drawer-version-dot{display:block;height:calc(var(--spacing, .25rem) * 1.5);width:calc(var(--spacing, .25rem) * 1.5);border-radius:calc(infinity * 1px);background-color:rgb(var(--text-placeholder))}.drawer-container[style*=\"width: 64px\"] .drawer-item{justify-content:center;padding-left:16px!important}.drawer-container[style*=\"width: 64px\"] .item-content{justify-content:center}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-scale-x{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-scale-y{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-scale-z{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-outline-style: solid;--tw-scale-x: 1;--tw-scale-y: 1;--tw-scale-z: 1;--tw-font-weight: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\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: i57.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: [
3630
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DrawerComponent, deps: [{ token: i2$1.Router }], target: i0.ɵɵFactoryTarget.Component });
3631
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DrawerComponent, isStandalone: true, selector: "fx-ui-drawer", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, isExpanded: { classPropertyName: "isExpanded", publicName: "isExpanded", isSignal: false, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: false, isRequired: false, transformFunction: null }, version: { classPropertyName: "version", publicName: "version", isSignal: false, isRequired: false, transformFunction: null } }, 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 alt=\"Home\"\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 @for (item of items(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n\n <!-- Version -->\n @if (version) {\n <div class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n @if (isExpanded) {\n <span>{{ version }}</span>\n }\n @if (!isExpanded) {\n <span class=\"drawer-version-dot\"></span>\n }\n </div>\n }\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n [attr.aria-label]=\"isExpanded ? 'Collapse navigation' : 'Expand navigation'\"\n [attr.aria-expanded]=\"isExpanded\"\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 @if (item.route && !item.children) {\n <a\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 @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n </div>\n </a>\n }\n\n @if (!item.route || item.children) {\n <button\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 @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n @if (isExpanded && item.children && item.children.length > 0) {\n <fx-ui-hero-icon\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n }\n </div>\n </button>\n }\n\n <!-- Accordion Children -->\n @if (item.children && item.children.length > 0) {\n <div\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n @for (child of item.children; track child) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n }\n </div>\n }\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";@layer properties;:host{display:block;height:100%}.drawer-host-wrapper{position:relative;height:100%;border-right-style:var(--tw-border-style);border-right-width:1px;border-color:rgb(var(--border-default))}.drawer-container{display:flex;height:100%;flex-direction:column;overflow:auto;background-color:rgb(var(--bg-primary));padding-inline:calc(var(--spacing, .25rem) * 2);transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);right:-12px;transition:all .2s ease}.toggle-btn:hover{background-color:rgb(var(--bg-primary-hover));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.toggle-btn:active{transform:translateY(-50%) scale(.9)}.toggle-btn:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-nav{flex:1;overflow-x:hidden;overflow-y:auto;padding-block:calc(var(--spacing, .25rem) * 2)}.drawer-nav::-webkit-scrollbar{width:calc(var(--spacing, .25rem) * 1.5)}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:.125rem;background-color:rgb(var(--border-default))}.drawer-nav::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--text-placeholder))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;margin-top:var(--spacing, .25rem);display:flex;min-height:calc(var(--spacing, .25rem) * 8);width:100%;cursor:pointer;align-items:center;border-radius:.25rem;--tw-border-style: none;border-style:none;background-color:transparent;padding-inline:1rem;padding-block:calc(var(--spacing, .25rem) * 2);color:rgb(var(--text-primary));text-decoration-line:none;transition:all .2s ease}.drawer-item:hover{--tw-scale-x: 95%;--tw-scale-y: 95%;--tw-scale-z: 95%;scale:var(--tw-scale-x) var(--tw-scale-y);background-color:rgb(var(--bg-primary-hover));color:rgb(var(--text-primary))}.drawer-item.active{background-image:linear-gradient(135deg,rgb(var(--gradient-primary-start)),rgb(var(--gradient-primary-end)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:var(--color-white, #fff)}.drawer-item.active .item-icon{color:var(--color-white, #fff)}.drawer-item:active{transform:scale(.98)}.drawer-item:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-item{-webkit-tap-highlight-color:transparent;--tw-outline-style: none;outline-style:none}.item-content{display:flex;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 3);overflow:hidden}.item-icon{flex-shrink:0;color:inherit}.item-label{flex:1;overflow:hidden;text-align:left;font-size:13px;--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);text-overflow:ellipsis;white-space:nowrap}.chevron-icon{margin-left:auto;flex-shrink:0;color:rgb(var(--text-primary));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;align-items:center;justify-content:center;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 3);font-size:11px;color:rgb(var(--text-placeholder));-webkit-user-select:none;user-select:none;font-family:Roboto,monospace}.drawer-version-dot{display:block;height:calc(var(--spacing, .25rem) * 1.5);width:calc(var(--spacing, .25rem) * 1.5);border-radius:calc(infinity * 1px);background-color:rgb(var(--text-placeholder))}.drawer-container[style*=\"width: 64px\"] .drawer-item{justify-content:center;padding-left:16px!important}.drawer-container[style*=\"width: 64px\"] .item-content{justify-content:center}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-scale-x{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-scale-y{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-scale-z{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-outline-style: solid;--tw-scale-x: 1;--tw-scale-y: 1;--tw-scale-z: 1;--tw-font-weight: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: 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"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], animations: [
4170
3632
  trigger('drawerExpand', [
4171
3633
  state('collapsed', style({ width: '70px' })),
4172
3634
  state('expanded', style({ width: '260px' })),
@@ -4177,11 +3639,11 @@ class DrawerComponent {
4177
3639
  state('expanded', style({ height: '*', overflow: 'visible', opacity: 1 })),
4178
3640
  transition('collapsed <=> expanded', animate('300ms cubic-bezier(0.4, 0, 0.2, 1)')),
4179
3641
  ]),
4180
- ] });
3642
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4181
3643
  }
4182
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DrawerComponent, decorators: [{
3644
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DrawerComponent, decorators: [{
4183
3645
  type: Component,
4184
- args: [{ selector: 'fx-ui-drawer', standalone: false, animations: [
3646
+ args: [{ selector: 'fx-ui-drawer', animations: [
4185
3647
  trigger('drawerExpand', [
4186
3648
  state('collapsed', style({ width: '70px' })),
4187
3649
  state('expanded', style({ width: '260px' })),
@@ -4192,64 +3654,58 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4192
3654
  state('expanded', style({ height: '*', overflow: 'visible', opacity: 1 })),
4193
3655
  transition('collapsed <=> expanded', animate('300ms cubic-bezier(0.4, 0, 0.2, 1)')),
4194
3656
  ]),
4195
- ], 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 alt=\"Home\"\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 [attr.aria-label]=\"isExpanded ? 'Collapse navigation' : 'Expand navigation'\"\n [attr.aria-expanded]=\"isExpanded\"\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\";@layer properties;:host{display:block;height:100%}.drawer-host-wrapper{position:relative;height:100%;border-right-style:var(--tw-border-style);border-right-width:1px;border-color:rgb(var(--border-default))}.drawer-container{display:flex;height:100%;flex-direction:column;overflow:auto;background-color:rgb(var(--bg-primary));padding-inline:calc(var(--spacing, .25rem) * 2);transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);right:-12px;transition:all .2s ease}.toggle-btn:hover{background-color:rgb(var(--bg-primary-hover));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.toggle-btn:active{transform:translateY(-50%) scale(.9)}.toggle-btn:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-nav{flex:1;overflow-x:hidden;overflow-y:auto;padding-block:calc(var(--spacing, .25rem) * 2)}.drawer-nav::-webkit-scrollbar{width:calc(var(--spacing, .25rem) * 1.5)}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:.125rem;background-color:rgb(var(--border-default))}.drawer-nav::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--text-placeholder))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;margin-top:var(--spacing, .25rem);display:flex;min-height:calc(var(--spacing, .25rem) * 8);width:100%;cursor:pointer;align-items:center;border-radius:.25rem;--tw-border-style: none;border-style:none;background-color:transparent;padding-inline:1rem;padding-block:calc(var(--spacing, .25rem) * 2);color:rgb(var(--text-primary));text-decoration-line:none;transition:all .2s ease;-webkit-tap-highlight-color:transparent;--tw-outline-style: none;outline-style:none}.drawer-item:hover{--tw-scale-x: 95%;--tw-scale-y: 95%;--tw-scale-z: 95%;scale:var(--tw-scale-x) var(--tw-scale-y);background-color:rgb(var(--bg-primary-hover));color:rgb(var(--text-primary))}.drawer-item.active{background-image:linear-gradient(135deg,rgb(var(--gradient-primary-start)),rgb(var(--gradient-primary-end)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:var(--color-white, #fff)}.drawer-item.active .item-icon{color:var(--color-white, #fff)}.drawer-item:active{transform:scale(.98)}.drawer-item:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.item-content{display:flex;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 3);overflow:hidden}.item-icon{flex-shrink:0;color:inherit}.item-label{flex:1;overflow:hidden;text-align:left;font-size:13px;--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);text-overflow:ellipsis;white-space:nowrap}.chevron-icon{margin-left:auto;flex-shrink:0;color:rgb(var(--text-primary));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;align-items:center;justify-content:center;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 3);font-size:11px;color:rgb(var(--text-placeholder));-webkit-user-select:none;user-select:none;font-family:Roboto,monospace}.drawer-version-dot{display:block;height:calc(var(--spacing, .25rem) * 1.5);width:calc(var(--spacing, .25rem) * 1.5);border-radius:calc(infinity * 1px);background-color:rgb(var(--text-placeholder))}.drawer-container[style*=\"width: 64px\"] .drawer-item{justify-content:center;padding-left:16px!important}.drawer-container[style*=\"width: 64px\"] .item-content{justify-content:center}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-scale-x{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-scale-y{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-scale-z{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-outline-style: solid;--tw-scale-x: 1;--tw-scale-y: 1;--tw-scale-z: 1;--tw-font-weight: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
4196
- }], ctorParameters: () => [{ type: i1$4.Router }], propDecorators: { items: [{
4197
- type: Input
4198
- }], isExpanded: [{
3657
+ ], changeDetection: ChangeDetectionStrategy.OnPush, imports: [
3658
+ NgClass,
3659
+ NgTemplateOutlet,
3660
+ MatTooltip,
3661
+ HeroIconComponent,
3662
+ RouterLink,
3663
+ ], 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 alt=\"Home\"\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 @for (item of items(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n\n <!-- Version -->\n @if (version) {\n <div class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n @if (isExpanded) {\n <span>{{ version }}</span>\n }\n @if (!isExpanded) {\n <span class=\"drawer-version-dot\"></span>\n }\n </div>\n }\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n [attr.aria-label]=\"isExpanded ? 'Collapse navigation' : 'Expand navigation'\"\n [attr.aria-expanded]=\"isExpanded\"\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 @if (item.route && !item.children) {\n <a\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 @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n </div>\n </a>\n }\n\n @if (!item.route || item.children) {\n <button\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 @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n @if (isExpanded && item.children && item.children.length > 0) {\n <fx-ui-hero-icon\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n }\n </div>\n </button>\n }\n\n <!-- Accordion Children -->\n @if (item.children && item.children.length > 0) {\n <div\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n @for (child of item.children; track child) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n }\n </div>\n }\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";@layer properties;:host{display:block;height:100%}.drawer-host-wrapper{position:relative;height:100%;border-right-style:var(--tw-border-style);border-right-width:1px;border-color:rgb(var(--border-default))}.drawer-container{display:flex;height:100%;flex-direction:column;overflow:auto;background-color:rgb(var(--bg-primary));padding-inline:calc(var(--spacing, .25rem) * 2);transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);right:-12px;transition:all .2s ease}.toggle-btn:hover{background-color:rgb(var(--bg-primary-hover));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.toggle-btn:active{transform:translateY(-50%) scale(.9)}.toggle-btn:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-nav{flex:1;overflow-x:hidden;overflow-y:auto;padding-block:calc(var(--spacing, .25rem) * 2)}.drawer-nav::-webkit-scrollbar{width:calc(var(--spacing, .25rem) * 1.5)}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:.125rem;background-color:rgb(var(--border-default))}.drawer-nav::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--text-placeholder))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;margin-top:var(--spacing, .25rem);display:flex;min-height:calc(var(--spacing, .25rem) * 8);width:100%;cursor:pointer;align-items:center;border-radius:.25rem;--tw-border-style: none;border-style:none;background-color:transparent;padding-inline:1rem;padding-block:calc(var(--spacing, .25rem) * 2);color:rgb(var(--text-primary));text-decoration-line:none;transition:all .2s ease}.drawer-item:hover{--tw-scale-x: 95%;--tw-scale-y: 95%;--tw-scale-z: 95%;scale:var(--tw-scale-x) var(--tw-scale-y);background-color:rgb(var(--bg-primary-hover));color:rgb(var(--text-primary))}.drawer-item.active{background-image:linear-gradient(135deg,rgb(var(--gradient-primary-start)),rgb(var(--gradient-primary-end)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:var(--color-white, #fff)}.drawer-item.active .item-icon{color:var(--color-white, #fff)}.drawer-item:active{transform:scale(.98)}.drawer-item:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-item{-webkit-tap-highlight-color:transparent;--tw-outline-style: none;outline-style:none}.item-content{display:flex;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 3);overflow:hidden}.item-icon{flex-shrink:0;color:inherit}.item-label{flex:1;overflow:hidden;text-align:left;font-size:13px;--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);text-overflow:ellipsis;white-space:nowrap}.chevron-icon{margin-left:auto;flex-shrink:0;color:rgb(var(--text-primary));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;align-items:center;justify-content:center;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 3);font-size:11px;color:rgb(var(--text-placeholder));-webkit-user-select:none;user-select:none;font-family:Roboto,monospace}.drawer-version-dot{display:block;height:calc(var(--spacing, .25rem) * 1.5);width:calc(var(--spacing, .25rem) * 1.5);border-radius:calc(infinity * 1px);background-color:rgb(var(--text-placeholder))}.drawer-container[style*=\"width: 64px\"] .drawer-item{justify-content:center;padding-left:16px!important}.drawer-container[style*=\"width: 64px\"] .item-content{justify-content:center}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-scale-x{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-scale-y{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-scale-z{syntax: \"*\"; inherits: false; initial-value: 1;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-outline-style: solid;--tw-scale-x: 1;--tw-scale-y: 1;--tw-scale-z: 1;--tw-font-weight: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
3664
+ }], ctorParameters: () => [{ type: i2$1.Router }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], isExpanded: [{
4199
3665
  type: Input
4200
3666
  }], logo: [{
4201
3667
  type: Input
4202
3668
  }], version: [{
4203
3669
  type: Input
4204
- }], toggleExpanded: [{
4205
- type: Output
4206
- }], itemClicked: [{
4207
- type: Output
4208
- }] } });
3670
+ }], toggleExpanded: [{ type: i0.Output, args: ["toggleExpanded"] }], itemClicked: [{ type: i0.Output, args: ["itemClicked"] }] } });
4209
3671
 
4210
3672
  /** Row-card skeleton placeholder for master-detail list panes. */
4211
3673
  class SkeletonListComponent {
4212
- rows = 5;
3674
+ rows = input(5, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
4213
3675
  range(n) {
4214
3676
  return Array.from({ length: Number(n) || 0 }, (_, i) => i);
4215
3677
  }
4216
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4217
- 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-lg border border-border-default p-semi\">\n <div class=\"flex items-center gap-normal mb-small\">\n <div class=\"w-8 h-8 rounded-lg 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" });
3678
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SkeletonListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3679
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SkeletonListComponent, isStandalone: true, selector: "fx-ui-skeleton-list", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"flex flex-col gap-normal animate-pulse\">\n @for (r of range(rows()); track r) {\n <div class=\"rounded-lg border border-border-default p-semi\">\n <div class=\"flex items-center gap-normal mb-small\">\n <div class=\"w-8 h-8 rounded-lg 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", changeDetection: i0.ChangeDetectionStrategy.OnPush });
4218
3680
  }
4219
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonListComponent, decorators: [{
3681
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SkeletonListComponent, decorators: [{
4220
3682
  type: Component,
4221
- 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-lg border border-border-default p-semi\">\n <div class=\"flex items-center gap-normal mb-small\">\n <div class=\"w-8 h-8 rounded-lg 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" }]
4222
- }], propDecorators: { rows: [{
4223
- type: Input
4224
- }] } });
3683
+ args: [{ selector: 'fx-ui-skeleton-list', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col gap-normal animate-pulse\">\n @for (r of range(rows()); track r) {\n <div class=\"rounded-lg border border-border-default p-semi\">\n <div class=\"flex items-center gap-normal mb-small\">\n <div class=\"w-8 h-8 rounded-lg 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" }]
3684
+ }], propDecorators: { rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }] } });
4225
3685
 
4226
3686
  /** Card-shaped skeleton placeholder for detail panels. */
4227
3687
  class SkeletonDetailComponent {
4228
3688
  /** Number of content cards rendered below the header card. */
4229
- cards = 3;
3689
+ cards = input(3, ...(ngDevMode ? [{ debugName: "cards" }] : /* istanbul ignore next */ []));
4230
3690
  /** Rows per content card. */
4231
- rows = 4;
3691
+ rows = input(4, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
4232
3692
  range(n) {
4233
3693
  return Array.from({ length: Number(n) || 0 }, (_, i) => i);
4234
3694
  }
4235
3695
  rowWidth(i) {
4236
3696
  return [90, 70, 80, 60][i % 4];
4237
3697
  }
4238
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4239
- 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" });
3698
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SkeletonDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3699
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SkeletonDetailComponent, isStandalone: true, selector: "fx-ui-skeleton-detail", inputs: { cards: { classPropertyName: "cards", publicName: "cards", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null } }, 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", changeDetection: i0.ChangeDetectionStrategy.OnPush });
4240
3700
  }
4241
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SkeletonDetailComponent, decorators: [{
3701
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SkeletonDetailComponent, decorators: [{
4242
3702
  type: Component,
4243
- 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" }]
4244
- }], propDecorators: { cards: [{
4245
- type: Input
4246
- }], rows: [{
4247
- type: Input
4248
- }] } });
3703
+ args: [{ selector: 'fx-ui-skeleton-detail', changeDetection: ChangeDetectionStrategy.OnPush, 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" }]
3704
+ }], propDecorators: { cards: [{ type: i0.Input, args: [{ isSignal: true, alias: "cards", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }] } });
4249
3705
 
4250
3706
  /** KPI tile row: big number + tinted icon box + caption, in a responsive grid. */
4251
3707
  class StatCardsComponent {
4252
- cards = [];
3708
+ cards = input([], ...(ngDevMode ? [{ debugName: "cards" }] : /* istanbul ignore next */ []));
4253
3709
  /** Grid columns; defaults to one column per card. */
4254
3710
  cols;
4255
3711
  get gridColumns() {
@@ -4265,38 +3721,36 @@ class StatCardsComponent {
4265
3721
  boxClass(card) {
4266
3722
  return card.tone ? toneBadge(card.tone) : 'bg-bg-hover text-text-secondary';
4267
3723
  }
4268
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StatCardsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4269
- 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"] }] });
3724
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: StatCardsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3725
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: StatCardsComponent, isStandalone: true, selector: "fx-ui-stat-cards", inputs: { cards: { classPropertyName: "cards", publicName: "cards", isSignal: true, isRequired: false, transformFunction: null }, cols: { classPropertyName: "cols", publicName: "cols", isSignal: false, isRequired: false, transformFunction: null } }, 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: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4270
3726
  }
4271
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StatCardsComponent, decorators: [{
3727
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: StatCardsComponent, decorators: [{
4272
3728
  type: Component,
4273
- 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" }]
4274
- }], propDecorators: { cards: [{
4275
- type: Input
4276
- }], cols: [{
3729
+ args: [{ selector: 'fx-ui-stat-cards', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
3730
+ NgStyle,
3731
+ NgClass,
3732
+ HeroIconComponent,
3733
+ ], 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" }]
3734
+ }], propDecorators: { cards: [{ type: i0.Input, args: [{ isSignal: true, alias: "cards", required: false }] }], cols: [{
4277
3735
  type: Input
4278
3736
  }] } });
4279
3737
 
4280
3738
  /** Centered "no data" block. The message is caller-translated (no i18n in lib). */
4281
3739
  class EmptyStateComponent {
4282
- message = 'No data';
3740
+ message = input('No data', ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
4283
3741
  /** Optional icon (hero-icon name). */
4284
3742
  icon;
4285
3743
  /** Min height of the block, CSS length. */
4286
- height = '120px';
4287
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4288
- 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"] }] });
3744
+ height = input('120px', ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
3745
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3746
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: EmptyStateComponent, isStandalone: true, selector: "fx-ui-empty-state", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: false, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null } }, 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4289
3747
  }
4290
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: EmptyStateComponent, decorators: [{
3748
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: EmptyStateComponent, decorators: [{
4291
3749
  type: Component,
4292
- 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" }]
4293
- }], propDecorators: { message: [{
4294
- type: Input
4295
- }], icon: [{
4296
- type: Input
4297
- }], height: [{
3750
+ args: [{ selector: 'fx-ui-empty-state', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HeroIconComponent], 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" }]
3751
+ }], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], icon: [{
4298
3752
  type: Input
4299
- }] } });
3753
+ }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }] } });
4300
3754
 
4301
3755
  /**
4302
3756
  * Tone-tinted filter chip row. Replaces the per-tab chipClass() copies —
@@ -4305,8 +3759,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4305
3759
  */
4306
3760
  class FilterChipsComponent {
4307
3761
  options = [];
3762
+ /* Accepts undefined so screens can bind [value]="filters.x" where the
3763
+ * filter bag keys are optional; '' and undefined both mean "All". */
4308
3764
  value = '';
4309
- valueChange = new EventEmitter();
3765
+ valueChange = output();
4310
3766
  /** Per-value tone overrides (e.g. { Safe: 'information', Protected: 'discovery' as any }). */
4311
3767
  toneOverrides = {};
4312
3768
  select(option) {
@@ -4314,7 +3770,7 @@ class FilterChipsComponent {
4314
3770
  this.valueChange.emit(option.value);
4315
3771
  }
4316
3772
  chipClass(option) {
4317
- const active = this.value === option.value;
3773
+ const active = (this.value ?? '') === option.value;
4318
3774
  if (!option.value) {
4319
3775
  return active
4320
3776
  ? 'bg-text-primary text-text-focus'
@@ -4328,19 +3784,17 @@ class FilterChipsComponent {
4328
3784
  }
4329
3785
  return active ? `${toneBg(tone)} text-text-focus` : `${toneBadge(tone)} hover:opacity-50`;
4330
3786
  }
4331
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FilterChipsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4332
- 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"] }] });
3787
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FilterChipsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3788
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: FilterChipsComponent, isStandalone: true, 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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4333
3789
  }
4334
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: FilterChipsComponent, decorators: [{
3790
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FilterChipsComponent, decorators: [{
4335
3791
  type: Component,
4336
- 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" }]
3792
+ args: [{ selector: 'fx-ui-filter-chips', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass], 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" }]
4337
3793
  }], propDecorators: { options: [{
4338
3794
  type: Input
4339
3795
  }], value: [{
4340
3796
  type: Input
4341
- }], valueChange: [{
4342
- type: Output
4343
- }], toneOverrides: [{
3797
+ }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], toneOverrides: [{
4344
3798
  type: Input
4345
3799
  }] } });
4346
3800
 
@@ -4348,7 +3802,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4348
3802
  class MeterComponent {
4349
3803
  value = 0;
4350
3804
  max = 10;
4351
- tone = null;
3805
+ tone = input(null, ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
4352
3806
  /** Caller-translated texts; omitted → bar only. */
4353
3807
  label;
4354
3808
  caption;
@@ -4358,21 +3812,19 @@ class MeterComponent {
4358
3812
  return Math.min(100, Math.max(0, pct));
4359
3813
  }
4360
3814
  get fillClass() {
4361
- return toneBg(this.tone);
3815
+ return toneBg(this.tone());
4362
3816
  }
4363
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MeterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4364
- 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\n class=\"h-2 rounded-full bg-bg-hover overflow-hidden\"\n role=\"progressbar\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"max\"\n [attr.aria-valuenow]=\"value\"\n [attr.aria-label]=\"label || null\"\n >\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"] }] });
3817
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MeterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3818
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: MeterComponent, isStandalone: true, selector: "fx-ui-meter", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: false, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: false, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: false, isRequired: false, transformFunction: null } }, 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\n class=\"h-2 rounded-full bg-bg-hover overflow-hidden\"\n role=\"progressbar\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"max\"\n [attr.aria-valuenow]=\"value\"\n [attr.aria-label]=\"label || null\"\n >\n <div class=\"h-full rounded-full\" [ngClass]=\"fillClass\" [style.width.%]=\"percent\"></div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4365
3819
  }
4366
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MeterComponent, decorators: [{
3820
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MeterComponent, decorators: [{
4367
3821
  type: Component,
4368
- 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\n class=\"h-2 rounded-full bg-bg-hover overflow-hidden\"\n role=\"progressbar\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"max\"\n [attr.aria-valuenow]=\"value\"\n [attr.aria-label]=\"label || null\"\n >\n <div class=\"h-full rounded-full\" [ngClass]=\"fillClass\" [style.width.%]=\"percent\"></div>\n </div>\n</div>\n" }]
3822
+ args: [{ selector: 'fx-ui-meter', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass], 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\n class=\"h-2 rounded-full bg-bg-hover overflow-hidden\"\n role=\"progressbar\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"max\"\n [attr.aria-valuenow]=\"value\"\n [attr.aria-label]=\"label || null\"\n >\n <div class=\"h-full rounded-full\" [ngClass]=\"fillClass\" [style.width.%]=\"percent\"></div>\n </div>\n</div>\n" }]
4369
3823
  }], propDecorators: { value: [{
4370
3824
  type: Input
4371
3825
  }], max: [{
4372
3826
  type: Input
4373
- }], tone: [{
4374
- type: Input
4375
- }], label: [{
3827
+ }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], label: [{
4376
3828
  type: Input
4377
3829
  }], caption: [{
4378
3830
  type: Input
@@ -4381,26 +3833,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4381
3833
  /** Detail-panel section: card with an icon + heading header and projected body. */
4382
3834
  class SectionCardComponent {
4383
3835
  /** Caller-translated heading. */
4384
- title = '';
3836
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
4385
3837
  /** hero-icon name; omitted → text-only header. */
4386
3838
  icon;
4387
- iconTone = null;
3839
+ iconTone = input(null, ...(ngDevMode ? [{ debugName: "iconTone" }] : /* istanbul ignore next */ []));
4388
3840
  get iconClass() {
4389
- return this.iconTone ? toneText(this.iconTone) : 'text-text-secondary';
3841
+ const iconTone = this.iconTone();
3842
+ return iconTone ? toneText(iconTone) : 'text-text-secondary';
4390
3843
  }
4391
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SectionCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4392
- 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"] }] });
3844
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SectionCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3845
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SectionCardComponent, isStandalone: true, selector: "fx-ui-section-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: false, isRequired: false, transformFunction: null }, iconTone: { classPropertyName: "iconTone", publicName: "iconTone", isSignal: true, isRequired: false, transformFunction: null } }, 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: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4393
3846
  }
4394
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SectionCardComponent, decorators: [{
3847
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SectionCardComponent, decorators: [{
4395
3848
  type: Component,
4396
- 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" }]
4397
- }], propDecorators: { title: [{
4398
- type: Input
4399
- }], icon: [{
3849
+ args: [{ selector: 'fx-ui-section-card', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HeroIconComponent, NgClass], 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" }]
3850
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], icon: [{
4400
3851
  type: Input
4401
- }], iconTone: [{
4402
- type: Input
4403
- }] } });
3852
+ }], iconTone: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTone", required: false }] }] } });
4404
3853
 
4405
3854
  /**
4406
3855
  * Label-over-value field for detail panels. The label uses txt-field-label
@@ -4409,17 +3858,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4409
3858
  */
4410
3859
  class InfoFieldComponent {
4411
3860
  /** Caller-translated label. */
4412
- label = '';
3861
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
4413
3862
  value;
4414
3863
  /** Colours the value; null/undefined renders the primary text colour. */
4415
3864
  tone = null;
4416
3865
  /** Monospace value (hashes, paths). */
4417
3866
  mono = false;
4418
3867
  /** Placeholder when value is empty. */
4419
- placeholder = '---';
3868
+ placeholder = input('---', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
4420
3869
  get displayValue() {
4421
3870
  if (this.value === null || this.value === undefined || this.value === '') {
4422
- return this.placeholder;
3871
+ return this.placeholder();
4423
3872
  }
4424
3873
  return String(this.value);
4425
3874
  }
@@ -4427,23 +3876,19 @@ class InfoFieldComponent {
4427
3876
  const toneClass = this.tone ? toneText(this.tone) : 'text-text-primary';
4428
3877
  return this.mono ? `${toneClass} font-mono break-all` : toneClass;
4429
3878
  }
4430
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InfoFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4431
- 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"] }] });
3879
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: InfoFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3880
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.20", type: InfoFieldComponent, isStandalone: true, selector: "fx-ui-info-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: false, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: false, isRequired: false, transformFunction: null }, mono: { classPropertyName: "mono", publicName: "mono", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, 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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4432
3881
  }
4433
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InfoFieldComponent, decorators: [{
3882
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: InfoFieldComponent, decorators: [{
4434
3883
  type: Component,
4435
- 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" }]
4436
- }], propDecorators: { label: [{
4437
- type: Input
4438
- }], value: [{
3884
+ args: [{ selector: 'fx-ui-info-field', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass], 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" }]
3885
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{
4439
3886
  type: Input
4440
3887
  }], tone: [{
4441
3888
  type: Input
4442
3889
  }], mono: [{
4443
3890
  type: Input
4444
- }], placeholder: [{
4445
- type: Input
4446
- }] } });
3891
+ }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }] } });
4447
3892
 
4448
3893
  /**
4449
3894
  * Compact total/critical/high/medium(/low) badge cluster used in table cells.
@@ -4456,7 +3901,7 @@ class SeverityBadgesComponent {
4456
3901
  showZero = true;
4457
3902
  /** Append the severity letter to counts ("3C", "5H", "2M") per the report design. */
4458
3903
  suffixed = false;
4459
- badgeClick = new EventEmitter();
3904
+ badgeClick = output();
4460
3905
  static TONES = {
4461
3906
  total: null,
4462
3907
  critical: 'critical',
@@ -4477,21 +3922,19 @@ class SeverityBadgesComponent {
4477
3922
  badgeClass(badge) {
4478
3923
  return badge.tone ? toneBadge(badge.tone) : 'bg-bg-hover text-text-primary';
4479
3924
  }
4480
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SeverityBadgesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4481
- 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 <button\n type=\"button\"\n class=\"px-2 py-0.5 rounded-full txt-utility-caption font-medium cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50\"\n [ngClass]=\"badgeClass(badge)\"\n [attr.aria-label]=\"badge.key + ': ' + badge.label\"\n (click)=\"badgeClick.emit(badge.key)\"\n >{{ badge.label }}</button>\n }\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
3925
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SeverityBadgesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3926
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: SeverityBadgesComponent, isStandalone: true, 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 <button\n type=\"button\"\n class=\"px-2 py-0.5 rounded-full txt-utility-caption font-medium cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50\"\n [ngClass]=\"badgeClass(badge)\"\n [attr.aria-label]=\"badge.key + ': ' + badge.label\"\n (click)=\"badgeClick.emit(badge.key)\"\n >{{ badge.label }}</button>\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4482
3927
  }
4483
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SeverityBadgesComponent, decorators: [{
3928
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: SeverityBadgesComponent, decorators: [{
4484
3929
  type: Component,
4485
- 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 <button\n type=\"button\"\n class=\"px-2 py-0.5 rounded-full txt-utility-caption font-medium cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50\"\n [ngClass]=\"badgeClass(badge)\"\n [attr.aria-label]=\"badge.key + ': ' + badge.label\"\n (click)=\"badgeClick.emit(badge.key)\"\n >{{ badge.label }}</button>\n }\n</div>\n" }]
3930
+ args: [{ selector: 'fx-ui-severity-badges', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass], template: "<div class=\"flex items-center gap-small\">\n @for (badge of badges; track badge.key) {\n <button\n type=\"button\"\n class=\"px-2 py-0.5 rounded-full txt-utility-caption font-medium cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50\"\n [ngClass]=\"badgeClass(badge)\"\n [attr.aria-label]=\"badge.key + ': ' + badge.label\"\n (click)=\"badgeClick.emit(badge.key)\"\n >{{ badge.label }}</button>\n }\n</div>\n" }]
4486
3931
  }], propDecorators: { stats: [{
4487
3932
  type: Input
4488
3933
  }], showZero: [{
4489
3934
  type: Input
4490
3935
  }], suffixed: [{
4491
3936
  type: Input
4492
- }], badgeClick: [{
4493
- type: Output
4494
- }] } });
3937
+ }], badgeClick: [{ type: i0.Output, args: ["badgeClick"] }] } });
4495
3938
 
4496
3939
  let nextUid = 0;
4497
3940
  /**
@@ -4512,23 +3955,23 @@ let nextUid = 0;
4512
3955
  class MasterDetailComponent {
4513
3956
  table;
4514
3957
  /** Fixed list-pane width on lg+ viewports (stacked full-width below). */
4515
- listWidth = '420px';
4516
- maxListHeight = '640px';
4517
- pageSizeOptions = [5, 10, 20, 50];
3958
+ listWidth = input('420px', ...(ngDevMode ? [{ debugName: "listWidth" }] : /* istanbul ignore next */ []));
3959
+ maxListHeight = input('640px', ...(ngDevMode ? [{ debugName: "maxListHeight" }] : /* istanbul ignore next */ []));
3960
+ pageSizeOptions = input([5, 10, 20, 50], ...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : /* istanbul ignore next */ []));
4518
3961
  /** Labels come in via inputs — the lib carries no i18n. */
4519
- emptyMessage = 'No data';
4520
- listLabel = '';
4521
- skeletonCards = 3;
4522
- rowTemplate;
4523
- detailTemplate;
4524
- paginator;
3962
+ emptyMessage = input('No data', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
3963
+ listLabel = input('', ...(ngDevMode ? [{ debugName: "listLabel" }] : /* istanbul ignore next */ []));
3964
+ skeletonCards = input(3, ...(ngDevMode ? [{ debugName: "skeletonCards" }] : /* istanbul ignore next */ []));
3965
+ rowTemplate = contentChild.required('row');
3966
+ detailTemplate = contentChild.required('detail');
3967
+ paginator = viewChild.required(MatPaginator);
4525
3968
  uid = `fx-md-${nextUid++}`;
4526
3969
  ngAfterViewInit() {
4527
3970
  // The paginator lives in this view, not the host page's, so the host's
4528
3971
  // @ViewChild(MatPaginator) never finds it. Hand it to the table so
4529
3972
  // refresh() keeps resetting pageIndex.
4530
3973
  if (this.table) {
4531
- this.table.paginator = this.paginator;
3974
+ this.table.paginator = this.paginator();
4532
3975
  }
4533
3976
  }
4534
3977
  isSelected(row) {
@@ -4568,36 +4011,60 @@ class MasterDetailComponent {
4568
4011
  el?.focus();
4569
4012
  el?.scrollIntoView({ block: 'nearest' });
4570
4013
  }
4571
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MasterDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4572
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MasterDetailComponent, isStandalone: false, selector: "fx-ui-master-detail", inputs: { table: "table", listWidth: "listWidth", maxListHeight: "maxListHeight", pageSizeOptions: "pageSizeOptions", emptyMessage: "emptyMessage", listLabel: "listLabel", skeletonCards: "skeletonCards" }, queries: [{ propertyName: "rowTemplate", first: true, predicate: ["row"], descendants: true }, { propertyName: "detailTemplate", first: true, predicate: ["detail"], descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], ngImport: i0, template: "<div class=\"flex flex-col lg:flex-row items-start gap-xl\" [style.--fx-md-list-width]=\"listWidth\">\n <!-- Master: list pane -->\n <div class=\"fx-md-list card-common\">\n <ng-content select=\"[mdHeader]\"></ng-content>\n <ng-content select=\"[mdFilters]\"></ng-content>\n <div\n class=\"flex flex-col gap-normal overflow-auto pr-xs\"\n [style.maxHeight]=\"maxListHeight\"\n role=\"listbox\"\n [attr.aria-label]=\"listLabel || null\"\n >\n @if (table.loading) {\n <fx-ui-skeleton-list [rows]=\"table.pageSize\"></fx-ui-skeleton-list>\n } @else {\n @for (row of table.dataSource.data; track table.idOf(row); let i = $index) {\n <button\n type=\"button\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(row)\"\n [tabindex]=\"isSelected(row) ? 0 : -1\"\n (click)=\"table.selectItem(row)\"\n (keydown)=\"onKeydown($event, i)\"\n class=\"text-left rounded-lg border p-semi transition-colors\"\n [ngClass]=\"\n isSelected(row)\n ? 'border-gradient-primary-start bg-gradient-primary-start/5'\n : 'border-border-default hover:border-border-interactive bg-bg-primary'\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: row, selected: isSelected(row) }\"\n ></ng-container>\n </button>\n }\n @if (!table.dataSource.data.length) {\n <fx-ui-empty-state [message]=\"emptyMessage\"></fx-ui-empty-state>\n }\n }\n </div>\n <!-- No (page) binding: ngAfterViewInit hands this paginator to the table,\n whose own BaseTable subscription (running after this child's hook)\n wires page events \u2014 a binding here would double-fetch every change. -->\n <mat-paginator\n class=\"mt-normal\"\n [length]=\"table.total\"\n [pageSize]=\"table.pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n ></mat-paginator>\n </div>\n\n <!-- Detail pane -->\n <div class=\"w-full lg:flex-1 min-w-0\">\n @if (table.selected) {\n @if (table.detailBusy) {\n <fx-ui-skeleton-detail [cards]=\"skeletonCards\"></fx-ui-skeleton-detail>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"detailTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: table.detail, selected: table.selected }\"\n ></ng-container>\n }\n } @else {\n <div class=\"card-common flex items-center justify-center h-[300px]\">\n <fx-ui-empty-state [message]=\"emptyMessage\"></fx-ui-empty-state>\n </div>\n }\n </div>\n</div>\n", styles: [".fx-md-list{width:100%}@media (min-width: 1080px){.fx-md-list{width:var(--fx-md-list-width, 420px);flex-shrink:0}}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i45.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: SkeletonListComponent, selector: "fx-ui-skeleton-list", inputs: ["rows"] }, { kind: "component", type: SkeletonDetailComponent, selector: "fx-ui-skeleton-detail", inputs: ["cards", "rows"] }, { kind: "component", type: EmptyStateComponent, selector: "fx-ui-empty-state", inputs: ["message", "icon", "height"] }] });
4014
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MasterDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4015
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: MasterDetailComponent, isStandalone: true, selector: "fx-ui-master-detail", inputs: { table: { classPropertyName: "table", publicName: "table", isSignal: false, isRequired: false, transformFunction: null }, listWidth: { classPropertyName: "listWidth", publicName: "listWidth", isSignal: true, isRequired: false, transformFunction: null }, maxListHeight: { classPropertyName: "maxListHeight", publicName: "maxListHeight", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, listLabel: { classPropertyName: "listLabel", publicName: "listLabel", isSignal: true, isRequired: false, transformFunction: null }, skeletonCards: { classPropertyName: "skeletonCards", publicName: "skeletonCards", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "rowTemplate", first: true, predicate: ["row"], descendants: true, isSignal: true }, { propertyName: "detailTemplate", first: true, predicate: ["detail"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"flex flex-col lg:flex-row items-start gap-xl\" [style.--fx-md-list-width]=\"listWidth()\">\n <!-- Master: list pane -->\n <div class=\"fx-md-list card-common\">\n <ng-content select=\"[mdHeader]\"></ng-content>\n <ng-content select=\"[mdFilters]\"></ng-content>\n <div\n class=\"flex flex-col gap-normal overflow-auto pr-xs\"\n [style.maxHeight]=\"maxListHeight()\"\n role=\"listbox\"\n [attr.aria-label]=\"listLabel() || null\"\n >\n @if (table.loading) {\n <fx-ui-skeleton-list [rows]=\"table.pageSize\"></fx-ui-skeleton-list>\n } @else {\n @for (row of table.dataSource.data; track table.idOf(row); let i = $index) {\n <button\n type=\"button\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(row)\"\n [tabindex]=\"isSelected(row) ? 0 : -1\"\n (click)=\"table.selectItem(row)\"\n (keydown)=\"onKeydown($event, i)\"\n class=\"text-left rounded-lg border p-semi transition-colors\"\n [ngClass]=\"\n isSelected(row)\n ? 'border-gradient-primary-start bg-gradient-primary-start/5'\n : 'border-border-default hover:border-border-interactive bg-bg-primary'\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: row, selected: isSelected(row) }\"\n ></ng-container>\n </button>\n }\n @if (!table.dataSource.data.length) {\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n }\n }\n </div>\n <!-- No (page) binding: ngAfterViewInit hands this paginator to the table,\n whose own BaseTable subscription (running after this child's hook)\n wires page events \u2014 a binding here would double-fetch every change. -->\n <mat-paginator\n class=\"mt-normal\"\n [length]=\"table.total\"\n [pageSize]=\"table.pageSize\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n ></mat-paginator>\n </div>\n\n <!-- Detail pane -->\n <div class=\"w-full lg:flex-1 min-w-0\">\n @if (table.selected) {\n @if (table.detailBusy) {\n <fx-ui-skeleton-detail [cards]=\"skeletonCards()\"></fx-ui-skeleton-detail>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"detailTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: table.detail, selected: table.selected }\"\n ></ng-container>\n }\n } @else {\n <div class=\"card-common flex items-center justify-center h-[300px]\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n </div>\n</div>\n", styles: [".fx-md-list{width:100%}@media(min-width:1080px){.fx-md-list{width:var(--fx-md-list-width, 420px);flex-shrink:0}}\n"], dependencies: [{ kind: "component", type: SkeletonListComponent, selector: "fx-ui-skeleton-list", inputs: ["rows"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EmptyStateComponent, selector: "fx-ui-empty-state", inputs: ["message", "icon", "height"] }, { kind: "component", type: MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: SkeletonDetailComponent, selector: "fx-ui-skeleton-detail", inputs: ["cards", "rows"] }] });
4573
4016
  }
4574
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MasterDetailComponent, decorators: [{
4017
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MasterDetailComponent, decorators: [{
4575
4018
  type: Component,
4576
- args: [{ selector: 'fx-ui-master-detail', standalone: false, template: "<div class=\"flex flex-col lg:flex-row items-start gap-xl\" [style.--fx-md-list-width]=\"listWidth\">\n <!-- Master: list pane -->\n <div class=\"fx-md-list card-common\">\n <ng-content select=\"[mdHeader]\"></ng-content>\n <ng-content select=\"[mdFilters]\"></ng-content>\n <div\n class=\"flex flex-col gap-normal overflow-auto pr-xs\"\n [style.maxHeight]=\"maxListHeight\"\n role=\"listbox\"\n [attr.aria-label]=\"listLabel || null\"\n >\n @if (table.loading) {\n <fx-ui-skeleton-list [rows]=\"table.pageSize\"></fx-ui-skeleton-list>\n } @else {\n @for (row of table.dataSource.data; track table.idOf(row); let i = $index) {\n <button\n type=\"button\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(row)\"\n [tabindex]=\"isSelected(row) ? 0 : -1\"\n (click)=\"table.selectItem(row)\"\n (keydown)=\"onKeydown($event, i)\"\n class=\"text-left rounded-lg border p-semi transition-colors\"\n [ngClass]=\"\n isSelected(row)\n ? 'border-gradient-primary-start bg-gradient-primary-start/5'\n : 'border-border-default hover:border-border-interactive bg-bg-primary'\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: row, selected: isSelected(row) }\"\n ></ng-container>\n </button>\n }\n @if (!table.dataSource.data.length) {\n <fx-ui-empty-state [message]=\"emptyMessage\"></fx-ui-empty-state>\n }\n }\n </div>\n <!-- No (page) binding: ngAfterViewInit hands this paginator to the table,\n whose own BaseTable subscription (running after this child's hook)\n wires page events \u2014 a binding here would double-fetch every change. -->\n <mat-paginator\n class=\"mt-normal\"\n [length]=\"table.total\"\n [pageSize]=\"table.pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n ></mat-paginator>\n </div>\n\n <!-- Detail pane -->\n <div class=\"w-full lg:flex-1 min-w-0\">\n @if (table.selected) {\n @if (table.detailBusy) {\n <fx-ui-skeleton-detail [cards]=\"skeletonCards\"></fx-ui-skeleton-detail>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"detailTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: table.detail, selected: table.selected }\"\n ></ng-container>\n }\n } @else {\n <div class=\"card-common flex items-center justify-center h-[300px]\">\n <fx-ui-empty-state [message]=\"emptyMessage\"></fx-ui-empty-state>\n </div>\n }\n </div>\n</div>\n", styles: [".fx-md-list{width:100%}@media (min-width: 1080px){.fx-md-list{width:var(--fx-md-list-width, 420px);flex-shrink:0}}\n"] }]
4019
+ args: [{ selector: 'fx-ui-master-detail', imports: [
4020
+ SkeletonListComponent,
4021
+ NgClass,
4022
+ NgTemplateOutlet,
4023
+ EmptyStateComponent,
4024
+ MatPaginator,
4025
+ SkeletonDetailComponent,
4026
+ ], template: "<div class=\"flex flex-col lg:flex-row items-start gap-xl\" [style.--fx-md-list-width]=\"listWidth()\">\n <!-- Master: list pane -->\n <div class=\"fx-md-list card-common\">\n <ng-content select=\"[mdHeader]\"></ng-content>\n <ng-content select=\"[mdFilters]\"></ng-content>\n <div\n class=\"flex flex-col gap-normal overflow-auto pr-xs\"\n [style.maxHeight]=\"maxListHeight()\"\n role=\"listbox\"\n [attr.aria-label]=\"listLabel() || null\"\n >\n @if (table.loading) {\n <fx-ui-skeleton-list [rows]=\"table.pageSize\"></fx-ui-skeleton-list>\n } @else {\n @for (row of table.dataSource.data; track table.idOf(row); let i = $index) {\n <button\n type=\"button\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(row)\"\n [tabindex]=\"isSelected(row) ? 0 : -1\"\n (click)=\"table.selectItem(row)\"\n (keydown)=\"onKeydown($event, i)\"\n class=\"text-left rounded-lg border p-semi transition-colors\"\n [ngClass]=\"\n isSelected(row)\n ? 'border-gradient-primary-start bg-gradient-primary-start/5'\n : 'border-border-default hover:border-border-interactive bg-bg-primary'\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: row, selected: isSelected(row) }\"\n ></ng-container>\n </button>\n }\n @if (!table.dataSource.data.length) {\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n }\n }\n </div>\n <!-- No (page) binding: ngAfterViewInit hands this paginator to the table,\n whose own BaseTable subscription (running after this child's hook)\n wires page events \u2014 a binding here would double-fetch every change. -->\n <mat-paginator\n class=\"mt-normal\"\n [length]=\"table.total\"\n [pageSize]=\"table.pageSize\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n ></mat-paginator>\n </div>\n\n <!-- Detail pane -->\n <div class=\"w-full lg:flex-1 min-w-0\">\n @if (table.selected) {\n @if (table.detailBusy) {\n <fx-ui-skeleton-detail [cards]=\"skeletonCards()\"></fx-ui-skeleton-detail>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"detailTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: table.detail, selected: table.selected }\"\n ></ng-container>\n }\n } @else {\n <div class=\"card-common flex items-center justify-center h-[300px]\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n </div>\n</div>\n", styles: [".fx-md-list{width:100%}@media(min-width:1080px){.fx-md-list{width:var(--fx-md-list-width, 420px);flex-shrink:0}}\n"] }]
4577
4027
  }], propDecorators: { table: [{
4578
4028
  type: Input
4579
- }], listWidth: [{
4580
- type: Input
4581
- }], maxListHeight: [{
4582
- type: Input
4583
- }], pageSizeOptions: [{
4584
- type: Input
4585
- }], emptyMessage: [{
4586
- type: Input
4587
- }], listLabel: [{
4588
- type: Input
4589
- }], skeletonCards: [{
4590
- type: Input
4591
- }], rowTemplate: [{
4592
- type: ContentChild,
4593
- args: ['row']
4594
- }], detailTemplate: [{
4595
- type: ContentChild,
4596
- args: ['detail']
4597
- }], paginator: [{
4598
- type: ViewChild,
4599
- args: [MatPaginator]
4600
- }] } });
4029
+ }], listWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "listWidth", required: false }] }], maxListHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxListHeight", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], listLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "listLabel", required: false }] }], skeletonCards: [{ type: i0.Input, args: [{ isSignal: true, alias: "skeletonCards", required: false }] }], rowTemplate: [{ type: i0.ContentChild, args: ['row', { isSignal: true }] }], detailTemplate: [{ type: i0.ContentChild, args: ['detail', { isSignal: true }] }], paginator: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatPaginator), { isSignal: true }] }] } });
4030
+
4031
+ /**
4032
+ * Row-action dropdown wrapper over mat-menu (behavior-layer rule, Playbook
4033
+ * §5.1 — apps never import @angular/material directly). Project the trigger
4034
+ * content; items render from [items] and come back through (select).
4035
+ *
4036
+ * <fx-ui-menu [items]="actions" (select)="onAction($event)">
4037
+ * <fx-ui-hero-icon icon="ellipsis-vertical" [size]="20" />
4038
+ * </fx-ui-menu>
4039
+ */
4040
+ class MenuComponent {
4041
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
4042
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
4043
+ /** Accessible name for the trigger button. */
4044
+ ariaLabel = input('Open menu', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
4045
+ select = output();
4046
+ toneClass(item) {
4047
+ switch (item.tone) {
4048
+ case 'critical':
4049
+ case 'danger':
4050
+ return 'text-danger';
4051
+ case 'warning':
4052
+ return 'text-warning';
4053
+ case 'success':
4054
+ return 'text-success';
4055
+ case 'information':
4056
+ return 'text-information';
4057
+ default:
4058
+ return 'text-text-primary';
4059
+ }
4060
+ }
4061
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4062
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: MenuComponent, isStandalone: true, selector: "fx-ui-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { select: "select" }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"inline-flex items-center justify-center rounded-lg p-1 hover:bg-bg-hover transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n [matMenuTriggerFor]=\"menu\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n <ng-content></ng-content>\n</button>\n\n<mat-menu #menu=\"matMenu\">\n @for (item of items(); track item.label) {\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"item.disabled\"\n (click)=\"select.emit(item)\"\n >\n <span class=\"flex items-center gap-normal\" [class]=\"toneClass(item)\">\n @if (item.icon) {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"18\"></fx-ui-hero-icon>\n }\n <span>{{ item.label }}</span>\n </span>\n </button>\n }\n</mat-menu>\n", dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1$4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4063
+ }
4064
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MenuComponent, decorators: [{
4065
+ type: Component,
4066
+ args: [{ selector: 'fx-ui-menu', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatMenuModule, HeroIconComponent], template: "<button\n type=\"button\"\n class=\"inline-flex items-center justify-center rounded-lg p-1 hover:bg-bg-hover transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n [matMenuTriggerFor]=\"menu\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n <ng-content></ng-content>\n</button>\n\n<mat-menu #menu=\"matMenu\">\n @for (item of items(); track item.label) {\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"item.disabled\"\n (click)=\"select.emit(item)\"\n >\n <span class=\"flex items-center gap-normal\" [class]=\"toneClass(item)\">\n @if (item.icon) {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"18\"></fx-ui-hero-icon>\n }\n <span>{{ item.label }}</span>\n </span>\n </button>\n }\n</mat-menu>\n" }]
4067
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], select: [{ type: i0.Output, args: ["select"] }] } });
4601
4068
 
4602
4069
  const FX_COMPONENTS = [
4603
4070
  InputComponent,
@@ -4616,12 +4083,9 @@ const FX_COMPONENTS = [
4616
4083
  ToastComponent,
4617
4084
  ToastContainerComponent,
4618
4085
  TagComponent,
4619
- ChartComponent,
4620
4086
  SliderComponent,
4621
4087
  SwitchComponent,
4622
- RichTextAreaComponent,
4623
4088
  SkeletonTableLoadingComponent,
4624
- FlowConnection,
4625
4089
  CircleProgressBar,
4626
4090
  TreeDiagram,
4627
4091
  TableCell,
@@ -4637,134 +4101,61 @@ const FX_COMPONENTS = [
4637
4101
  InfoFieldComponent,
4638
4102
  SeverityBadgesComponent,
4639
4103
  MasterDetailComponent,
4104
+ MenuComponent,
4640
4105
  ];
4641
4106
 
4642
- class ConfirmationDialogComponent {
4643
- ref;
4644
- bindings;
4645
- loading = false;
4646
- title = '';
4647
- message = '';
4648
- cancelLabel = 'Cancel';
4649
- confirmLabel = 'Submit';
4650
- constructor(ref, bindings) {
4651
- this.ref = ref;
4652
- this.bindings = bindings;
4653
- this.title = _.get(bindings, 'title');
4654
- this.message = _.get(bindings, 'message');
4655
- this.cancelLabel = _.get(bindings, 'cancelLabel');
4656
- this.confirmLabel = _.get(bindings, 'confirmLabel');
4657
- }
4658
- async accept() {
4659
- this.loading = true;
4660
- if (_.get(this.bindings, 'callback')) {
4661
- await this.bindings.callback();
4662
- this.loading = false;
4663
- }
4664
- this.ref.close(true);
4665
- }
4666
- cancel() {
4667
- this.ref.close(false);
4668
- }
4669
- 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 });
4670
- 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 mat-dialog-title 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.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { 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", "type", "ariaLabel"], outputs: ["clicked"] }] });
4671
- }
4672
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ConfirmationDialogComponent, decorators: [{
4673
- type: Component,
4674
- args: [{ selector: 'fx-ui-confirmation-dialog', standalone: false, template: "<div animate.enter=\"fade-in-animation\" class=\"dialog-container\">\n <h1 mat-dialog-title 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" }]
4675
- }], ctorParameters: () => [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
4676
- type: Inject,
4677
- args: [MAT_DIALOG_DATA]
4678
- }] }] });
4679
-
4680
4107
  const DIALOGS_COMPONENT = [
4681
4108
  ConfirmationDialogComponent
4682
4109
  ];
4683
4110
 
4684
- const MY_MOMENT_FORMATS = {
4685
- parseInput: 'YYYY-MM-DD',
4686
- fullPickerInput: 'YYYY-MM-DD HH:mm',
4687
- datePickerInput: 'YYYY-MM-DD',
4688
- timePickerInput: 'HH:mm',
4689
- monthYearLabel: 'MMM YYYY',
4690
- dateA11yLabel: 'LL',
4691
- monthYearA11yLabel: 'MMMM YYYY',
4692
- };
4111
+ /**
4112
+ * Compatibility barrel over the (now standalone) core components.
4113
+ *
4114
+ * Deliberately NOT re-exported anymore: Angular Material —
4115
+ * Material is a behavior layer that stays an
4116
+ * implementation detail of this lib (Playbook §5.1); each standalone
4117
+ * component imports what it needs itself. Apps consume fx-ui-* only.
4118
+ *
4119
+ * Heavy components live in secondary entry points and are not part of this
4120
+ * barrel: @foxeltech/angular-ui/chart, /flow, /rich-text.
4121
+ */
4693
4122
  class UiModule {
4694
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
4695
- 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, MasterDetailComponent, ConfirmationDialogComponent], imports: [CommonModule,
4696
- FormsModule,
4123
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
4124
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.20", ngImport: i0, type: UiModule, imports: [FormsModule,
4697
4125
  ReactiveFormsModule,
4698
4126
  RouterModule,
4699
- OwlDateTimeModule,
4700
- OwlNativeDateTimeModule,
4701
- OwlMomentDateTimeModule,
4702
4127
  HasPermissionDirective,
4703
- TrimOnBlurDirective,
4704
- NgHeroiconsModule, i39.VflowComponent, i39.HandleComponent, i39.ResizableComponent, i39.SelectableDirective, i39.MiniMapComponent, i39.NodeToolbarComponent, i39.CustomTemplateEdgeComponent, i39.DragHandleDirective, i39.ConnectionControllerDirective, i39.NodeHtmlTemplateDirective, i39.NodeSvgTemplateDirective, i39.GroupNodeTemplateDirective, i39.EdgeLabelHtmlTemplateDirective, i39.EdgeTemplateDirective, i39.ConnectionTemplateDirective, i39.HandleTemplateDirective, i1$5.NgxEchartsModule, i3.MatSelectModule, i42.MatRadioModule, i43.MatButtonModule, i44.MatIconModule, i45.MatPaginatorModule, i46.MatTableModule, i47.MatSnackBarModule, i1$2.MatDialogModule, i49.MatCheckboxModule, i50.MatCardModule, i51.MatDatepickerModule, i52.MatTimepickerModule, i53.MatBadgeModule, i54.MatExpansionModule, i55.MatFormFieldModule, i56.MatMenuModule, i57.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, MasterDetailComponent, ConfirmationDialogComponent,
4705
- // Module
4706
- FormsModule,
4128
+ TrimOnBlurDirective, InputComponent, SelectComponent, RadioButtonComponent, CheckboxComponent, DndUploadComponent, ButtonComponent, RadioButtonToggleComponent, DatetimePicker, LoadingPanel, SearchBarComponent, TabGroupComponent, TabComponent, HeroIconComponent, ToastComponent, ToastContainerComponent, TagComponent, SliderComponent, SwitchComponent, SkeletonTableLoadingComponent, CircleProgressBar, TreeDiagram, TableCell, KanbanBoardComponent, DrawerComponent, SkeletonListComponent, SkeletonDetailComponent, StatCardsComponent, EmptyStateComponent, FilterChipsComponent, MeterComponent, SectionCardComponent, InfoFieldComponent, SeverityBadgesComponent, MasterDetailComponent, MenuComponent, ConfirmationDialogComponent], exports: [InputComponent, SelectComponent, RadioButtonComponent, CheckboxComponent, DndUploadComponent, ButtonComponent, RadioButtonToggleComponent, DatetimePicker, LoadingPanel, SearchBarComponent, TabGroupComponent, TabComponent, HeroIconComponent, ToastComponent, ToastContainerComponent, TagComponent, SliderComponent, SwitchComponent, SkeletonTableLoadingComponent, CircleProgressBar, TreeDiagram, TableCell, KanbanBoardComponent, DrawerComponent, SkeletonListComponent, SkeletonDetailComponent, StatCardsComponent, EmptyStateComponent, FilterChipsComponent, MeterComponent, SectionCardComponent, InfoFieldComponent, SeverityBadgesComponent, MasterDetailComponent, MenuComponent, ConfirmationDialogComponent, FormsModule,
4707
4129
  ReactiveFormsModule,
4708
4130
  RouterModule,
4709
- OwlDateTimeModule,
4710
- OwlNativeDateTimeModule,
4711
4131
  HasPermissionDirective,
4712
- NgHeroiconsModule, i3.MatSelectModule, i42.MatRadioModule, i43.MatButtonModule, i44.MatIconModule, i45.MatPaginatorModule, i46.MatTableModule, i47.MatSnackBarModule, i1$2.MatDialogModule, i49.MatCheckboxModule, i50.MatCardModule, i51.MatDatepickerModule, i52.MatTimepickerModule, i53.MatBadgeModule, i54.MatExpansionModule, i55.MatFormFieldModule, i56.MatMenuModule, i57.MatTooltipModule, i2$3.DragDropModule] });
4713
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, providers: [
4714
- importProvidersFrom(NgHeroiconsModule.forRoot()),
4715
- { provide: OWL_DATE_TIME_FORMATS, useValue: MY_MOMENT_FORMATS },
4716
- ], imports: [CommonModule,
4717
- FormsModule,
4132
+ TrimOnBlurDirective] });
4133
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiModule, imports: [FormsModule,
4718
4134
  ReactiveFormsModule,
4719
- RouterModule,
4720
- OwlDateTimeModule,
4721
- OwlNativeDateTimeModule,
4722
- OwlMomentDateTimeModule,
4723
- NgHeroiconsModule, i39.VflowComponent, i39.HandleComponent, i39.ResizableComponent, i39.MiniMapComponent, i39.NodeToolbarComponent, i39.CustomTemplateEdgeComponent, NgxEchartsModule.forRoot({ echarts: () => import('echarts') }), MATERIAL_MODULE,
4724
- // Module
4725
- FormsModule,
4135
+ RouterModule, SelectComponent, DatetimePicker, MasterDetailComponent, MenuComponent, FormsModule,
4726
4136
  ReactiveFormsModule,
4727
- RouterModule,
4728
- OwlDateTimeModule,
4729
- OwlNativeDateTimeModule,
4730
- NgHeroiconsModule, i3.MatSelectModule, i42.MatRadioModule, i43.MatButtonModule, i44.MatIconModule, i45.MatPaginatorModule, i46.MatTableModule, i47.MatSnackBarModule, i1$2.MatDialogModule, i49.MatCheckboxModule, i50.MatCardModule, i51.MatDatepickerModule, i52.MatTimepickerModule, i53.MatBadgeModule, i54.MatExpansionModule, i55.MatFormFieldModule, i56.MatMenuModule, i57.MatTooltipModule, i2$3.DragDropModule] });
4137
+ RouterModule] });
4731
4138
  }
4732
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: UiModule, decorators: [{
4139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiModule, decorators: [{
4733
4140
  type: NgModule,
4734
4141
  args: [{
4735
- declarations: [...FX_COMPONENTS, ...DIALOGS_COMPONENT],
4736
4142
  imports: [
4737
- CommonModule,
4738
4143
  FormsModule,
4739
4144
  ReactiveFormsModule,
4740
4145
  RouterModule,
4741
- OwlDateTimeModule,
4742
- OwlNativeDateTimeModule,
4743
- OwlMomentDateTimeModule,
4744
4146
  HasPermissionDirective,
4745
4147
  TrimOnBlurDirective,
4746
- NgHeroiconsModule,
4747
- ...Vflow,
4748
- NgxEchartsModule.forRoot({ echarts: () => import('echarts') }),
4749
- ...MATERIAL_MODULE,
4148
+ ...FX_COMPONENTS,
4149
+ ...DIALOGS_COMPONENT,
4750
4150
  ],
4751
4151
  exports: [
4752
- // Component
4753
4152
  ...FX_COMPONENTS,
4754
4153
  ...DIALOGS_COMPONENT,
4755
- // Module
4756
4154
  FormsModule,
4757
4155
  ReactiveFormsModule,
4758
4156
  RouterModule,
4759
- OwlDateTimeModule,
4760
- OwlNativeDateTimeModule,
4761
4157
  HasPermissionDirective,
4762
- NgHeroiconsModule,
4763
- ...MATERIAL_MODULE,
4764
- ],
4765
- providers: [
4766
- importProvidersFrom(NgHeroiconsModule.forRoot()),
4767
- { provide: OWL_DATE_TIME_FORMATS, useValue: MY_MOMENT_FORMATS },
4158
+ TrimOnBlurDirective,
4768
4159
  ],
4769
4160
  }]
4770
4161
  }] });
@@ -4777,5 +4168,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4777
4168
  * Generated bundle index. Do not edit.
4778
4169
  */
4779
4170
 
4780
- export { AuthInterceptor, AuthStateService, BaseComponent, BaseDialogComponent, BaseMasterDetailComponent, 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, MasterDetailComponent, 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 };
4171
+ export { AuthInterceptor, AuthStateService, BaseComponent, BaseDialogComponent, BaseMasterDetailComponent, BaseResolver, BaseTableComponent, BreadcrumbService, ButtonComponent, CheckboxComponent, CircleProgressBar, ConfirmationDialogComponent, DatetimePicker, DndUploadComponent, DrawerComponent, EmptyStateComponent, FX_ICON_SPRITE_URL, FilterChipsComponent, FxComponent, FxDialogService, FxLoadingService, FxStorageService, FxToastrService, FxUtils, FxValidators, HasPermissionDirective, HeroIconComponent, HttpLoaderFactory, HttpWrapper, InfoFieldComponent, InputComponent, KanbanBoardComponent, LoadingPanel, MasterDetailComponent, MenuComponent, MeterComponent, NotificationService, PermissionGuard, PermissionService, RadioButtonComponent, RadioButtonToggleComponent, RealtimeTableSync, 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 };
4781
4172
  //# sourceMappingURL=foxeltech-angular-ui.mjs.map