@acorex/platform 19.3.0-next.5 → 19.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/common/lib/app/index.d.ts +0 -1
  2. package/common/lib/common.module.d.ts +1 -1
  3. package/common/lib/configs/app.config.d.ts +12 -3
  4. package/common/lib/home-page/home-page.service.d.ts +6 -0
  5. package/common/lib/layout/logo/logo.component.d.ts +4 -0
  6. package/common/lib/settings/settings.service.d.ts +4 -1
  7. package/common/lib/utils/index.d.ts +0 -1
  8. package/common/lib/utils/regional-util.service.d.ts +2 -2
  9. package/common/lib/utils/regional.types.d.ts +6 -16
  10. package/core/lib/index.d.ts +1 -0
  11. package/{common/lib/app → core/lib/startup}/app-startup.service.d.ts +1 -5
  12. package/core/lib/startup/app-startup.types.d.ts +6 -0
  13. package/core/lib/startup/index.d.ts +2 -0
  14. package/core/lib/types/logo.types.d.ts +5 -9
  15. package/fesm2022/acorex-platform-auth.mjs +5 -1
  16. package/fesm2022/acorex-platform-auth.mjs.map +1 -1
  17. package/fesm2022/acorex-platform-common.mjs +130 -218
  18. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  19. package/fesm2022/acorex-platform-core.mjs +42 -13
  20. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-builder.mjs +17 -0
  22. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  23. package/fesm2022/acorex-platform-layout-components.mjs +247 -0
  24. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -0
  25. package/fesm2022/acorex-platform-layout-designer.mjs +2 -2
  26. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  27. package/fesm2022/acorex-platform-layout-entity.mjs +44 -20
  28. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  29. package/fesm2022/acorex-platform-layout-search.mjs +4 -3
  30. package/fesm2022/acorex-platform-layout-search.mjs.map +1 -1
  31. package/fesm2022/acorex-platform-layout-setting.mjs +5 -4
  32. package/fesm2022/acorex-platform-layout-setting.mjs.map +1 -1
  33. package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-CuyWAi6X.mjs → acorex-platform-themes-default-entity-master-list-view.component-Ol8haGqF.mjs} +5 -4
  34. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-Ol8haGqF.mjs.map +1 -0
  35. package/fesm2022/acorex-platform-themes-default.mjs +18 -20
  36. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  37. package/fesm2022/acorex-platform-themes-shared.mjs +22 -18
  38. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  39. package/fesm2022/{acorex-platform-widgets-tabular-data-edit-popup.component-CybYV1Kf.mjs → acorex-platform-widgets-tabular-data-edit-popup.component-1IseEVXQ.mjs} +2 -2
  40. package/fesm2022/acorex-platform-widgets-tabular-data-edit-popup.component-1IseEVXQ.mjs.map +1 -0
  41. package/fesm2022/acorex-platform-widgets.mjs +35 -3775
  42. package/fesm2022/acorex-platform-widgets.mjs.map +1 -1
  43. package/layout/builder/lib/builder/context-store.service.d.ts +2 -1
  44. package/layout/builder/lib/builder/widget-base.component.d.ts +1 -0
  45. package/layout/builder/lib/builder/widget-container.component.d.ts +1 -0
  46. package/layout/builder/lib/builder/widget-map.d.ts +1 -0
  47. package/layout/builder/lib/builder/widget-renderer.directive.d.ts +1 -0
  48. package/layout/components/README.md +3 -0
  49. package/layout/components/index.d.ts +1 -0
  50. package/layout/components/lib/user-avatar/index.d.ts +4 -0
  51. package/layout/components/lib/user-avatar/user-avatar.component.d.ts +27 -0
  52. package/layout/components/lib/user-avatar/user-avatar.provider.d.ts +3 -0
  53. package/layout/components/lib/user-avatar/user-avatar.service.d.ts +42 -0
  54. package/layout/components/lib/user-avatar/user-avatar.types.d.ts +12 -0
  55. package/layout/entity/lib/entity-master-single.viewmodel.d.ts +1 -0
  56. package/layout/entity/lib/entity.module.d.ts +1 -1
  57. package/layout/entity/lib/widgets/lookup-widget/lookup-widget-column.component.d.ts +1 -1
  58. package/layout/entity/lib/widgets/lookup-widget/lookup-widget-edit.component.d.ts +1 -0
  59. package/layout/entity/lib/widgets/lookup-widget/lookup-widget.config.d.ts +0 -5
  60. package/layout/search/lib/search.module.d.ts +1 -1
  61. package/layout/setting/lib/settings.module.d.ts +1 -1
  62. package/package.json +8 -2
  63. package/themes/default/lib/layouts/root-layout/components/header/header.component.d.ts +12 -3
  64. package/themes/default/lib/layouts/root-layout/horizontal/horizontal-layout.component.d.ts +12 -6
  65. package/themes/default/lib/layouts/root-layout/root-layout.component.d.ts +2 -1
  66. package/themes/default/lib/layouts/root-layout/vertical/vertical-layout.component.d.ts +14 -5
  67. package/themes/shared/lib/shared.module.d.ts +1 -1
  68. package/widgets/lib/widgets/index.d.ts +0 -9
  69. package/common/lib/utils/data-generator.d.ts +0 -26
  70. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-CuyWAi6X.mjs.map +0 -1
  71. package/fesm2022/acorex-platform-widgets-tabular-data-edit-popup.component-CybYV1Kf.mjs.map +0 -1
  72. package/widgets/lib/widgets/charts/bar-chart/bar-chart-widget.component.d.ts +0 -41
  73. package/widgets/lib/widgets/charts/bar-chart/bar-chart-widget.config.d.ts +0 -7
  74. package/widgets/lib/widgets/charts/bar-chart/bar-chart.type.d.ts +0 -34
  75. package/widgets/lib/widgets/charts/bar-chart/index.d.ts +0 -2
  76. package/widgets/lib/widgets/charts/chart.type.d.ts +0 -3
  77. package/widgets/lib/widgets/charts/clock-calendar/clock-calendar-widget.component.d.ts +0 -40
  78. package/widgets/lib/widgets/charts/clock-calendar/clock-calendar-widget.config.d.ts +0 -7
  79. package/widgets/lib/widgets/charts/clock-calendar/clock-calendar.types.d.ts +0 -50
  80. package/widgets/lib/widgets/charts/clock-calendar/index.d.ts +0 -3
  81. package/widgets/lib/widgets/charts/donut-chart/donut-chart-widget.component.d.ts +0 -58
  82. package/widgets/lib/widgets/charts/donut-chart/donut-chart-widget.config.d.ts +0 -7
  83. package/widgets/lib/widgets/charts/donut-chart/donut-chart.type.d.ts +0 -67
  84. package/widgets/lib/widgets/charts/donut-chart/index.d.ts +0 -2
  85. package/widgets/lib/widgets/charts/gauge-chart/gauge-chart-widget.component.d.ts +0 -69
  86. package/widgets/lib/widgets/charts/gauge-chart/gauge-chart-widget.config.d.ts +0 -7
  87. package/widgets/lib/widgets/charts/gauge-chart/gauge-chart.type.d.ts +0 -29
  88. package/widgets/lib/widgets/charts/gauge-chart/index.d.ts +0 -3
  89. package/widgets/lib/widgets/charts/notification/index.d.ts +0 -3
  90. package/widgets/lib/widgets/charts/notification/notification-widget.component.d.ts +0 -54
  91. package/widgets/lib/widgets/charts/notification/notification-widget.config.d.ts +0 -10
  92. package/widgets/lib/widgets/charts/notification/notification.type.d.ts +0 -47
  93. package/widgets/lib/widgets/charts/shared/chart-base.component.d.ts +0 -44
  94. package/widgets/lib/widgets/charts/shared/chart-base.type.d.ts +0 -37
  95. package/widgets/lib/widgets/charts/shared/components/chart-tooltip/chart-tooltip.component.d.ts +0 -28
  96. package/widgets/lib/widgets/charts/shared/components/chart-tooltip/index.d.ts +0 -1
  97. package/widgets/lib/widgets/charts/sticky-note/index.d.ts +0 -2
  98. package/widgets/lib/widgets/charts/sticky-note/sticky-note-widget.component.d.ts +0 -21
  99. package/widgets/lib/widgets/charts/sticky-note/sticky-note-widget.config.d.ts +0 -7
  100. package/widgets/lib/widgets/charts/tasklist/index.d.ts +0 -3
  101. package/widgets/lib/widgets/charts/tasklist/tasklist-widget.component.d.ts +0 -34
  102. package/widgets/lib/widgets/charts/tasklist/tasklist-widget.config.d.ts +0 -7
  103. package/widgets/lib/widgets/charts/tasklist/tasklist.type.d.ts +0 -36
  104. package/widgets/lib/widgets/charts/weather/index.d.ts +0 -4
  105. package/widgets/lib/widgets/charts/weather/weather-services/index.d.ts +0 -3
  106. package/widgets/lib/widgets/charts/weather/weather-services/weather-api.abstract.d.ts +0 -174
  107. package/widgets/lib/widgets/charts/weather/weather-services/weather-api.key.d.ts +0 -2
  108. package/widgets/lib/widgets/charts/weather/weather-services/weather-api.mock.service.d.ts +0 -47
  109. package/widgets/lib/widgets/charts/weather/weather-services/weather-api.service.d.ts +0 -48
  110. package/widgets/lib/widgets/charts/weather/weather-widget.component.d.ts +0 -109
  111. package/widgets/lib/widgets/charts/weather/weather-widget.config.d.ts +0 -14
  112. package/widgets/lib/widgets/charts/weather/weather.module.d.ts +0 -11
@@ -10,9 +10,9 @@ import { AXDecoratorModule } from '@acorex/components/decorators';
10
10
  import * as i2 from '@acorex/components/loading';
11
11
  import { AXLoadingModule } from '@acorex/components/loading';
12
12
  import * as i1$1 from '@angular/common';
13
- import { CommonModule, DatePipe } from '@angular/common';
13
+ import { CommonModule } from '@angular/common';
14
14
  import * as i0 from '@angular/core';
15
- import { computed, EventEmitter, ChangeDetectionStrategy, Component, inject, afterNextRender, HostBinding, signal, ViewEncapsulation, InjectionToken, effect, ViewChild, untracked, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef, viewChild, ElementRef, afterRender, NgZone, model, input, linkedSignal, Injector, runInInjectionContext, Directive, output, HostListener, Injectable, NgModule, importProvidersFrom } from '@angular/core';
15
+ import { computed, EventEmitter, ChangeDetectionStrategy, Component, inject, afterNextRender, HostBinding, signal, ViewEncapsulation, InjectionToken, effect, ViewChild, untracked, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef, viewChild, ElementRef, afterRender, NgZone, model, input, linkedSignal, HostListener, importProvidersFrom, NgModule } from '@angular/core';
16
16
  import * as i1 from '@acorex/components/check-box';
17
17
  import { AXCheckBoxModule } from '@acorex/components/check-box';
18
18
  import * as i4 from '@acorex/components/form';
@@ -31,7 +31,7 @@ import { AXTextBoxModule } from '@acorex/components/text-box';
31
31
  import * as i5$1 from '@acorex/core/translation';
32
32
  import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
33
33
  import { AXBasePageComponent } from '@acorex/components/page';
34
- import { AXDateTimeFormatter, AXDateTimeModule, AXCalendarService } from '@acorex/core/date-time';
34
+ import { AXDateTimeFormatter, AXCalendarService } from '@acorex/core/date-time';
35
35
  import * as i3$2 from '@acorex/components/datetime-box';
36
36
  import { AXDateTimeBoxModule } from '@acorex/components/datetime-box';
37
37
  import * as i5$2 from '@acorex/components/text-area';
@@ -39,8 +39,7 @@ import { AXTextAreaModule } from '@acorex/components/text-area';
39
39
  import { set, isNumber, castArray, cloneDeep, isEqual, sum, get } from 'lodash-es';
40
40
  import * as i4$1 from '@acorex/components/tabs';
41
41
  import { AXTabsModule } from '@acorex/components/tabs';
42
- import * as i2$9 from '@acorex/core/format';
43
- import { AXFormatService, AXFormatModule } from '@acorex/core/format';
42
+ import { AXFormatService } from '@acorex/core/format';
44
43
  import * as i1$4 from '@acorex/components/number-box';
45
44
  import { AXNumberBoxModule } from '@acorex/components/number-box';
46
45
  import * as i3$3 from '@acorex/components/password-box';
@@ -55,7 +54,7 @@ import * as i5$3 from '@acorex/components/search-box';
55
54
  import { AXSearchBoxModule } from '@acorex/components/search-box';
56
55
  import * as i2$4 from '@acorex/components/selection-list';
57
56
  import { AXSelectionListModule } from '@acorex/components/selection-list';
58
- import { first, Subscription, interval, map, Observable, catchError, throwError, switchMap } from 'rxjs';
57
+ import { first, Subscription } from 'rxjs';
59
58
  import { AXFileService } from '@acorex/core/file';
60
59
  import * as i6 from '@acorex/components/dropdown';
61
60
  import { AXDropdownModule } from '@acorex/components/dropdown';
@@ -71,7 +70,7 @@ import { AXImageModule } from '@acorex/components/image';
71
70
  import * as i1$6 from '@acorex/components/map';
72
71
  import { AXMapModule } from '@acorex/components/map';
73
72
  import * as i1$7 from '@acorex/components/grid-layout-builder';
74
- import { AXGridLayoutContainerComponent, AXGridLayoutBuilderModule, AXGridLayoutWidgetComponent } from '@acorex/components/grid-layout-builder';
73
+ import { AXGridLayoutContainerComponent, AXGridLayoutBuilderModule } from '@acorex/components/grid-layout-builder';
75
74
  import { AXPDesignerService, AXPWidgetDesignerRendererDirective, AXPDesignerGridDrawerComponent, AXPDesignerAddWidgetMiniButtonComponent } from '@acorex/platform/layout/designer';
76
75
  import * as i1$8 from '@acorex/components/button-group';
77
76
  import { AXButtonGroupModule } from '@acorex/components/button-group';
@@ -81,10 +80,6 @@ import * as i2$8 from '@acorex/components/color-box';
81
80
  import { AXColorBoxModule } from '@acorex/components/color-box';
82
81
  import * as i1$9 from '@acorex/components/popover';
83
82
  import { AXPopoverComponent, AXPopoverModule } from '@acorex/components/popover';
84
- import { AXTagModule } from '@acorex/components/tag';
85
- import * as i5$4 from '@acorex/components/avatar';
86
- import { AXAvatarModule } from '@acorex/components/avatar';
87
- import { HttpClient, HttpClientModule } from '@angular/common/http';
88
83
  import * as i1$a from '@acorex/components/cron-job';
89
84
  import { AXCronJobModule } from '@acorex/components/cron-job';
90
85
  import * as i1$b from '@acorex/components/qrcode';
@@ -1927,7 +1922,7 @@ class AXPDateTimeBoxWidgetEditComponent extends AXPValueWidgetComponent {
1927
1922
  ></ax-button>
1928
1923
  }
1929
1924
  </div>
1930
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: AXFormModule }, { kind: "directive", type: i4.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXDateTimeBoxModule }, { kind: "component", type: i3$2.AXDateTimeBoxComponent, selector: "ax-datetime-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "depth", "id", "type", "look", "holidayDates", "allowTyping", "format"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "onOpened", "onClosed", "readonlyChange", "disabledChange", "formatChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1925
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: AXFormModule }, { kind: "directive", type: i4.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXDateTimeBoxModule }, { kind: "component", type: i3$2.AXDateTimeBoxComponent, selector: "ax-datetime-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "depth", "id", "type", "look", "holidayDates", "allowTyping", "calendar", "picker", "format"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "onOpened", "onClosed", "readonlyChange", "disabledChange", "formatChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1931
1926
  }
1932
1927
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPDateTimeBoxWidgetEditComponent, decorators: [{
1933
1928
  type: Component,
@@ -6721,20 +6716,19 @@ class AXPToggleWidgetEditComponent extends AXPValueWidgetComponent {
6721
6716
  }
6722
6717
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPToggleWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
6723
6718
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPToggleWidgetEditComponent, isStandalone: true, selector: "axp-switch-widget-edit", host: { properties: { "class": "this.__class" } }, usesInheritance: true, ngImport: i0, template: `
6724
- <div class="ax-flex ax-flex-row ax-gap-2">
6725
- <ax-switch
6726
- [ngModel]="this.getValue()"
6727
- [disabled]="disabled()"
6728
- [readonly]="readonly()"
6729
- [color]="color()"
6730
- (onValueChanged)="handleValueChanged($event)">
6731
-
6719
+ <div class="ax-flex ax-items-center ax-gap-2">
6720
+ <ax-switch
6721
+ [ngModel]="this.getValue()"
6722
+ [disabled]="disabled()"
6723
+ [readonly]="readonly()"
6724
+ [color]="color()"
6725
+ (onValueChanged)="handleValueChanged($event)"
6726
+ >
6732
6727
  </ax-switch>
6733
- @if(label())
6734
- {
6735
- <ax-label [textContent]="label()"></ax-label>
6728
+ @if(label()) {
6729
+ <ax-label [textContent]="label()"></ax-label>
6736
6730
  }
6737
- </div>
6731
+ </div>
6738
6732
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXSwitchModule }, { kind: "component", type: i2$5.AXSwitchComponent, selector: "ax-switch", inputs: ["disabled", "readonly", "color", "tabIndex", "value", "name", "isLoading"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged", "readonlyChange", "disabledChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXLabelModule }, { kind: "component", type: i2$2.AXLabelComponent, selector: "ax-label", inputs: ["required", "for"], outputs: ["requiredChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6739
6733
  }
6740
6734
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPToggleWidgetEditComponent, decorators: [{
@@ -6742,20 +6736,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
6742
6736
  args: [{
6743
6737
  selector: 'axp-switch-widget-edit',
6744
6738
  template: `
6745
- <div class="ax-flex ax-flex-row ax-gap-2">
6746
- <ax-switch
6747
- [ngModel]="this.getValue()"
6748
- [disabled]="disabled()"
6749
- [readonly]="readonly()"
6750
- [color]="color()"
6751
- (onValueChanged)="handleValueChanged($event)">
6752
-
6739
+ <div class="ax-flex ax-items-center ax-gap-2">
6740
+ <ax-switch
6741
+ [ngModel]="this.getValue()"
6742
+ [disabled]="disabled()"
6743
+ [readonly]="readonly()"
6744
+ [color]="color()"
6745
+ (onValueChanged)="handleValueChanged($event)"
6746
+ >
6753
6747
  </ax-switch>
6754
- @if(label())
6755
- {
6756
- <ax-label [textContent]="label()"></ax-label>
6748
+ @if(label()) {
6749
+ <ax-label [textContent]="label()"></ax-label>
6757
6750
  }
6758
- </div>
6751
+ </div>
6759
6752
  `,
6760
6753
  changeDetection: ChangeDetectionStrategy.OnPush,
6761
6754
  imports: [CommonModule, FormsModule, AXFormModule, AXSwitchModule, AXValidationModule, AXLabelModule],
@@ -7879,7 +7872,7 @@ class AXPGalleryWidgetViewComponent extends AXPValueWidgetComponent {
7879
7872
  <small>No Media!</small>
7880
7873
  }
7881
7874
  </div>
7882
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$7.AXImageComponent, selector: "ax-image", inputs: ["overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7875
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$7.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7883
7876
  }
7884
7877
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPGalleryWidgetViewComponent, decorators: [{
7885
7878
  type: Component,
@@ -8416,7 +8409,7 @@ class AXPSignatureWidgetEditComponent extends AXPValueWidgetComponent {
8416
8409
  </div>
8417
8410
  }
8418
8411
  </div>
8419
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$7.AXImageComponent, selector: "ax-image", inputs: ["overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8412
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i5.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$7.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8420
8413
  }
8421
8414
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPSignatureWidgetEditComponent, decorators: [{
8422
8415
  type: Component,
@@ -8514,7 +8507,7 @@ class AXPSignatureWidgetViewComponent extends AXPValueWidgetComponent {
8514
8507
  <span>{{placeholder()}}</span>
8515
8508
  }
8516
8509
  </div>
8517
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$7.AXImageComponent, selector: "ax-image", inputs: ["overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8510
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$7.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8518
8511
  }
8519
8512
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPSignatureWidgetViewComponent, decorators: [{
8520
8513
  type: Component,
@@ -12393,3721 +12386,6 @@ const AXPRequiredValidationWidget = {
12393
12386
  },
12394
12387
  };
12395
12388
 
12396
- /**
12397
- * Common base types and utilities for all chart components
12398
- */
12399
- /**
12400
- * Color utility functions for charts
12401
- */
12402
- const AXPChartColors = {
12403
- // Modern color palette suitable for data visualization
12404
- defaultColors: [
12405
- '#4361ee', // Blue
12406
- '#3a0ca3', // Purple
12407
- '#7209b7', // Violet
12408
- '#f72585', // Pink
12409
- '#4cc9f0', // Light Blue
12410
- '#4895ef', // Sky Blue
12411
- '#560bad', // Deep Purple
12412
- '#f15bb5', // Light Pink
12413
- '#00bbf9', // Cyan
12414
- '#00f5d4', // Teal
12415
- ],
12416
- // Get a color from the palette by index with wraparound
12417
- getColor: (index, customPalette) => {
12418
- const palette = customPalette || AXPChartColors.defaultColors;
12419
- return palette[index % palette.length];
12420
- },
12421
- // Generate a continuous color palette from a base color
12422
- generatePalette: (baseColor, count) => {
12423
- // Simple implementation - in real usage you might want a more sophisticated algorithm
12424
- const colors = [];
12425
- for (let i = 0; i < count; i++) {
12426
- // This is simplistic - a real implementation would use HSL or other color manipulation
12427
- const opacity = 0.4 + (0.6 * i) / count;
12428
- colors.push(`${baseColor}${Math.floor(opacity * 255)
12429
- .toString(16)
12430
- .padStart(2, '0')}`);
12431
- }
12432
- return colors;
12433
- },
12434
- };
12435
- /**
12436
- * Shared utility for loading D3.js dynamically
12437
- */
12438
- async function loadD3() {
12439
- try {
12440
- // Dynamic import of d3 without relying on d3 being imported at the top
12441
- return await import('d3');
12442
- }
12443
- catch (error) {
12444
- console.error('Failed to load D3.js:', error);
12445
- throw error;
12446
- }
12447
- }
12448
-
12449
- /**
12450
- * Base component class for all chart components with common chart functionality
12451
- */
12452
- class AXPChartBaseComponent extends AXPValueWidgetComponent {
12453
- // Constructor with protected change detector
12454
- constructor(cdr) {
12455
- super();
12456
- this.cdr = cdr;
12457
- // Get injector for running effects
12458
- this.injector = inject(Injector);
12459
- // Track component lifecycle
12460
- this.isInitialized = signal(false);
12461
- this.isRendered = signal(false);
12462
- // Internal chart data storage with fallback logic
12463
- this._internalData = signal(null);
12464
- // Accessor for chart data with fallback to getValue() or defaultValue
12465
- this.chartData = computed(() => {
12466
- if (this._internalData()) {
12467
- return this._internalData();
12468
- }
12469
- return this.getValue() || this.defaultValue;
12470
- });
12471
- // Options tracker for detecting changes
12472
- this._lastOptionsSnapshot = '';
12473
- // Store the effect cleanup function
12474
- this.effectRef = null;
12475
- }
12476
- ngOnInit() {
12477
- super.ngOnInit();
12478
- this.loadD3();
12479
- }
12480
- ngAfterViewInit() {
12481
- this.isRendered.set(true);
12482
- this.setupEffects();
12483
- }
12484
- ngOnDestroy() {
12485
- // Clean up effect if it exists
12486
- if (this.effectRef) {
12487
- this.effectRef.destroy();
12488
- }
12489
- this.cleanupChart();
12490
- }
12491
- /**
12492
- * Load D3.js library asynchronously
12493
- */
12494
- async loadD3() {
12495
- try {
12496
- this.d3 = await loadD3();
12497
- this.isInitialized.set(true);
12498
- // Initialize chart data once D3 is loaded
12499
- const initialData = this.getValue() || this.defaultValue;
12500
- if (initialData) {
12501
- this._internalData.set(initialData);
12502
- }
12503
- // Create chart once D3 is loaded and if we're already rendered
12504
- if (this.isRendered()) {
12505
- this.createChart();
12506
- }
12507
- }
12508
- catch (error) {
12509
- console.error('Error loading D3.js:', error);
12510
- }
12511
- }
12512
- /**
12513
- * Set up reactive effects to track data and option changes
12514
- */
12515
- setupEffects() {
12516
- // Run effect in injection context to avoid NG0203 error
12517
- this.effectRef = runInInjectionContext(this.injector, () => {
12518
- return effect(() => {
12519
- // Only update if D3 is loaded and component is rendered
12520
- if (!this.isInitialized() || !this.isRendered())
12521
- return;
12522
- // Track dependencies explicitly
12523
- const data = this.getValue();
12524
- const options = this.options();
12525
- // Store current options snapshot for comparison
12526
- const currentOptions = JSON.stringify(options);
12527
- const optionsChanged = currentOptions !== this._lastOptionsSnapshot;
12528
- this._lastOptionsSnapshot = currentOptions;
12529
- // Check if data changed
12530
- const dataChanged = data && JSON.stringify(data) !== JSON.stringify(this._internalData());
12531
- // Update internal data if it changed
12532
- if (dataChanged && data) {
12533
- this._internalData.set(data);
12534
- }
12535
- // Update chart if either data or options changed
12536
- if (dataChanged || optionsChanged) {
12537
- this.updateChart();
12538
- }
12539
- });
12540
- });
12541
- }
12542
- /**
12543
- * Get dimensions of the container element
12544
- */
12545
- getContainerDimensions(containerElement) {
12546
- if (!containerElement?.nativeElement) {
12547
- return { width: 300, height: 300 }; // Default fallback
12548
- }
12549
- const { clientWidth, clientHeight } = containerElement.nativeElement;
12550
- return {
12551
- width: clientWidth || 300,
12552
- height: clientHeight || 300,
12553
- };
12554
- }
12555
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPChartBaseComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
12556
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: AXPChartBaseComponent, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
12557
- }
12558
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPChartBaseComponent, decorators: [{
12559
- type: Directive
12560
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
12561
-
12562
- class AXPChartTooltipComponent {
12563
- constructor() {
12564
- this.data = input(null);
12565
- this.position = input({ x: 0, y: 0 });
12566
- this.visible = input(false);
12567
- /**
12568
- * Whether to show the tooltip's percentage badge
12569
- */
12570
- this.showPercentage = input(true);
12571
- /**
12572
- * Optional custom styling for the tooltip
12573
- */
12574
- this.style = input({});
12575
- }
12576
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPChartTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12577
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPChartTooltipComponent, isStandalone: true, selector: "ax-chart-tooltip", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, showPercentage: { classPropertyName: "showPercentage", publicName: "showPercentage", isSignal: true, isRequired: false, transformFunction: null }, style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (visible() && data()) {\n<div class=\"chart-tooltip\" [style.left.px]=\"position().x\" [style.top.px]=\"position().y\" [ngStyle]=\"style()\">\n <div class=\"chart-tooltip-title\">{{ data()!.title }}</div>\n <div class=\"chart-tooltip-content\">\n @if (data()!.color) {\n <div class=\"chart-tooltip-color\" [style.background-color]=\"data()!.color\"></div>\n }\n <div class=\"chart-tooltip-value\">{{ data()!.value }}</div>\n @if (showPercentage() && data()!.percentage) {\n <div class=\"chart-tooltip-percentage\">{{ data()!.percentage }}</div>\n }\n </div>\n</div>\n}\n", styles: [".chart-tooltip{position:absolute;pointer-events:none;background-color:rgba(33,33,33,.9);color:#fff;padding:.5rem .75rem;border-radius:.375rem;font-size:.8rem;z-index:10;box-shadow:0 4px 12px rgba(0,0,0,.15);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.1);transform:translate(10px,-50%);max-width:200px;font-family:var(--ax-font-family, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);transition:opacity .15s ease,transform .15s ease}.chart-tooltip-title{font-weight:600;padding-bottom:.5rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chart-tooltip-content{display:flex;justify-content:space-between;align-items:center;gap:.5rem}.chart-tooltip-color{width:10px;height:10px;border-radius:2px;flex-shrink:0;box-shadow:0 1px 2px rgba(0,0,0,.2)}.chart-tooltip-value{font-weight:500;flex-grow:1}.chart-tooltip-percentage{background-color:rgba(255,255,255,.2);padding:.125rem .375rem;border-radius:1rem;font-size:.7rem;font-weight:500;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12578
- }
12579
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPChartTooltipComponent, decorators: [{
12580
- type: Component,
12581
- args: [{ selector: 'ax-chart-tooltip', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible() && data()) {\n<div class=\"chart-tooltip\" [style.left.px]=\"position().x\" [style.top.px]=\"position().y\" [ngStyle]=\"style()\">\n <div class=\"chart-tooltip-title\">{{ data()!.title }}</div>\n <div class=\"chart-tooltip-content\">\n @if (data()!.color) {\n <div class=\"chart-tooltip-color\" [style.background-color]=\"data()!.color\"></div>\n }\n <div class=\"chart-tooltip-value\">{{ data()!.value }}</div>\n @if (showPercentage() && data()!.percentage) {\n <div class=\"chart-tooltip-percentage\">{{ data()!.percentage }}</div>\n }\n </div>\n</div>\n}\n", styles: [".chart-tooltip{position:absolute;pointer-events:none;background-color:rgba(33,33,33,.9);color:#fff;padding:.5rem .75rem;border-radius:.375rem;font-size:.8rem;z-index:10;box-shadow:0 4px 12px rgba(0,0,0,.15);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.1);transform:translate(10px,-50%);max-width:200px;font-family:var(--ax-font-family, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);transition:opacity .15s ease,transform .15s ease}.chart-tooltip-title{font-weight:600;padding-bottom:.5rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chart-tooltip-content{display:flex;justify-content:space-between;align-items:center;gap:.5rem}.chart-tooltip-color{width:10px;height:10px;border-radius:2px;flex-shrink:0;box-shadow:0 1px 2px rgba(0,0,0,.2)}.chart-tooltip-value{font-weight:500;flex-grow:1}.chart-tooltip-percentage{background-color:rgba(255,255,255,.2);padding:.125rem .375rem;border-radius:1rem;font-size:.7rem;font-weight:500;flex-shrink:0}\n"] }]
12582
- }] });
12583
-
12584
- class AXPBarChartWidgetViewComponent extends AXPChartBaseComponent {
12585
- constructor() {
12586
- super(...arguments);
12587
- this.barClick = output();
12588
- // Chart container reference
12589
- this.chartContainerEl = viewChild.required('chartContainer');
12590
- this.margin = { top: 20, right: 20, bottom: 30, left: 40 };
12591
- // Tooltip state
12592
- this._tooltipVisible = signal(false);
12593
- this._tooltipPosition = signal({ x: 0, y: 0 });
12594
- this._tooltipData = signal({
12595
- title: '',
12596
- value: '0',
12597
- percentage: '0%',
12598
- color: '',
12599
- });
12600
- // Tooltip accessors
12601
- this.tooltipVisible = computed(() => this._tooltipVisible());
12602
- this.tooltipPosition = computed(() => this._tooltipPosition());
12603
- this.tooltipData = computed(() => this._tooltipData());
12604
- // Bar appearance options
12605
- this.barWidth = computed(() => this.options()['barWidth'] ?? 80);
12606
- this.cornerRadius = computed(() => this.options()['cornerRadius'] ?? 4);
12607
- }
12608
- // Chart lifecycle methods
12609
- createChart() {
12610
- if (!this.d3 || !this.chartContainerEl()?.nativeElement)
12611
- return;
12612
- const containerElement = this.chartContainerEl().nativeElement;
12613
- const data = this.chartData() || [];
12614
- // Clear existing chart
12615
- this.d3.select(containerElement).selectAll('svg').remove();
12616
- // Early return if no data
12617
- if (!data.length) {
12618
- this.showNoDataMessage(containerElement);
12619
- return;
12620
- }
12621
- // Get options and setup dimensions
12622
- const options = this.options();
12623
- this.setupDimensions(containerElement, options);
12624
- // Create SVG container
12625
- this.svg = this.d3
12626
- .select(containerElement)
12627
- .append('svg')
12628
- .attr('width', this.width + this.margin.left + this.margin.right)
12629
- .attr('height', this.height + this.margin.top + this.margin.bottom);
12630
- // Create chart group with margins
12631
- this.chart = this.svg.append('g').attr('transform', `translate(${this.margin.left},${this.margin.top})`);
12632
- // Create scales and axes
12633
- this.setupScales(data);
12634
- this.createAxes(options);
12635
- // Render the bars
12636
- this.renderBars(data);
12637
- }
12638
- updateChart() {
12639
- this.createChart();
12640
- }
12641
- cleanupChart() {
12642
- if (this.svg) {
12643
- this.d3.select(this.chartContainerEl()?.nativeElement).selectAll('svg').remove();
12644
- this.svg = null;
12645
- this.chart = null;
12646
- }
12647
- this._tooltipVisible.set(false);
12648
- }
12649
- // Private chart creation methods
12650
- setupDimensions(containerElement, options) {
12651
- // Set width and height based on container or options
12652
- const containerWidth = containerElement.clientWidth;
12653
- const containerHeight = containerElement.clientHeight;
12654
- // Ensure minimum dimensions for the chart
12655
- const minDim = 200;
12656
- this.width = Math.max(options.width || containerWidth, minDim) - this.margin.left - this.margin.right;
12657
- this.height = Math.max(options.height || containerHeight, minDim) - this.margin.top - this.margin.bottom;
12658
- }
12659
- setupScales(data) {
12660
- // Get the bar width percentage (default 80%)
12661
- const barWidthPercent = this.barWidth() / 100;
12662
- // Calculate padding based on barWidth (inverse relationship)
12663
- const padding = Math.max(0.1, 1 - barWidthPercent);
12664
- // Create x scale (band scale for categorical data)
12665
- this.xScale = this.d3
12666
- .scaleBand()
12667
- .domain(data.map((d) => d.label))
12668
- .range([0, this.width])
12669
- .padding(padding);
12670
- // Create y scale (linear scale for values)
12671
- this.yScale = this.d3
12672
- .scaleLinear()
12673
- .domain([0, this.d3.max(data, (d) => d.value) || 0])
12674
- .nice()
12675
- .range([this.height, 0]);
12676
- }
12677
- createAxes(options) {
12678
- // Only create axes if they are enabled in options
12679
- const showXAxis = options.showXAxis !== false;
12680
- const showYAxis = options.showYAxis !== false;
12681
- const showGrid = options.showGrid !== false;
12682
- if (showXAxis) {
12683
- // Create X axis
12684
- this.xAxis = this.chart
12685
- .append('g')
12686
- .attr('class', 'axp-bar-chart-axis-x')
12687
- .attr('transform', `translate(0,${this.height})`)
12688
- .call(this.d3.axisBottom(this.xScale));
12689
- }
12690
- if (showYAxis) {
12691
- // Create Y axis
12692
- this.yAxis = this.chart.append('g').attr('class', 'axp-bar-chart-axis-y').call(this.d3.axisLeft(this.yScale));
12693
- }
12694
- if (showGrid) {
12695
- // Add horizontal grid lines
12696
- this.chart
12697
- .append('g')
12698
- .attr('class', 'axp-bar-chart-grid')
12699
- .call(this.d3
12700
- .axisLeft(this.yScale)
12701
- .tickSize(-this.width)
12702
- .tickFormat(() => ''))
12703
- .selectAll('.tick')
12704
- .style('color', 'rgb(153 153 153 / 30%)'); // Add gray color to ticks
12705
- }
12706
- }
12707
- renderBars(data) {
12708
- // Get corner radius from options
12709
- const radius = this.cornerRadius();
12710
- // Add bars with modern colors
12711
- const bars = this.chart
12712
- .selectAll('.axp-bar-chart-bar')
12713
- .data(data)
12714
- .enter()
12715
- .append('rect')
12716
- .attr('class', 'axp-bar-chart-bar')
12717
- .attr('x', (d) => this.xScale(d.label))
12718
- .attr('width', this.xScale.bandwidth())
12719
- .attr('y', this.height) // Start from bottom for animation
12720
- .attr('height', 0) // Start with height 0 for animation
12721
- .attr('rx', radius) // Rounded corners
12722
- .attr('ry', radius) // Rounded corners
12723
- .attr('fill', (d, i) => d.color || AXPChartColors.getColor(i))
12724
- .on('mouseenter', (event, d) => this.handleBarHover(event, d))
12725
- .on('mousemove', (event) => this.updateTooltipPosition(event))
12726
- .on('mouseleave', () => this._tooltipVisible.set(false))
12727
- .on('click', (event, d) => this.handleBarClick(event, d));
12728
- // Add animation
12729
- bars
12730
- .transition()
12731
- .duration(800)
12732
- .delay((d, i) => i * 50) // Stagger each bar animation
12733
- .attr('y', (d) => this.yScale(d.value))
12734
- .attr('height', (d) => this.height - this.yScale(d.value))
12735
- .ease(this.d3.easeQuadOut); // Simple quadratic ease-out animation
12736
- }
12737
- // Event handlers
12738
- handleBarHover(event, datum) {
12739
- if (this.options().showTooltip !== false) {
12740
- const index = this.chartData().findIndex((item) => item.id === datum.id);
12741
- const color = datum.color || AXPChartColors.getColor(index);
12742
- // Calculate percentage of total
12743
- const total = this.chartData().reduce((sum, item) => sum + item.value, 0);
12744
- const percentage = total > 0 ? ((datum.value / total) * 100).toFixed(1) : '0';
12745
- this._tooltipData.set({
12746
- title: datum.label,
12747
- value: datum.value.toString(),
12748
- percentage: `${percentage}%`,
12749
- color: color,
12750
- });
12751
- this.updateTooltipPosition(event);
12752
- this._tooltipVisible.set(true);
12753
- }
12754
- }
12755
- updateTooltipPosition(event) {
12756
- const container = this.chartContainerEl().nativeElement.getBoundingClientRect();
12757
- const x = event.clientX - container.left;
12758
- const y = event.clientY - container.top;
12759
- this._tooltipPosition.set({
12760
- x: x,
12761
- y: y,
12762
- });
12763
- }
12764
- handleBarClick(event, datum) {
12765
- this.barClick.emit(datum);
12766
- }
12767
- showNoDataMessage(containerElement) {
12768
- const messageContainer = this.d3
12769
- .select(containerElement)
12770
- .append('div')
12771
- .attr('class', 'axp-bar-chart-no-data-message')
12772
- .style('width', '100%')
12773
- .style('height', '100%')
12774
- .style('display', 'flex')
12775
- .style('flex-direction', 'column')
12776
- .style('align-items', 'center')
12777
- .style('justify-content', 'center')
12778
- .style('text-align', 'center');
12779
- // Add an icon
12780
- messageContainer
12781
- .append('div')
12782
- .attr('class', 'axp-bar-chart-no-data-icon')
12783
- .style('margin-bottom', '10px')
12784
- .style('color', 'var(--ax-text-muted, #999)')
12785
- .html('<i class="fa-light fa-chart-bar fa-2x"></i>');
12786
- // Add text message
12787
- messageContainer
12788
- .append('div')
12789
- .attr('class', 'axp-bar-chart-no-data-text')
12790
- .style('font-size', '16px')
12791
- .style('font-weight', '600')
12792
- .style('color', 'var(--ax-text-color, #333)')
12793
- .text('No data available');
12794
- }
12795
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPBarChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
12796
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.0.3", type: AXPBarChartWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { barClick: "barClick" }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"axp-bar-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: [":host{display:block;width:100%;height:100%;min-height:300px}:host .axp-bar-chart{width:100%;height:100%;min-height:300px;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden}:host .axp-bar-chart-bar{transition:opacity .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1),filter .3s cubic-bezier(.4,0,.2,1);cursor:pointer;filter:drop-shadow(0 1px 2px rgba(0,0,0,.1))}:host .axp-bar-chart-bar:hover{filter:brightness(.9) drop-shadow(0 4px 6px rgba(0,0,0,.15));transform:translateY(-3px)}:host .axp-bar-chart-axis-x path,:host .axp-bar-chart-axis-y path{stroke:var(--ax-border-color, #e0e0e0)}:host .axp-bar-chart-axis-x line,:host .axp-bar-chart-axis-y line,:host .axp-bar-chart-grid line{stroke:var(--ax-border-color, #e0e0e0);stroke-dasharray:2,2;stroke-opacity:.5}:host .axp-bar-chart-grid path{stroke-width:0}:host .axp-bar-chart-axis-x text,:host .axp-bar-chart-axis-y text{fill:var(--ax-text-muted, #666);font-size:12px}:host .axp-bar-chart-no-data-message{font-family:var(--ax-font-family, system-ui, sans-serif);display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:1.5rem}:host .axp-bar-chart-no-data-icon{font-size:1.5rem;margin-bottom:.75rem;color:var(--ax-text-muted, #999)}:host .axp-bar-chart-no-data-text{font-size:1rem;font-weight:600;color:var(--ax-text-color, #333)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12797
- }
12798
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPBarChartWidgetViewComponent, decorators: [{
12799
- type: Component,
12800
- args: [{ standalone: true, imports: [CommonModule, AXPChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"axp-bar-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: [":host{display:block;width:100%;height:100%;min-height:300px}:host .axp-bar-chart{width:100%;height:100%;min-height:300px;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden}:host .axp-bar-chart-bar{transition:opacity .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1),filter .3s cubic-bezier(.4,0,.2,1);cursor:pointer;filter:drop-shadow(0 1px 2px rgba(0,0,0,.1))}:host .axp-bar-chart-bar:hover{filter:brightness(.9) drop-shadow(0 4px 6px rgba(0,0,0,.15));transform:translateY(-3px)}:host .axp-bar-chart-axis-x path,:host .axp-bar-chart-axis-y path{stroke:var(--ax-border-color, #e0e0e0)}:host .axp-bar-chart-axis-x line,:host .axp-bar-chart-axis-y line,:host .axp-bar-chart-grid line{stroke:var(--ax-border-color, #e0e0e0);stroke-dasharray:2,2;stroke-opacity:.5}:host .axp-bar-chart-grid path{stroke-width:0}:host .axp-bar-chart-axis-x text,:host .axp-bar-chart-axis-y text{fill:var(--ax-text-muted, #666);font-size:12px}:host .axp-bar-chart-no-data-message{font-family:var(--ax-font-family, system-ui, sans-serif);display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:1.5rem}:host .axp-bar-chart-no-data-icon{font-size:1.5rem;margin-bottom:.75rem;color:var(--ax-text-muted, #999)}:host .axp-bar-chart-no-data-text{font-size:1rem;font-weight:600;color:var(--ax-text-color, #333)}\n"] }]
12801
- }] });
12802
-
12803
- var barChartWidget_component = /*#__PURE__*/Object.freeze({
12804
- __proto__: null,
12805
- AXPBarChartWidgetViewComponent: AXPBarChartWidgetViewComponent
12806
- });
12807
-
12808
- const AXP_WIDGETS_CHART_CATEGORY = {
12809
- name: 'chart',
12810
- order: 6,
12811
- title: 'Charts',
12812
- };
12813
- const AXP_WIDGETS_UTILITY_CATEGORY = {
12814
- name: 'utility',
12815
- order: 7,
12816
- title: 'Utilities',
12817
- };
12818
-
12819
- const AXPBarChartWidget = {
12820
- name: 'bar-chart',
12821
- title: 'Bar Chart Widget',
12822
- categories: [AXP_WIDGETS_CHART_CATEGORY],
12823
- groups: [AXPWidgetGroupEnum.DashboardWidget],
12824
- type: 'dashboard',
12825
- icon: 'fa-light fa-chart-bar',
12826
- properties: [
12827
- // ====== Layout & Dimensions ======
12828
- {
12829
- name: 'height',
12830
- title: 'Height',
12831
- group: AXP_STYLING_PROPERTY_GROUP,
12832
- schema: {
12833
- defaultValue: 300,
12834
- dataType: 'number',
12835
- interface: {
12836
- name: 'height',
12837
- path: 'options.height',
12838
- type: AXPWidgetsCatalog.number,
12839
- options: {
12840
- minValue: 0,
12841
- maxValue: 800,
12842
- },
12843
- },
12844
- },
12845
- visible: true,
12846
- },
12847
- {
12848
- name: 'width',
12849
- title: 'Width',
12850
- group: AXP_STYLING_PROPERTY_GROUP,
12851
- schema: {
12852
- defaultValue: null,
12853
- dataType: 'number',
12854
- interface: {
12855
- name: 'width',
12856
- path: 'options.width',
12857
- type: AXPWidgetsCatalog.number,
12858
- options: {
12859
- minValue: 0,
12860
- maxValue: 1200,
12861
- },
12862
- },
12863
- },
12864
- visible: true,
12865
- },
12866
- // ====== Axis Settings ======
12867
- {
12868
- name: 'showXAxis',
12869
- title: 'Show X Axis',
12870
- group: AXP_APPEARANCE_PROPERTY_GROUP,
12871
- schema: {
12872
- defaultValue: true,
12873
- dataType: 'boolean',
12874
- interface: {
12875
- name: 'showXAxis',
12876
- path: 'options.showXAxis',
12877
- type: AXPWidgetsCatalog.toggle,
12878
- },
12879
- },
12880
- visible: true,
12881
- },
12882
- {
12883
- name: 'showYAxis',
12884
- title: 'Show Y Axis',
12885
- group: AXP_APPEARANCE_PROPERTY_GROUP,
12886
- schema: {
12887
- defaultValue: true,
12888
- dataType: 'boolean',
12889
- interface: {
12890
- name: 'showYAxis',
12891
- path: 'options.showYAxis',
12892
- type: AXPWidgetsCatalog.toggle,
12893
- },
12894
- },
12895
- visible: true,
12896
- },
12897
- {
12898
- name: 'showGrid',
12899
- title: 'Show Grid Lines',
12900
- group: AXP_APPEARANCE_PROPERTY_GROUP,
12901
- schema: {
12902
- defaultValue: true,
12903
- dataType: 'boolean',
12904
- interface: {
12905
- name: 'showGrid',
12906
- path: 'options.showGrid',
12907
- type: AXPWidgetsCatalog.toggle,
12908
- },
12909
- },
12910
- visible: true,
12911
- },
12912
- // ====== Tooltip Settings ======
12913
- {
12914
- name: 'showTooltip',
12915
- title: 'Show Tooltip',
12916
- group: AXP_APPEARANCE_PROPERTY_GROUP,
12917
- schema: {
12918
- defaultValue: true,
12919
- dataType: 'boolean',
12920
- interface: {
12921
- name: 'showTooltip',
12922
- path: 'options.showTooltip',
12923
- type: AXPWidgetsCatalog.toggle,
12924
- },
12925
- },
12926
- visible: true,
12927
- },
12928
- // ====== Bar Appearance ======
12929
- {
12930
- name: 'barWidth',
12931
- title: 'Bar Width',
12932
- group: AXP_APPEARANCE_PROPERTY_GROUP,
12933
- schema: {
12934
- defaultValue: 80,
12935
- dataType: 'number',
12936
- interface: {
12937
- name: 'barWidth',
12938
- path: 'options.barWidth',
12939
- type: AXPWidgetsCatalog.number,
12940
- options: {
12941
- placeholder: '1-100',
12942
- minValue: 1,
12943
- maxValue: 100,
12944
- },
12945
- },
12946
- },
12947
- visible: true,
12948
- },
12949
- {
12950
- name: 'cornerRadius',
12951
- title: 'Corner Radius',
12952
- group: AXP_APPEARANCE_PROPERTY_GROUP,
12953
- schema: {
12954
- defaultValue: 4,
12955
- dataType: 'number',
12956
- interface: {
12957
- name: 'cornerRadius',
12958
- path: 'options.cornerRadius',
12959
- type: AXPWidgetsCatalog.number,
12960
- options: {
12961
- placeholder: '0-20',
12962
- minValue: 0,
12963
- maxValue: 20,
12964
- },
12965
- },
12966
- },
12967
- visible: true,
12968
- },
12969
- ],
12970
- components: {
12971
- view: {
12972
- component: () => Promise.resolve().then(function () { return barChartWidget_component; }).then((c) => c.AXPBarChartWidgetViewComponent),
12973
- },
12974
- },
12975
- meta: {
12976
- dimensions: {
12977
- width: 5,
12978
- height: 6,
12979
- minWidth: 2,
12980
- minHeight: 2,
12981
- maxWidth: 6,
12982
- maxHeight: 7,
12983
- },
12984
- },
12985
- };
12986
-
12987
- class AXPClockCalendarWidgetViewComponent extends AXPValueWidgetComponent {
12988
- constructor() {
12989
- super(...arguments);
12990
- // Dependencies
12991
- this.cdr = inject(ChangeDetectorRef);
12992
- // Time state
12993
- this.currentTime = new Date();
12994
- this.currentDate = new Date();
12995
- this.clockSubscription = null;
12996
- // Static clock elements
12997
- this.clockHours = Array.from({ length: 12 }, (_, i) => i + 1);
12998
- this.clockHourNumbers = Array.from({ length: 12 }, (_, i) => ({
12999
- number: i === 0 ? 12 : i,
13000
- angle: i * 30,
13001
- }));
13002
- // Clock hands rotation angles
13003
- this.hourRotation = 0;
13004
- this.minuteRotation = 0;
13005
- this.secondRotation = 0;
13006
- // Options with computed properties and defaults
13007
- this.displayLayout = computed(() => this.options()?.displayLayout?.id ?? 'both');
13008
- this.showDigitalClock = computed(() => {
13009
- const layout = this.displayLayout();
13010
- return layout === 'both' || layout === 'digital';
13011
- });
13012
- this.showAnalogClock = computed(() => {
13013
- const layout = this.displayLayout();
13014
- return layout === 'both' || layout === 'analog';
13015
- });
13016
- this.showDate = computed(() => this.options()?.showDate !== false);
13017
- this.showDayOfWeek = computed(() => this.options()?.showDayOfWeek !== false);
13018
- this.use24Hour = computed(() => this.options()?.use24Hour === true);
13019
- this.showSeconds = computed(() => this.options()?.showSeconds !== false);
13020
- this.dateFormat = computed(() => this.options()?.dateFormat?.id ?? 'dd MMM yyyy');
13021
- this.timezone = computed(() => this.options()?.timezone?.id ?? 'local');
13022
- this.showTimezoneIndicator = computed(() => this.timezone() !== 'local');
13023
- this.displayTimezone = computed(() => {
13024
- const tz = this.timezone();
13025
- if (tz === 'local')
13026
- return '';
13027
- if (tz.startsWith('UTC')) {
13028
- const [match, sign, hours, minutes] = tz.match(/UTC([+-])(\d+):?(\d+)?/) ?? [];
13029
- if (match) {
13030
- if (!minutes || minutes === '00') {
13031
- return `UTC${sign}${parseInt(hours)}`;
13032
- }
13033
- return `UTC${sign}${parseInt(hours)}:${minutes}`;
13034
- }
13035
- }
13036
- return tz;
13037
- });
13038
- this.timeFormat = computed(() => this.showSeconds() ? (this.use24Hour() ? 'HH:mm:ss' : 'hh:mm:ss a') : this.use24Hour() ? 'HH:mm' : 'hh:mm a');
13039
- }
13040
- ngOnInit() {
13041
- super.ngOnInit();
13042
- this.startClockTimer();
13043
- this.updateTime();
13044
- }
13045
- ngOnDestroy() {
13046
- this.stopClockTimer();
13047
- }
13048
- startClockTimer() {
13049
- this.stopClockTimer();
13050
- this.clockSubscription = interval(1000).subscribe(() => this.updateTime());
13051
- }
13052
- stopClockTimer() {
13053
- this.clockSubscription?.unsubscribe();
13054
- this.clockSubscription = null;
13055
- }
13056
- updateTime() {
13057
- const now = this.getAdjustedTime();
13058
- this.currentTime = now;
13059
- this.currentDate = now;
13060
- this.updateClockHandsRotation(now);
13061
- this.cdr.markForCheck();
13062
- }
13063
- getAdjustedTime() {
13064
- const now = new Date();
13065
- const tz = this.timezone();
13066
- if (tz === 'local' || !tz.startsWith('UTC')) {
13067
- return now;
13068
- }
13069
- const [match, sign, hours, minutes] = tz.match(/UTC([+-])(\d+):?(\d+)?/) ?? [];
13070
- if (!match) {
13071
- return now;
13072
- }
13073
- const offsetHours = parseInt(hours) * (sign === '+' ? 1 : -1);
13074
- const offsetMinutes = minutes ? parseInt(minutes) * (sign === '+' ? 1 : -1) : 0;
13075
- const utcTime = now.getTime() + now.getTimezoneOffset() * 60000;
13076
- return new Date(utcTime + (offsetHours * 3600000 + offsetMinutes * 60000));
13077
- }
13078
- updateClockHandsRotation(now) {
13079
- const hours = now.getHours() % 12;
13080
- const minutes = now.getMinutes();
13081
- const seconds = now.getSeconds();
13082
- // For analog clocks:
13083
- // - 12 o'clock is 0°
13084
- // - 3 o'clock is 90°
13085
- // - 6 o'clock is 180°
13086
- // - 9 o'clock is 270°
13087
- // Hour hand: 30° per hour (360°/12) plus gradual movement from minutes
13088
- this.hourRotation = hours * 30 + minutes / 2 + 180;
13089
- // Minute hand: 6° per minute (360°/60)
13090
- this.minuteRotation = minutes * 6 + 180;
13091
- // Second hand: 6° per second (360°/60)
13092
- this.secondRotation = seconds * 6 + 180;
13093
- }
13094
- initializeWidget() {
13095
- this.updateTime();
13096
- }
13097
- updateWidget() {
13098
- this.stopClockTimer();
13099
- this.startClockTimer();
13100
- this.updateTime();
13101
- }
13102
- destroyWidget() {
13103
- this.stopClockTimer();
13104
- }
13105
- getDayOfWeek() {
13106
- const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
13107
- return days[this.currentDate.getDay()];
13108
- }
13109
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPClockCalendarWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
13110
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPClockCalendarWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n }\n\n <!-- Day of week display -->\n @if (showDayOfWeek()) {\n <div class=\"axp-clock-calendar-day-label\">{{ getDayOfWeek() }}</div>\n }\n\n <div class=\"axp-clock-calendar-content\">\n <!-- Digital Clock Display -->\n @if (showDigitalClock()) {\n <div class=\"axp-clock-calendar-digital-clock\">\n {{ currentTime | format : 'datetime' : timeFormat() | async }}\n </div>\n }\n\n <!-- Analog Clock Display -->\n @if (showAnalogClock()) {\n <div class=\"axp-clock-calendar-analog-clock\">\n <!-- Hour markers -->\n @for (hour of clockHours; track hour) {\n <div\n class=\"axp-clock-calendar-hour-marker\"\n [style.transform]=\"'rotate(' + hour * 30 + 'deg) translateY(-80px)'\"\n ></div>\n }\n\n <!-- Clock Numbers -->\n <div class=\"axp-clock-calendar-numbers-container\">\n @for (hour of clockHourNumbers; track hour) {\n <div\n class=\"axp-clock-calendar-hour-number\"\n [style.transform]=\"'rotate(' + hour.angle + 'deg) translateY(-82px)'\"\n >\n <span [style.transform]=\"'rotate(' + -hour.angle + 'deg)'\">{{ hour.number }}</span>\n </div>\n }\n </div>\n\n <!-- Clock Hands -->\n <div class=\"axp-clock-calendar-hands-container\">\n <div class=\"axp-clock-calendar-hour-hand\" [style.transform]=\"'rotate(' + hourRotation + 'deg)'\"></div>\n <div class=\"axp-clock-calendar-minute-hand\" [style.transform]=\"'rotate(' + minuteRotation + 'deg)'\"></div>\n @if (showSeconds()) {\n <div class=\"axp-clock-calendar-second-hand\" [style.transform]=\"'rotate(' + secondRotation + 'deg)'\"></div>\n }\n <div class=\"axp-clock-calendar-center-dot\"></div>\n </div>\n </div>\n }\n\n <!-- Date Display -->\n @if (showDate()) {\n <div class=\"axp-clock-calendar-date-display\">\n <i class=\"fa-regular fa-calendar\"></i>\n {{ currentDate | format : 'datetime' : dateFormat() | async }}\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-clock-calendar-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;padding:1rem;position:relative;overflow:hidden;box-shadow:var(--ax-shadow-sm);background-color:var(--ax-surface-color);color:var(--ax-text-color)}.axp-clock-calendar-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;position:relative}.axp-clock-calendar-timezone-badge{position:absolute;top:.5rem;right:.5rem;font-size:.75rem;padding:.25rem;border-radius:1rem;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-timezone-badge:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-timezone-badge{display:flex;align-items:center;gap:.25rem}.axp-clock-calendar-timezone-badge i{font-size:.75rem}.axp-clock-calendar-day-label{font-size:.9rem;font-weight:600;text-transform:uppercase;letter-spacing:.05rem;margin-bottom:.25rem}.axp-clock-calendar-digital-clock{font-size:1.5rem;font-weight:500;letter-spacing:.05rem;font-family:monospace;padding:.5rem .75rem;border-radius:.25rem}.axp-clock-calendar-analog-clock{position:relative;border-radius:50%;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-analog-clock:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-analog-clock{display:flex;align-items:center;justify-content:center;background:var(--ax-surface-color);width:min(180px,100%);height:0;padding-bottom:min(180px,100%);margin:.5rem auto;min-width:120px;min-height:120px;box-shadow:var(--ax-shadow-sm)}.axp-clock-calendar-hands-container,.axp-clock-calendar-numbers-container{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.axp-clock-calendar-hour-marker{position:absolute;left:50%;top:50%;width:2px;height:4%;margin-left:-1px;border-radius:1px;background-color:var(--ax-text-muted);transform-origin:50% 0}.axp-clock-calendar-hour-number{position:absolute;left:50%;top:50%;transform-origin:50% 0;font-size:clamp(.7rem,2.5vw,.9rem);font-weight:600;color:var(--ax-text-color)}.axp-clock-calendar-hour-number span{display:block}.axp-clock-calendar-hour-hand{position:absolute;top:50%;left:50%;width:4px;height:25%;margin-left:-2px;background-color:rgba(23,23,23,.75)}.axp-clock-calendar-hour-hand:is(.ax-dark *){background-color:rgba(245,245,245,.75)}.axp-clock-calendar-hour-hand{transform-origin:50% 0;border-radius:3px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-minute-hand{position:absolute;top:50%;left:50%;width:3px;height:38%;margin-left:-1.5px;background-color:rgba(23,23,23,.5)}.axp-clock-calendar-minute-hand:is(.ax-dark *){background-color:rgba(245,245,245,.5)}.axp-clock-calendar-minute-hand{transform-origin:50% 0;border-radius:2px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-second-hand{position:absolute;top:50%;left:50%;width:2px;height:42%;margin-left:-1px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-500),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-400),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand{transform-origin:50% 0;border-radius:1px;box-shadow:0 0 3px rgba(0,0,0,.2)}.axp-clock-calendar-center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;border-radius:50%;margin-top:-5px;margin-left:-5px;background-color:#d81159;border:2px solid var(--ax-surface-color);box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-date-display{display:flex;align-items:center;gap:.5rem;font-size:.85rem;padding:.25rem .6rem;border-radius:.25rem;background-color:var(--ax-surface-hover);color:var(--ax-text-color)}.axp-clock-calendar-date-display i{font-size:.85rem;opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i2$9.AXFormatPipe, name: "format" }, { kind: "ngmodule", type: AXTagModule }, { kind: "ngmodule", type: AXDecoratorModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13111
- }
13112
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPClockCalendarWidgetViewComponent, decorators: [{
13113
- type: Component,
13114
- args: [{ standalone: true, imports: [CommonModule, AXDateTimeModule, AXFormatModule, AXTagModule, AXDecoratorModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n }\n\n <!-- Day of week display -->\n @if (showDayOfWeek()) {\n <div class=\"axp-clock-calendar-day-label\">{{ getDayOfWeek() }}</div>\n }\n\n <div class=\"axp-clock-calendar-content\">\n <!-- Digital Clock Display -->\n @if (showDigitalClock()) {\n <div class=\"axp-clock-calendar-digital-clock\">\n {{ currentTime | format : 'datetime' : timeFormat() | async }}\n </div>\n }\n\n <!-- Analog Clock Display -->\n @if (showAnalogClock()) {\n <div class=\"axp-clock-calendar-analog-clock\">\n <!-- Hour markers -->\n @for (hour of clockHours; track hour) {\n <div\n class=\"axp-clock-calendar-hour-marker\"\n [style.transform]=\"'rotate(' + hour * 30 + 'deg) translateY(-80px)'\"\n ></div>\n }\n\n <!-- Clock Numbers -->\n <div class=\"axp-clock-calendar-numbers-container\">\n @for (hour of clockHourNumbers; track hour) {\n <div\n class=\"axp-clock-calendar-hour-number\"\n [style.transform]=\"'rotate(' + hour.angle + 'deg) translateY(-82px)'\"\n >\n <span [style.transform]=\"'rotate(' + -hour.angle + 'deg)'\">{{ hour.number }}</span>\n </div>\n }\n </div>\n\n <!-- Clock Hands -->\n <div class=\"axp-clock-calendar-hands-container\">\n <div class=\"axp-clock-calendar-hour-hand\" [style.transform]=\"'rotate(' + hourRotation + 'deg)'\"></div>\n <div class=\"axp-clock-calendar-minute-hand\" [style.transform]=\"'rotate(' + minuteRotation + 'deg)'\"></div>\n @if (showSeconds()) {\n <div class=\"axp-clock-calendar-second-hand\" [style.transform]=\"'rotate(' + secondRotation + 'deg)'\"></div>\n }\n <div class=\"axp-clock-calendar-center-dot\"></div>\n </div>\n </div>\n }\n\n <!-- Date Display -->\n @if (showDate()) {\n <div class=\"axp-clock-calendar-date-display\">\n <i class=\"fa-regular fa-calendar\"></i>\n {{ currentDate | format : 'datetime' : dateFormat() | async }}\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-clock-calendar-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;padding:1rem;position:relative;overflow:hidden;box-shadow:var(--ax-shadow-sm);background-color:var(--ax-surface-color);color:var(--ax-text-color)}.axp-clock-calendar-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;position:relative}.axp-clock-calendar-timezone-badge{position:absolute;top:.5rem;right:.5rem;font-size:.75rem;padding:.25rem;border-radius:1rem;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-timezone-badge:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-timezone-badge{display:flex;align-items:center;gap:.25rem}.axp-clock-calendar-timezone-badge i{font-size:.75rem}.axp-clock-calendar-day-label{font-size:.9rem;font-weight:600;text-transform:uppercase;letter-spacing:.05rem;margin-bottom:.25rem}.axp-clock-calendar-digital-clock{font-size:1.5rem;font-weight:500;letter-spacing:.05rem;font-family:monospace;padding:.5rem .75rem;border-radius:.25rem}.axp-clock-calendar-analog-clock{position:relative;border-radius:50%;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-analog-clock:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-analog-clock{display:flex;align-items:center;justify-content:center;background:var(--ax-surface-color);width:min(180px,100%);height:0;padding-bottom:min(180px,100%);margin:.5rem auto;min-width:120px;min-height:120px;box-shadow:var(--ax-shadow-sm)}.axp-clock-calendar-hands-container,.axp-clock-calendar-numbers-container{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.axp-clock-calendar-hour-marker{position:absolute;left:50%;top:50%;width:2px;height:4%;margin-left:-1px;border-radius:1px;background-color:var(--ax-text-muted);transform-origin:50% 0}.axp-clock-calendar-hour-number{position:absolute;left:50%;top:50%;transform-origin:50% 0;font-size:clamp(.7rem,2.5vw,.9rem);font-weight:600;color:var(--ax-text-color)}.axp-clock-calendar-hour-number span{display:block}.axp-clock-calendar-hour-hand{position:absolute;top:50%;left:50%;width:4px;height:25%;margin-left:-2px;background-color:rgba(23,23,23,.75)}.axp-clock-calendar-hour-hand:is(.ax-dark *){background-color:rgba(245,245,245,.75)}.axp-clock-calendar-hour-hand{transform-origin:50% 0;border-radius:3px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-minute-hand{position:absolute;top:50%;left:50%;width:3px;height:38%;margin-left:-1.5px;background-color:rgba(23,23,23,.5)}.axp-clock-calendar-minute-hand:is(.ax-dark *){background-color:rgba(245,245,245,.5)}.axp-clock-calendar-minute-hand{transform-origin:50% 0;border-radius:2px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-second-hand{position:absolute;top:50%;left:50%;width:2px;height:42%;margin-left:-1px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-500),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-400),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand{transform-origin:50% 0;border-radius:1px;box-shadow:0 0 3px rgba(0,0,0,.2)}.axp-clock-calendar-center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;border-radius:50%;margin-top:-5px;margin-left:-5px;background-color:#d81159;border:2px solid var(--ax-surface-color);box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-date-display{display:flex;align-items:center;gap:.5rem;font-size:.85rem;padding:.25rem .6rem;border-radius:.25rem;background-color:var(--ax-surface-hover);color:var(--ax-text-color)}.axp-clock-calendar-date-display i{font-size:.85rem;opacity:.7}\n"] }]
13115
- }] });
13116
-
13117
- var clockCalendarWidget_component = /*#__PURE__*/Object.freeze({
13118
- __proto__: null,
13119
- AXPClockCalendarWidgetViewComponent: AXPClockCalendarWidgetViewComponent
13120
- });
13121
-
13122
- /**
13123
- * ACoreX Clock Calendar Widget Types
13124
- * Contains all types and interfaces for the Clock Calendar widget
13125
- */
13126
- /**
13127
- * Common timezone options for the widget configuration
13128
- */
13129
- const AXP_TIMEZONE_OPTIONS = [
13130
- { id: 'local', title: 'Local Time' },
13131
- { id: 'UTC+0', title: 'UTC (GMT)' },
13132
- { id: 'UTC+1', title: 'Central European Time (UTC+1)' },
13133
- { id: 'UTC+2', title: 'Eastern European Time (UTC+2)' },
13134
- { id: 'UTC+3', title: 'Moscow Time (UTC+3)' },
13135
- { id: 'UTC+4', title: 'Gulf Time (UTC+4)' },
13136
- { id: 'UTC+5:30', title: 'Indian Time (UTC+5:30)' },
13137
- { id: 'UTC+8', title: 'China Time (UTC+8)' },
13138
- { id: 'UTC+9', title: 'Japan Time (UTC+9)' },
13139
- { id: 'UTC+10', title: 'Australian Eastern Time (UTC+10)' },
13140
- { id: 'UTC-5', title: 'Eastern Time (UTC-5)' },
13141
- { id: 'UTC-6', title: 'Central Time (UTC-6)' },
13142
- { id: 'UTC-7', title: 'Mountain Time (UTC-7)' },
13143
- { id: 'UTC-8', title: 'Pacific Time (UTC-8)' },
13144
- ];
13145
- /**
13146
- * Common date format options for the widget configuration
13147
- */
13148
- const AXP_DATE_FORMAT_OPTIONS = [
13149
- { id: 'dd MMM yyyy', title: '31 Dec 2023' },
13150
- { id: 'MMM dd, yyyy', title: 'Dec 31, 2023' },
13151
- { id: 'dd/MM/yyyy', title: '31/12/2023' },
13152
- { id: 'MM/dd/yyyy', title: '12/31/2023' },
13153
- ];
13154
-
13155
- const AXPClockCalendarWidget = {
13156
- name: 'clock-calendar',
13157
- title: 'Clock & Calendar',
13158
- categories: [AXP_WIDGETS_UTILITY_CATEGORY],
13159
- groups: [AXPWidgetGroupEnum.DashboardWidget],
13160
- type: 'dashboard',
13161
- icon: 'fa-light fa-clock',
13162
- properties: [
13163
- // ====== Display Settings ======
13164
- {
13165
- name: 'displayLayout',
13166
- title: 'Display Layout',
13167
- group: AXP_APPEARANCE_PROPERTY_GROUP,
13168
- schema: {
13169
- dataType: 'string',
13170
- defaultValue: 'both',
13171
- interface: {
13172
- name: 'displayLayout',
13173
- path: 'options.displayLayout',
13174
- type: AXPWidgetsCatalog.select,
13175
- options: {
13176
- dataSource: [
13177
- { id: 'both', title: 'Digital & Analog' },
13178
- { id: 'digital', title: 'Digital Only' },
13179
- { id: 'analog', title: 'Analog Only' },
13180
- ],
13181
- },
13182
- },
13183
- },
13184
- visible: true,
13185
- },
13186
- {
13187
- name: 'showDate',
13188
- title: 'Show Date',
13189
- group: AXP_APPEARANCE_PROPERTY_GROUP,
13190
- schema: {
13191
- defaultValue: true,
13192
- dataType: 'boolean',
13193
- interface: {
13194
- name: 'showDate',
13195
- path: 'options.showDate',
13196
- type: AXPWidgetsCatalog.toggle,
13197
- },
13198
- },
13199
- visible: true,
13200
- },
13201
- {
13202
- name: 'showDayOfWeek',
13203
- title: 'Show Day of Week',
13204
- group: AXP_APPEARANCE_PROPERTY_GROUP,
13205
- schema: {
13206
- defaultValue: true,
13207
- dataType: 'boolean',
13208
- interface: {
13209
- name: 'showDayOfWeek',
13210
- path: 'options.showDayOfWeek',
13211
- type: AXPWidgetsCatalog.toggle,
13212
- },
13213
- },
13214
- visible: true,
13215
- },
13216
- // ====== Time Format Settings ======
13217
- {
13218
- name: 'use24Hour',
13219
- title: 'Use 24 Hour Format',
13220
- group: AXP_BEHAVIOR_PROPERTY_GROUP,
13221
- schema: {
13222
- defaultValue: false,
13223
- dataType: 'boolean',
13224
- interface: {
13225
- name: 'use24Hour',
13226
- path: 'options.use24Hour',
13227
- type: AXPWidgetsCatalog.toggle,
13228
- },
13229
- },
13230
- visible: true,
13231
- },
13232
- {
13233
- name: 'showSeconds',
13234
- title: 'Show Seconds',
13235
- group: AXP_BEHAVIOR_PROPERTY_GROUP,
13236
- schema: {
13237
- defaultValue: true,
13238
- dataType: 'boolean',
13239
- interface: {
13240
- name: 'showSeconds',
13241
- path: 'options.showSeconds',
13242
- type: AXPWidgetsCatalog.toggle,
13243
- },
13244
- },
13245
- visible: true,
13246
- },
13247
- // {
13248
- // name: 'showHourMarkers',
13249
- // title: 'Show Hour Markers',
13250
- // group: AXP_APPEARANCE_PROPERTY_GROUP,
13251
- // schema: {
13252
- // defaultValue: true,
13253
- // dataType: 'boolean',
13254
- // interface: {
13255
- // name: 'showHourMarkers',
13256
- // path: 'options.showHourMarkers',
13257
- // type: AXPWidgetsCatalog.toggle,
13258
- // },
13259
- // },
13260
- // visible: true,
13261
- // },
13262
- {
13263
- name: 'dateFormat',
13264
- title: 'Date Format',
13265
- group: AXP_BEHAVIOR_PROPERTY_GROUP,
13266
- schema: {
13267
- defaultValue: 'dd MMM yyyy',
13268
- dataType: 'string',
13269
- interface: {
13270
- name: 'dateFormat',
13271
- path: 'options.dateFormat',
13272
- type: AXPWidgetsCatalog.select,
13273
- options: {
13274
- dataSource: AXP_DATE_FORMAT_OPTIONS,
13275
- },
13276
- },
13277
- },
13278
- visible: true,
13279
- },
13280
- {
13281
- name: 'timezone',
13282
- title: 'Timezone',
13283
- group: AXP_BEHAVIOR_PROPERTY_GROUP,
13284
- schema: {
13285
- defaultValue: 'local',
13286
- dataType: 'string',
13287
- interface: {
13288
- name: 'timezone',
13289
- path: 'options.timezone',
13290
- type: AXPWidgetsCatalog.select,
13291
- options: {
13292
- dataSource: AXP_TIMEZONE_OPTIONS,
13293
- },
13294
- },
13295
- },
13296
- visible: true,
13297
- },
13298
- ],
13299
- components: {
13300
- view: {
13301
- component: () => Promise.resolve().then(function () { return clockCalendarWidget_component; }).then((m) => m.AXPClockCalendarWidgetViewComponent),
13302
- },
13303
- },
13304
- meta: {
13305
- dimensions: {
13306
- width: 2,
13307
- height: 5,
13308
- minWidth: 2,
13309
- minHeight: 2,
13310
- maxWidth: 3,
13311
- maxHeight: 6,
13312
- },
13313
- },
13314
- };
13315
-
13316
- /**
13317
- * Donut Chart Widget Component
13318
- * Displays data in a circular donut chart with interactive segments
13319
- */
13320
- class AXPDonutChartWidgetViewComponent extends AXPChartBaseComponent {
13321
- constructor() {
13322
- super(...arguments);
13323
- this.segmentClick = output();
13324
- // Chart reference and D3 related properties
13325
- this.cdr = inject(ChangeDetectorRef);
13326
- this.chartContainerEl = viewChild.required('chartContainer');
13327
- this.pieData = [];
13328
- // State management
13329
- this.hiddenSegments = new Set();
13330
- // Tooltip state
13331
- this._tooltipVisible = signal(false);
13332
- this._tooltipPosition = signal({ x: 0, y: 0 });
13333
- this._tooltipData = signal({
13334
- title: '',
13335
- value: 0,
13336
- percentage: '0%',
13337
- color: '',
13338
- });
13339
- // Public computed properties for the template
13340
- this.tooltipVisible = computed(() => this._tooltipVisible());
13341
- this.tooltipPosition = computed(() => this._tooltipPosition());
13342
- this.tooltipData = computed(() => this._tooltipData());
13343
- // Computed configuration options
13344
- this.showLegend = computed(() => this.options()['showLegend'] !== false);
13345
- this.showTooltip = computed(() => this.options()['showTooltip'] !== false);
13346
- this.legendPosition = computed(() => this.options()['legendPosition']?.id || 'right');
13347
- this.donutWidth = computed(() => this.options()['donutWidth'] ?? 35);
13348
- this.cornerRadius = computed(() => this.options()['cornerRadius'] ?? 4);
13349
- // Data accessor for handling different incoming data formats
13350
- this.chartDataArray = computed(() => {
13351
- const data = this.chartData();
13352
- if (data === null || data === undefined) {
13353
- return [];
13354
- }
13355
- // Handle both array format and object format with data property
13356
- return Array.isArray(data) ? data : data.data || [];
13357
- });
13358
- }
13359
- getColor(index) {
13360
- return AXPChartColors.getColor(index);
13361
- }
13362
- isSegmentHidden(id) {
13363
- return this.hiddenSegments.has(id);
13364
- }
13365
- // Event handlers
13366
- onSegmentClick(item) {
13367
- this.toggleSegment(item);
13368
- this.segmentClick.emit(item);
13369
- }
13370
- onLegendMouseEnter(item) {
13371
- if (!this.svg)
13372
- return;
13373
- // Highlight the target segment
13374
- this.svg
13375
- .selectAll('path')
13376
- .filter((d) => d?.data?.id === item.id)
13377
- .classed('axp-donut-chart-highlighted', true)
13378
- .attr('transform', 'scale(1.02)');
13379
- // Dim other segments
13380
- this.svg
13381
- .selectAll('path')
13382
- .filter((d) => d?.data?.id !== item.id)
13383
- .classed('axp-donut-chart-dimmed', true);
13384
- }
13385
- onLegendMouseLeave() {
13386
- if (!this.svg)
13387
- return;
13388
- // Reset all segments
13389
- this.svg
13390
- .selectAll('path')
13391
- .classed('axp-donut-chart-highlighted', false)
13392
- .classed('axp-donut-chart-dimmed', false)
13393
- .attr('transform', 'scale(1)');
13394
- }
13395
- // Chart lifecycle methods (implementation of base class abstract methods)
13396
- createChart() {
13397
- if (!this.d3 || !this.chartContainerEl()?.nativeElement)
13398
- return;
13399
- try {
13400
- const containerElement = this.chartContainerEl().nativeElement;
13401
- const chartElement = containerElement.querySelector('div');
13402
- this.clearChart(chartElement);
13403
- const data = this.chartDataArray();
13404
- if (!data || data.length === 0) {
13405
- this.showNoDataMessage(chartElement);
13406
- return;
13407
- }
13408
- const options = this.options();
13409
- const { width, height } = this.setupDimensions(containerElement, options);
13410
- this.renderDonutChart(chartElement, width, height);
13411
- }
13412
- catch (error) {
13413
- console.error('Error creating donut chart:', error);
13414
- this.handleChartError();
13415
- }
13416
- }
13417
- updateChart() {
13418
- this.createChart();
13419
- }
13420
- cleanupChart() {
13421
- if (this.svg) {
13422
- this.d3.select(this.chartContainerEl()?.nativeElement).selectAll('svg').remove();
13423
- this.svg = null;
13424
- this.pieData = [];
13425
- }
13426
- this.hiddenSegments.clear();
13427
- this._tooltipVisible.set(false);
13428
- }
13429
- // Private helper methods
13430
- clearChart(element) {
13431
- this.d3.select(element).selectAll('*').remove();
13432
- }
13433
- handleChartError() {
13434
- try {
13435
- const containerElement = this.chartContainerEl()?.nativeElement;
13436
- if (containerElement) {
13437
- const chartElement = containerElement.querySelector('div');
13438
- if (chartElement) {
13439
- this.showNoDataMessage(chartElement);
13440
- }
13441
- }
13442
- }
13443
- catch (e) {
13444
- console.error('Failed to show no data message:', e);
13445
- }
13446
- }
13447
- setupDimensions(containerElement, options) {
13448
- const containerWidth = containerElement.clientWidth;
13449
- const containerHeight = containerElement.clientHeight;
13450
- // Ensure minimum dimensions for the chart
13451
- const minDim = 200;
13452
- const width = Math.max(options['width'] || containerWidth, minDim);
13453
- const height = Math.max(options['height'] || containerHeight, minDim);
13454
- return { width, height };
13455
- }
13456
- renderDonutChart(chartElement, width, height) {
13457
- const data = this.chartDataArray();
13458
- // Filter out hidden segments
13459
- const visibleData = data.filter((item) => !this.hiddenSegments.has(item.id));
13460
- // If all segments are hidden, show no data message and return
13461
- if (visibleData.length === 0) {
13462
- this.showAllSegmentsHiddenMessage(chartElement);
13463
- return;
13464
- }
13465
- const total = this.calculateTotal();
13466
- // Calculate chart dimensions based on legend position
13467
- const { chartWidth, chartHeight, translateX, translateY } = this.calculateChartLayout(width, height);
13468
- // Create SVG container with filters
13469
- const svg = this.createSvgWithFilters(chartElement, width, height);
13470
- // Create main chart group
13471
- this.svg = svg.append('g').attr('transform', `translate(${translateX}, ${translateY})`);
13472
- // Create donut segments
13473
- this.createDonutSegments(chartWidth, chartHeight, visibleData, total);
13474
- // Add total in center
13475
- this.addTotalDisplay(total);
13476
- }
13477
- calculateChartLayout(width, height) {
13478
- const legendPosition = this.legendPosition();
13479
- let chartWidth = width;
13480
- let chartHeight = height;
13481
- let translateX = width / 2;
13482
- let translateY = height / 2;
13483
- if (this.showLegend()) {
13484
- if (legendPosition === 'right') {
13485
- // Reserve space for right legend
13486
- const legendWidth = Math.min(width * 0.3, 150);
13487
- chartWidth = width - legendWidth - 20;
13488
- translateX = (width - chartWidth) / 3 + chartWidth / 2;
13489
- }
13490
- else if (legendPosition === 'bottom') {
13491
- // Reserve space for bottom legend
13492
- const legendHeight = Math.min(height * 0.2, 80);
13493
- chartHeight = height - legendHeight - 20;
13494
- translateY = (height - chartHeight) / 3 + chartHeight / 2;
13495
- }
13496
- }
13497
- return { chartWidth, chartHeight, translateX, translateY };
13498
- }
13499
- createSvgWithFilters(chartElement, width, height) {
13500
- const svg = this.d3
13501
- .select(chartElement)
13502
- .append('svg')
13503
- .attr('width', width)
13504
- .attr('height', height)
13505
- .attr('viewBox', `0 0 ${width} ${height}`)
13506
- .attr('preserveAspectRatio', 'xMidYMid meet');
13507
- // Add drop shadow filter
13508
- const defs = svg.append('defs');
13509
- const filter = defs.append('filter').attr('id', 'axp-donut-chart-segment-shadow').attr('height', '130%');
13510
- filter.append('feGaussianBlur').attr('in', 'SourceAlpha').attr('stdDeviation', 2).attr('result', 'blur');
13511
- filter.append('feOffset').attr('in', 'blur').attr('dx', 1).attr('dy', 1).attr('result', 'offsetBlur');
13512
- const feComponentTransfer = filter
13513
- .append('feComponentTransfer')
13514
- .attr('in', 'offsetBlur')
13515
- .attr('result', 'offsetBlur');
13516
- feComponentTransfer.append('feFuncA').attr('type', 'linear').attr('slope', 0.3);
13517
- const feMerge = filter.append('feMerge');
13518
- feMerge.append('feMergeNode').attr('in', 'offsetBlur');
13519
- feMerge.append('feMergeNode').attr('in', 'SourceGraphic');
13520
- return svg;
13521
- }
13522
- createDonutSegments(chartWidth, chartHeight, data, total) {
13523
- // Create pie layout
13524
- const pie = this.d3
13525
- .pie()
13526
- .value((d) => d.value)
13527
- .sort(null)
13528
- .padAngle(0.02);
13529
- // Calculate the radius of the donut chart
13530
- const radius = (Math.min(chartWidth, chartHeight) / 2) * 0.85;
13531
- // Calculate inner radius based on donutWidth percentage
13532
- const donutWidthPercent = this.donutWidth() / 100;
13533
- const innerRadius = radius * (1 - donutWidthPercent);
13534
- // Create arc generator with the configured radius and corner radius
13535
- const arc = this.d3
13536
- .arc()
13537
- .innerRadius(innerRadius)
13538
- .outerRadius(radius * 0.95)
13539
- .cornerRadius(this.cornerRadius());
13540
- // Generate pie data
13541
- this.pieData = pie(data);
13542
- // Create color scale
13543
- const colorScale = this.setupColorScale(this.chartDataArray());
13544
- // Add segments with animation
13545
- this.addSegmentsWithAnimation(arc, colorScale, total);
13546
- }
13547
- setupColorScale(data) {
13548
- return this.d3
13549
- .scaleOrdinal()
13550
- .domain(data.map((_, i) => i.toString()))
13551
- .range(data.map((_, i) => this.getColor(i)));
13552
- }
13553
- addSegmentsWithAnimation(arc, colorScale, total) {
13554
- // Add segments
13555
- const segments = this.svg
13556
- .selectAll('path')
13557
- .data(this.pieData)
13558
- .enter()
13559
- .append('path')
13560
- .attr('class', 'axp-donut-chart-segment')
13561
- .attr('fill', (d, i) => colorScale(i.toString()))
13562
- .style('opacity', 0)
13563
- .on('click', (event, d) => this.onSegmentClick(d.data))
13564
- .on('mousemove', (event, d) => this.handleSegmentHover(event, d, total))
13565
- .on('mouseleave', () => this._tooltipVisible.set(false));
13566
- // Animate segments
13567
- segments
13568
- .transition()
13569
- .duration(800)
13570
- .ease(this.d3.easeCubicOut)
13571
- .delay((d, i) => i * 50)
13572
- .style('opacity', 1)
13573
- .attrTween('d', (d) => {
13574
- const interpolate = this.d3.interpolate({ startAngle: d.startAngle, endAngle: d.startAngle }, d);
13575
- return (t) => arc(interpolate(t));
13576
- });
13577
- }
13578
- handleSegmentHover(event, datum, total) {
13579
- if (!this.showTooltip())
13580
- return;
13581
- const percentage = ((datum.data.value / total) * 100).toFixed(1);
13582
- const segmentColor = this.getColor(this.chartDataArray().findIndex((item) => item.id === datum.data.id));
13583
- this._tooltipData.set({
13584
- title: datum.data.name,
13585
- value: datum.data.value,
13586
- percentage: `${percentage}%`,
13587
- color: segmentColor,
13588
- });
13589
- this.updateTooltipPosition(event);
13590
- this._tooltipVisible.set(true);
13591
- }
13592
- updateTooltipPosition(event) {
13593
- const container = this.chartContainerEl().nativeElement.getBoundingClientRect();
13594
- const x = event.clientX - container.left;
13595
- const y = event.clientY - container.top;
13596
- this._tooltipPosition.set({
13597
- x: x,
13598
- y: y,
13599
- });
13600
- }
13601
- toggleSegment(item) {
13602
- if (this.hiddenSegments.has(item.id)) {
13603
- this.hiddenSegments.delete(item.id);
13604
- }
13605
- else {
13606
- this.hiddenSegments.add(item.id);
13607
- }
13608
- // Hide tooltip when toggling segments
13609
- this._tooltipVisible.set(false);
13610
- this.updateChart();
13611
- }
13612
- calculateTotal() {
13613
- return this.chartDataArray()
13614
- .filter((item) => !this.hiddenSegments.has(item.id))
13615
- .reduce((sum, item) => sum + item.value, 0);
13616
- }
13617
- showNoDataMessage(containerElement) {
13618
- const messageContainer = this.d3
13619
- .select(containerElement)
13620
- .append('div')
13621
- .attr('class', 'axp-donut-chart-no-data-message')
13622
- .style('width', 'auto')
13623
- .style('text-align', 'center');
13624
- // Add an icon
13625
- messageContainer
13626
- .append('div')
13627
- .attr('class', 'axp-donut-chart-no-data-icon')
13628
- .html('<i class="fa-light fa-chart-pie-simple fa-2x"></i>');
13629
- // Add text message and help text
13630
- messageContainer.append('div').attr('class', 'axp-donut-chart-no-data-text').text('No data available');
13631
- messageContainer
13632
- .append('div')
13633
- .attr('class', 'axp-donut-chart-no-data-help')
13634
- .text('Please provide data in the correct format');
13635
- // Position in center
13636
- const container = containerElement.getBoundingClientRect();
13637
- messageContainer.style('left', `${container.width / 2}px`).style('top', `${container.height / 2}px`);
13638
- }
13639
- // Add method to show message when all segments are hidden
13640
- showAllSegmentsHiddenMessage(containerElement) {
13641
- this.clearChart(containerElement);
13642
- // Add a simple div to ensure proper positioning
13643
- const wrapper = this.d3
13644
- .select(containerElement)
13645
- .append('div')
13646
- .style('position', 'relative')
13647
- .style('width', '100%')
13648
- .style('height', '100%');
13649
- const messageContainer = wrapper
13650
- .append('div')
13651
- .attr('class', 'axp-donut-chart-no-data-message')
13652
- .style('position', 'absolute')
13653
- .style('left', '50%')
13654
- .style('top', '50%')
13655
- .style('transform', 'translate(-50%, -50%)')
13656
- .style('text-align', 'center')
13657
- .style('z-index', '10')
13658
- .style('background-color', 'rgba(255, 255, 255, 0.95)')
13659
- .style('padding', '1.5rem')
13660
- .style('border-radius', '0.5rem')
13661
- .style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
13662
- .style('width', '80%')
13663
- .style('max-width', '300px');
13664
- // Add an icon
13665
- messageContainer
13666
- .append('div')
13667
- .attr('class', 'axp-donut-chart-no-data-icon')
13668
- .style('color', 'var(--ax-text-muted, #999)')
13669
- .style('margin-bottom', '0.75rem')
13670
- .html('<i class="fa-light fa-eye-slash fa-2x"></i>');
13671
- // Add text message and help text
13672
- messageContainer
13673
- .append('div')
13674
- .attr('class', 'axp-donut-chart-no-data-text')
13675
- .style('font-size', '1rem')
13676
- .style('font-weight', '600')
13677
- .style('color', 'var(--ax-text-color, #333)')
13678
- .style('margin-bottom', '0.5rem')
13679
- .text('All segments are hidden');
13680
- messageContainer
13681
- .append('div')
13682
- .attr('class', 'axp-donut-chart-no-data-help')
13683
- .style('font-size', '0.8rem')
13684
- .style('color', 'var(--ax-text-muted, #999)')
13685
- .text('Click on a legend item to show data');
13686
- }
13687
- addTotalDisplay(total) {
13688
- if (!this.svg)
13689
- return;
13690
- // Remove any existing total display
13691
- this.svg.selectAll('.axp-donut-chart-total-display').remove();
13692
- // Create group for the total display
13693
- const totalDisplay = this.svg
13694
- .append('g')
13695
- .attr('class', 'axp-donut-chart-total-display')
13696
- .attr('text-anchor', 'middle');
13697
- // Add total value
13698
- totalDisplay
13699
- .append('text')
13700
- .attr('class', 'axp-donut-chart-total-value')
13701
- .style('font-size', '1.8rem')
13702
- .style('font-weight', '600')
13703
- .style('fill', 'currentColor')
13704
- .text(total.toLocaleString());
13705
- // Add "Total" label
13706
- totalDisplay
13707
- .append('text')
13708
- .attr('class', 'axp-donut-chart-total-label')
13709
- .attr('dy', '1.4em')
13710
- .style('font-size', '0.9rem')
13711
- .style('fill', 'currentColor')
13712
- .style('fill-opacity', '0.8')
13713
- .text('Total');
13714
- }
13715
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPDonutChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
13716
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPDonutChartWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { segmentClick: "segmentClick" }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"axp-donut-chart-container\" #chartContainer>\n <!-- Chart visualization area -->\n <div class=\"axp-donut-chart-content\"></div>\n\n <!-- Legend with conditional positioning -->\n @if (showLegend()) {\n <div\n class=\"axp-donut-chart-legend-container\"\n [class.axp-donut-chart-legend-right]=\"legendPosition() === 'right'\"\n [class.axp-donut-chart-legend-bottom]=\"legendPosition() === 'bottom'\"\n >\n @for (item of chartDataArray(); track item.id) {\n <div\n class=\"axp-donut-chart-legend-item\"\n (mouseenter)=\"onLegendMouseEnter(item)\"\n (mouseleave)=\"onLegendMouseLeave()\"\n (click)=\"onSegmentClick(item)\"\n [class.axp-donut-chart-hidden]=\"isSegmentHidden(item.id)\"\n >\n <div class=\"axp-donut-chart-legend-color\" [style.background-color]=\"getColor($index)\"></div>\n <span class=\"axp-donut-chart-legend-name\">{{ item.name }}</span>\n <span class=\"axp-donut-chart-legend-value\">{{ item.value }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-donut-chart-container{position:relative;height:100%;width:100%;padding:1rem;border-radius:.5rem;box-shadow:var(--ax-card-shadow, 0 2px 8px rgba(0, 0, 0, .05));box-sizing:border-box;display:flex;flex-direction:column;overflow:hidden}.axp-donut-chart-content{flex:1;width:100%;display:flex;align-items:center;justify-content:center;position:relative;min-height:0}.axp-donut-chart-legend-container{display:flex;gap:.75rem;padding:.75rem;flex-wrap:wrap;justify-content:center;font-family:var(--ax-font-family, system-ui, sans-serif);z-index:5}.axp-donut-chart-legend-right{flex-direction:column;position:absolute;right:.75rem;top:0;bottom:0;margin:auto;height:fit-content;max-height:80%;overflow-y:auto;overflow-x:hidden;padding:.75rem;background-color:rgba(255,255,255,.9);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:.375rem;box-shadow:0 2px 8px rgba(0,0,0,.05);max-width:30%}.axp-donut-chart-legend-bottom{position:absolute;bottom:.5rem;left:0;right:0;margin:0 auto;width:auto;max-width:98%;flex-direction:row;flex-wrap:wrap;justify-content:center;padding:.75rem;background-color:rgba(255,255,255,.9);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:.375rem;box-shadow:0 2px 8px rgba(0,0,0,.05)}.axp-donut-chart-legend-item{display:flex;align-items:center;gap:.375rem;padding:.25rem .5rem;border-radius:.375rem;cursor:pointer;transition:all .2s ease;white-space:nowrap;font-size:.875rem}.axp-donut-chart-legend-item:hover{background-color:var(--ax-hover-bg, rgba(0, 0, 0, .05));transform:translateY(-1px)}.axp-donut-chart-legend-item.axp-donut-chart-hidden{opacity:.5}.axp-donut-chart-legend-color{min-width:10px;min-height:10px;width:10px;height:10px;border-radius:2px;box-shadow:0 1px 3px rgba(0,0,0,.1)}.axp-donut-chart-legend-name{font-size:.875rem;font-weight:500;color:var(--ax-text-color, #333)}.axp-donut-chart-legend-value{font-size:.875rem;opacity:.7;margin-left:4px;font-weight:400;color:var(--ax-text-muted, #666)}.axp-donut-chart-no-data-message{position:absolute;text-align:center;transform:translate(-50%,-50%);font-family:var(--ax-font-family, system-ui, sans-serif);background-color:rgba(255,255,255,.9);padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px rgba(0,0,0,.08);width:80%;max-width:300px}.axp-donut-chart-no-data-message .axp-donut-chart-no-data-icon{color:var(--ax-text-muted, #999);margin-bottom:.75rem}.axp-donut-chart-no-data-message .axp-donut-chart-no-data-text{font-size:1rem;font-weight:600;color:var(--ax-text-color, #333);margin-bottom:.5rem}.axp-donut-chart-no-data-message .axp-donut-chart-no-data-help{font-size:.8rem;color:var(--ax-text-muted, #999)}.axp-donut-chart-segment{cursor:pointer;transition:all .3s cubic-bezier(.25,.8,.25,1);stroke:#fff;stroke-width:1.5px;filter:drop-shadow(0px 1px 2px rgba(0,0,0,.1))}.axp-donut-chart-segment:hover{opacity:.92;filter:drop-shadow(0px 3px 5px rgba(0,0,0,.15));transform:scale(1.01)}.axp-donut-chart-highlighted{opacity:1;filter:brightness(1.05) drop-shadow(0px 3px 5px rgba(0,0,0,.15));transform:scale(1.02)}.axp-donut-chart-dimmed{opacity:.4}.axp-donut-chart-total-display{pointer-events:none}.axp-donut-chart-total-value{fill:currentColor}.axp-donut-chart-total-label{fill:currentColor;opacity:.8}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13717
- }
13718
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPDonutChartWidgetViewComponent, decorators: [{
13719
- type: Component,
13720
- args: [{ standalone: true, imports: [CommonModule, AXPChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"axp-donut-chart-container\" #chartContainer>\n <!-- Chart visualization area -->\n <div class=\"axp-donut-chart-content\"></div>\n\n <!-- Legend with conditional positioning -->\n @if (showLegend()) {\n <div\n class=\"axp-donut-chart-legend-container\"\n [class.axp-donut-chart-legend-right]=\"legendPosition() === 'right'\"\n [class.axp-donut-chart-legend-bottom]=\"legendPosition() === 'bottom'\"\n >\n @for (item of chartDataArray(); track item.id) {\n <div\n class=\"axp-donut-chart-legend-item\"\n (mouseenter)=\"onLegendMouseEnter(item)\"\n (mouseleave)=\"onLegendMouseLeave()\"\n (click)=\"onSegmentClick(item)\"\n [class.axp-donut-chart-hidden]=\"isSegmentHidden(item.id)\"\n >\n <div class=\"axp-donut-chart-legend-color\" [style.background-color]=\"getColor($index)\"></div>\n <span class=\"axp-donut-chart-legend-name\">{{ item.name }}</span>\n <span class=\"axp-donut-chart-legend-value\">{{ item.value }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-donut-chart-container{position:relative;height:100%;width:100%;padding:1rem;border-radius:.5rem;box-shadow:var(--ax-card-shadow, 0 2px 8px rgba(0, 0, 0, .05));box-sizing:border-box;display:flex;flex-direction:column;overflow:hidden}.axp-donut-chart-content{flex:1;width:100%;display:flex;align-items:center;justify-content:center;position:relative;min-height:0}.axp-donut-chart-legend-container{display:flex;gap:.75rem;padding:.75rem;flex-wrap:wrap;justify-content:center;font-family:var(--ax-font-family, system-ui, sans-serif);z-index:5}.axp-donut-chart-legend-right{flex-direction:column;position:absolute;right:.75rem;top:0;bottom:0;margin:auto;height:fit-content;max-height:80%;overflow-y:auto;overflow-x:hidden;padding:.75rem;background-color:rgba(255,255,255,.9);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:.375rem;box-shadow:0 2px 8px rgba(0,0,0,.05);max-width:30%}.axp-donut-chart-legend-bottom{position:absolute;bottom:.5rem;left:0;right:0;margin:0 auto;width:auto;max-width:98%;flex-direction:row;flex-wrap:wrap;justify-content:center;padding:.75rem;background-color:rgba(255,255,255,.9);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:.375rem;box-shadow:0 2px 8px rgba(0,0,0,.05)}.axp-donut-chart-legend-item{display:flex;align-items:center;gap:.375rem;padding:.25rem .5rem;border-radius:.375rem;cursor:pointer;transition:all .2s ease;white-space:nowrap;font-size:.875rem}.axp-donut-chart-legend-item:hover{background-color:var(--ax-hover-bg, rgba(0, 0, 0, .05));transform:translateY(-1px)}.axp-donut-chart-legend-item.axp-donut-chart-hidden{opacity:.5}.axp-donut-chart-legend-color{min-width:10px;min-height:10px;width:10px;height:10px;border-radius:2px;box-shadow:0 1px 3px rgba(0,0,0,.1)}.axp-donut-chart-legend-name{font-size:.875rem;font-weight:500;color:var(--ax-text-color, #333)}.axp-donut-chart-legend-value{font-size:.875rem;opacity:.7;margin-left:4px;font-weight:400;color:var(--ax-text-muted, #666)}.axp-donut-chart-no-data-message{position:absolute;text-align:center;transform:translate(-50%,-50%);font-family:var(--ax-font-family, system-ui, sans-serif);background-color:rgba(255,255,255,.9);padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px rgba(0,0,0,.08);width:80%;max-width:300px}.axp-donut-chart-no-data-message .axp-donut-chart-no-data-icon{color:var(--ax-text-muted, #999);margin-bottom:.75rem}.axp-donut-chart-no-data-message .axp-donut-chart-no-data-text{font-size:1rem;font-weight:600;color:var(--ax-text-color, #333);margin-bottom:.5rem}.axp-donut-chart-no-data-message .axp-donut-chart-no-data-help{font-size:.8rem;color:var(--ax-text-muted, #999)}.axp-donut-chart-segment{cursor:pointer;transition:all .3s cubic-bezier(.25,.8,.25,1);stroke:#fff;stroke-width:1.5px;filter:drop-shadow(0px 1px 2px rgba(0,0,0,.1))}.axp-donut-chart-segment:hover{opacity:.92;filter:drop-shadow(0px 3px 5px rgba(0,0,0,.15));transform:scale(1.01)}.axp-donut-chart-highlighted{opacity:1;filter:brightness(1.05) drop-shadow(0px 3px 5px rgba(0,0,0,.15));transform:scale(1.02)}.axp-donut-chart-dimmed{opacity:.4}.axp-donut-chart-total-display{pointer-events:none}.axp-donut-chart-total-value{fill:currentColor}.axp-donut-chart-total-label{fill:currentColor;opacity:.8}\n"] }]
13721
- }] });
13722
-
13723
- var donutChartWidget_component = /*#__PURE__*/Object.freeze({
13724
- __proto__: null,
13725
- AXPDonutChartWidgetViewComponent: AXPDonutChartWidgetViewComponent
13726
- });
13727
-
13728
- const AXPDonutChartWidget = {
13729
- name: 'donut-chart',
13730
- title: 'Donut Chart Widget',
13731
- categories: AXP_WIDGETS_CHART_CATEGORY,
13732
- groups: [AXPWidgetGroupEnum.DashboardWidget],
13733
- type: 'dashboard',
13734
- icon: 'fa-light fa-donut',
13735
- properties: [
13736
- // ====== Size & Layout ======
13737
- {
13738
- name: 'height',
13739
- title: 'Height',
13740
- group: AXP_STYLING_PROPERTY_GROUP,
13741
- schema: {
13742
- defaultValue: 300,
13743
- dataType: 'number',
13744
- interface: {
13745
- name: 'height',
13746
- path: 'options.height',
13747
- type: AXPWidgetsCatalog.number,
13748
- options: {
13749
- minValue: 200,
13750
- maxValue: 800,
13751
- },
13752
- },
13753
- },
13754
- visible: true,
13755
- },
13756
- {
13757
- name: 'width',
13758
- title: 'Width',
13759
- group: AXP_STYLING_PROPERTY_GROUP,
13760
- schema: {
13761
- defaultValue: 300,
13762
- dataType: 'number',
13763
- interface: {
13764
- name: 'width',
13765
- path: 'options.width',
13766
- type: AXPWidgetsCatalog.number,
13767
- options: {
13768
- minValue: 200,
13769
- maxValue: 1200,
13770
- },
13771
- },
13772
- },
13773
- visible: true,
13774
- },
13775
- // ====== Legend ======
13776
- {
13777
- name: 'showLegend',
13778
- title: 'Show Legend',
13779
- group: AXP_APPEARANCE_PROPERTY_GROUP,
13780
- schema: {
13781
- defaultValue: true,
13782
- dataType: 'boolean',
13783
- interface: {
13784
- name: 'showLegend',
13785
- path: 'options.showLegend',
13786
- type: AXPWidgetsCatalog.toggle,
13787
- },
13788
- },
13789
- visible: true,
13790
- },
13791
- {
13792
- name: 'legendPosition',
13793
- title: 'Legend Position',
13794
- group: AXP_APPEARANCE_PROPERTY_GROUP,
13795
- schema: {
13796
- defaultValue: 'right',
13797
- dataType: 'string',
13798
- interface: {
13799
- name: 'legendPosition',
13800
- path: 'options.legendPosition',
13801
- type: AXPWidgetsCatalog.select,
13802
- options: {
13803
- dataSource: ['right', 'bottom'],
13804
- },
13805
- },
13806
- },
13807
- visible: true,
13808
- },
13809
- // ====== Tooltip ======
13810
- {
13811
- name: 'showTooltip',
13812
- title: 'Show Tooltip',
13813
- group: AXP_APPEARANCE_PROPERTY_GROUP,
13814
- schema: {
13815
- defaultValue: true,
13816
- dataType: 'boolean',
13817
- interface: {
13818
- name: 'showTooltip',
13819
- path: 'options.showTooltip',
13820
- type: AXPWidgetsCatalog.toggle,
13821
- },
13822
- },
13823
- visible: true,
13824
- },
13825
- // ====== Donut Appearance ======
13826
- {
13827
- name: 'donutWidth',
13828
- title: 'Donut Width',
13829
- group: AXP_APPEARANCE_PROPERTY_GROUP,
13830
- schema: {
13831
- defaultValue: 35,
13832
- dataType: 'number',
13833
- interface: {
13834
- name: 'donutWidth',
13835
- path: 'options.donutWidth',
13836
- type: AXPWidgetsCatalog.number,
13837
- options: {
13838
- placeholder: '10-80',
13839
- minValue: 10,
13840
- maxValue: 80,
13841
- },
13842
- },
13843
- },
13844
- visible: true,
13845
- },
13846
- {
13847
- name: 'cornerRadius',
13848
- title: 'Corner Radius',
13849
- group: AXP_APPEARANCE_PROPERTY_GROUP,
13850
- schema: {
13851
- defaultValue: 4,
13852
- dataType: 'number',
13853
- interface: {
13854
- name: 'cornerRadius',
13855
- path: 'options.cornerRadius',
13856
- type: AXPWidgetsCatalog.number,
13857
- options: {
13858
- placeholder: '0-20',
13859
- minValue: 0,
13860
- maxValue: 20,
13861
- },
13862
- },
13863
- },
13864
- visible: true,
13865
- },
13866
- ],
13867
- components: {
13868
- view: {
13869
- component: () => Promise.resolve().then(function () { return donutChartWidget_component; }).then((c) => c.AXPDonutChartWidgetViewComponent),
13870
- },
13871
- },
13872
- meta: {
13873
- dimensions: {
13874
- width: 4,
13875
- height: 4,
13876
- minWidth: 2,
13877
- minHeight: 2,
13878
- maxWidth: 5,
13879
- maxHeight: 6,
13880
- },
13881
- },
13882
- };
13883
-
13884
- class AXPGaugeChartWidgetViewComponent extends AXPChartBaseComponent {
13885
- constructor() {
13886
- super(...arguments);
13887
- this.cdr = inject(ChangeDetectorRef);
13888
- this.chartContainerEl = viewChild.required('chartContainer');
13889
- this.chartEl = viewChild.required('chart');
13890
- // Default values
13891
- this.backgroundColor = 'transparent';
13892
- this.baseColor = '#e2e8f0';
13893
- this.labelFontSize = 16;
13894
- this.showValue = true;
13895
- this.valueColor = '#6366f1';
13896
- this.valueFontSize = 24;
13897
- // Default values as computed properties
13898
- this.minValue = computed(() => this.options()['minValue'] ?? 0);
13899
- this.maxValue = computed(() => this.options()['maxValue'] ?? 100);
13900
- this.thresholds = computed(() => this.options()['thresholds'] ?? []);
13901
- this.label = computed(() => this.options()['label'] ?? '');
13902
- this.width = computed(() => this.options()['width'] ?? 300);
13903
- this.height = computed(() => this.options()['height'] ?? 300);
13904
- this.gaugeWidth = computed(() => this.options()['gaugeWidth'] ?? 22);
13905
- this.cornerRadius = computed(() => this.options()['cornerRadius'] ?? 5);
13906
- }
13907
- createChart() {
13908
- // Clear any existing chart
13909
- this.d3.select(this.chartEl().nativeElement).selectAll('*').remove();
13910
- // Calculate responsive dimensions
13911
- const containerWidth = this.width() || this.chartContainerEl().nativeElement.clientWidth;
13912
- const containerHeight = this.height() || this.chartContainerEl().nativeElement.clientHeight;
13913
- const size = Math.min(containerWidth, containerHeight * 2);
13914
- const margin = size * 0.1;
13915
- // Set up SVG dimensions with viewBox for responsiveness
13916
- const svg = this.d3
13917
- .select(this.chartEl().nativeElement)
13918
- .attr('width', '100%')
13919
- .attr('height', '100%')
13920
- .attr('viewBox', `0 0 ${size} ${size / 2}`)
13921
- .attr('preserveAspectRatio', 'xMidYMid meet');
13922
- // Create a group for the chart with margin and move it to show only the top half
13923
- const chartGroup = svg.append('g').attr('transform', `translate(${size / 2}, ${size / 2 - margin})`);
13924
- // Define gauge parameters
13925
- const radius = size / 2 - margin;
13926
- const innerRadius = radius - this.gaugeWidth();
13927
- const outerRadius = radius;
13928
- // Create gradient definitions
13929
- this.createGradients(svg, this.thresholds());
13930
- // Draw the background arc
13931
- this.drawBackgroundArc(chartGroup, innerRadius, outerRadius, this.cornerRadius());
13932
- // Draw the threshold arcs if thresholds exist
13933
- if (this.thresholds().length > 0) {
13934
- this.drawThresholds(chartGroup, innerRadius, outerRadius, this.minValue(), this.maxValue(), this.thresholds(), this.cornerRadius());
13935
- }
13936
- // Draw tick marks
13937
- this.drawTicks(chartGroup, outerRadius, this.minValue(), this.maxValue());
13938
- // Draw the dial/needle with animation
13939
- this.drawDial(chartGroup, radius, this.chartData() ?? 0, this.minValue(), this.maxValue());
13940
- // Draw the value display (after the dial so it's on top)
13941
- if (this.showValue) {
13942
- this.drawValueDisplay(chartGroup, this.chartData() ?? 0, this.label(), radius);
13943
- }
13944
- }
13945
- updateChart() {
13946
- this.createChart();
13947
- }
13948
- cleanupChart() {
13949
- if (this.chartEl()?.nativeElement) {
13950
- this.d3.select(this.chartEl().nativeElement).selectAll('*').remove();
13951
- }
13952
- }
13953
- /**
13954
- * Create gradient definitions for thresholds
13955
- */
13956
- createGradients(svg, thresholds) {
13957
- const defs = svg.append('defs');
13958
- // Create a radial gradient for the background
13959
- const bgGradient = defs
13960
- .append('radialGradient')
13961
- .attr('id', 'gauge-bg-gradient')
13962
- .attr('cx', '50%')
13963
- .attr('cy', '50%')
13964
- .attr('r', '50%')
13965
- .attr('gradientUnits', 'userSpaceOnUse');
13966
- if (thresholds.length === 0) {
13967
- // Default gradient when no thresholds are provided
13968
- bgGradient
13969
- .append('stop')
13970
- .attr('offset', '0%')
13971
- .attr('stop-color', this.d3.color(this.valueColor)?.brighter(0.5).toString() || this.valueColor);
13972
- bgGradient.append('stop').attr('offset', '100%').attr('stop-color', this.valueColor);
13973
- }
13974
- else {
13975
- bgGradient
13976
- .append('stop')
13977
- .attr('offset', '0%')
13978
- .attr('stop-color', this.d3.color(this.baseColor)?.brighter(0.5).toString() || this.baseColor);
13979
- bgGradient.append('stop').attr('offset', '100%').attr('stop-color', this.baseColor);
13980
- // Create gradients for each threshold
13981
- thresholds.forEach((threshold, i) => {
13982
- const gradient = defs
13983
- .append('linearGradient')
13984
- .attr('id', `threshold-gradient-${i}`)
13985
- .attr('gradientUnits', 'userSpaceOnUse')
13986
- .attr('x1', '-1')
13987
- .attr('y1', '0')
13988
- .attr('x2', '1')
13989
- .attr('y2', '0');
13990
- gradient
13991
- .append('stop')
13992
- .attr('offset', '0%')
13993
- .attr('stop-color', this.d3.color(threshold.color)?.brighter(0.5).toString() || threshold.color);
13994
- gradient.append('stop').attr('offset', '100%').attr('stop-color', threshold.color);
13995
- });
13996
- }
13997
- }
13998
- /**
13999
- * Draw the background arc.
14000
- */
14001
- drawBackgroundArc(chartGroup, innerRadius, outerRadius, cornerRadius) {
14002
- const backgroundArc = this.d3
14003
- .arc()
14004
- .innerRadius(innerRadius)
14005
- .outerRadius(outerRadius)
14006
- .startAngle(-Math.PI / 2) // Start from bottom (-90 degrees)
14007
- .endAngle(Math.PI / 2) // End at top (90 degrees)
14008
- .cornerRadius(cornerRadius);
14009
- chartGroup
14010
- .append('path')
14011
- .attr('d', backgroundArc({
14012
- innerRadius,
14013
- outerRadius,
14014
- startAngle: -Math.PI / 2,
14015
- endAngle: Math.PI / 2,
14016
- }))
14017
- .attr('fill', this.backgroundColor === 'transparent' ? 'url(#gauge-bg-gradient)' : this.backgroundColor)
14018
- .attr('filter', 'drop-shadow(0px 2px 3px rgba(0,0,0,0.1))');
14019
- }
14020
- /**
14021
- * Draw the threshold arcs and labels.
14022
- */
14023
- drawThresholds(chartGroup, innerRadius, outerRadius, minValue, maxValue, thresholds, cornerRadius) {
14024
- const arc = this.d3
14025
- .arc()
14026
- .innerRadius(innerRadius)
14027
- .outerRadius(outerRadius * 0.98)
14028
- .cornerRadius(cornerRadius);
14029
- // Sort thresholds by value in ascending order
14030
- const sortedThresholds = [...thresholds].sort((a, b) => a.value - b.value);
14031
- // Calculate all angles first using the color angle calculation
14032
- const angles = sortedThresholds.map((t) => this.scaleValueToColorAngle(t.value, minValue, maxValue));
14033
- // Start from the minimum value angle
14034
- let previousEndAngle = this.scaleValueToColorAngle(minValue, minValue, maxValue);
14035
- sortedThresholds.forEach((threshold, i) => {
14036
- const endAngle = angles[i];
14037
- chartGroup
14038
- .append('path')
14039
- .attr('d', arc({
14040
- innerRadius,
14041
- outerRadius,
14042
- startAngle: previousEndAngle,
14043
- endAngle,
14044
- }))
14045
- .attr('fill', `url(#threshold-gradient-${i})`)
14046
- .attr('stroke', 'rgba(255,255,255,0.3)')
14047
- .attr('stroke-width', 1);
14048
- previousEndAngle = endAngle;
14049
- });
14050
- // Fill the remaining space to maxValue if needed
14051
- const lastEndAngle = this.scaleValueToColorAngle(maxValue, minValue, maxValue);
14052
- if (previousEndAngle < lastEndAngle) {
14053
- chartGroup
14054
- .append('path')
14055
- .attr('d', arc({
14056
- innerRadius,
14057
- outerRadius,
14058
- startAngle: previousEndAngle,
14059
- endAngle: lastEndAngle,
14060
- }))
14061
- .attr('fill', `url(#threshold-gradient-${sortedThresholds.length - 1})`)
14062
- .attr('stroke', 'rgba(255,255,255,0.3)')
14063
- .attr('stroke-width', 1);
14064
- }
14065
- }
14066
- /**
14067
- * Draw tick marks around the gauge
14068
- */
14069
- drawTicks(chartGroup, radius, minValue, maxValue) {
14070
- const tickCount = 10;
14071
- const minorTickCount = 40;
14072
- // Draw minor ticks
14073
- for (let i = 0; i <= minorTickCount; i++) {
14074
- const value = minValue + (i / minorTickCount) * (maxValue - minValue);
14075
- const angle = this.scaleValueToAngle(value, minValue, maxValue);
14076
- const outerPoint = {
14077
- x: radius * 0.9 * Math.cos(angle),
14078
- y: radius * 0.9 * Math.sin(angle),
14079
- };
14080
- const innerPoint = {
14081
- x: radius * 0.87 * Math.cos(angle),
14082
- y: radius * 0.87 * Math.sin(angle),
14083
- };
14084
- chartGroup
14085
- .append('line')
14086
- .attr('x1', innerPoint.x)
14087
- .attr('y1', innerPoint.y)
14088
- .attr('x2', outerPoint.x)
14089
- .attr('y2', outerPoint.y)
14090
- .attr('stroke', '#adb5bd')
14091
- .attr('stroke-width', 0.5);
14092
- }
14093
- // Draw major ticks and labels
14094
- for (let i = 0; i <= tickCount; i++) {
14095
- const value = minValue + (i / tickCount) * (maxValue - minValue);
14096
- const angle = this.scaleValueToAngle(value, minValue, maxValue);
14097
- const outerPoint = {
14098
- x: radius * 0.92 * Math.cos(angle),
14099
- y: radius * 0.92 * Math.sin(angle),
14100
- };
14101
- const innerPoint = {
14102
- x: radius * 0.85 * Math.cos(angle),
14103
- y: radius * 0.85 * Math.sin(angle),
14104
- };
14105
- // Major tick line
14106
- chartGroup
14107
- .append('line')
14108
- .attr('x1', innerPoint.x)
14109
- .attr('y1', innerPoint.y)
14110
- .attr('x2', outerPoint.x)
14111
- .attr('y2', outerPoint.y)
14112
- .attr('stroke', '#adb5bd')
14113
- .attr('stroke-width', 2);
14114
- // Label position with offset
14115
- const labelRadius = radius * 1.15;
14116
- const labelX = labelRadius * Math.cos(angle);
14117
- const labelY = labelRadius * Math.sin(angle);
14118
- // Add tick value label
14119
- chartGroup
14120
- .append('text')
14121
- .attr('x', labelX)
14122
- .attr('y', labelY)
14123
- .attr('text-anchor', 'middle')
14124
- .style('font-size', `${radius * 0.1}px`)
14125
- .style('font-weight', '500')
14126
- .style('fill', 'currentColor')
14127
- .text(value.toFixed(0));
14128
- }
14129
- }
14130
- /**
14131
- * Draw the value display in the center
14132
- */
14133
- drawValueDisplay(chartGroup, value, label, radius) {
14134
- // Value text - positioned below the needle pivot
14135
- chartGroup
14136
- .append('text')
14137
- .attr('class', 'value')
14138
- .attr('x', 0)
14139
- .attr('y', radius * 0.25) // Moved up from 0.3
14140
- .attr('text-anchor', 'middle')
14141
- .attr('dominant-baseline', 'central')
14142
- .style('font-size', `${this.valueFontSize}px`)
14143
- .style('font-weight', 'bold')
14144
- .style('fill', 'currentColor')
14145
- .text(value.toFixed(1));
14146
- // Label text
14147
- chartGroup
14148
- .append('text')
14149
- .attr('class', 'label')
14150
- .attr('x', 0)
14151
- .attr('y', radius * 0.45) // Keeping this position to create more space
14152
- .attr('text-anchor', 'middle')
14153
- .attr('dominant-baseline', 'central')
14154
- .style('font-size', `${this.labelFontSize}px`)
14155
- .style('fill', '#6c757d')
14156
- .text(label);
14157
- }
14158
- /**
14159
- * Draw the dial/needle with animation.
14160
- */
14161
- drawDial(chartGroup, radius, value, minValue, maxValue) {
14162
- const needleGroup = chartGroup.append('g');
14163
- const valueAngle = this.scaleValueToAngle(value, minValue, maxValue); // Use regular angle for needle
14164
- // Draw needle base (circle)
14165
- needleGroup
14166
- .append('circle')
14167
- .attr('cx', 0)
14168
- .attr('cy', 0)
14169
- .attr('r', radius * 0.08)
14170
- .attr('fill', 'url(#gauge-bg-gradient)')
14171
- .attr('stroke', '#6c757d')
14172
- .attr('stroke-width', 1);
14173
- // Inner circle
14174
- needleGroup
14175
- .append('circle')
14176
- .attr('cx', 0)
14177
- .attr('cy', 0)
14178
- .attr('r', radius * 0.04)
14179
- .attr('fill', '#495057');
14180
- // Create needle
14181
- const needlePath = needleGroup
14182
- .append('path')
14183
- .attr('d', this.createNeedlePath(radius))
14184
- .attr('fill', '#dc3545')
14185
- .attr('transform', `rotate(${this.radiansToDegrees(-Math.PI)})`) // Start at left (-180 degrees)
14186
- .attr('filter', 'drop-shadow(0px 1px 2px rgba(0,0,0,0.3))');
14187
- // Animate the needle
14188
- needlePath
14189
- .transition()
14190
- .duration(800)
14191
- .ease(this.d3.easeCubicOut)
14192
- .attrTween('transform', () => {
14193
- const interpolate = this.d3.interpolate(-Math.PI, valueAngle);
14194
- return (t) => `rotate(${this.radiansToDegrees(interpolate(t))})`;
14195
- });
14196
- }
14197
- /**
14198
- * Create a path for the needle
14199
- */
14200
- createNeedlePath(radius) {
14201
- const needleLength = radius * 0.75;
14202
- const needleBaseWidth = radius * 0.04;
14203
- return `M 0 -${needleBaseWidth} L ${needleLength} 0 L 0 ${needleBaseWidth} Z`;
14204
- }
14205
- /**
14206
- * Draw the chart label.
14207
- */
14208
- drawLabel(chartGroup, label) {
14209
- chartGroup
14210
- .append('text')
14211
- .attr('text-anchor', 'middle')
14212
- .attr('dy', '0.35em')
14213
- .text(label || '')
14214
- .style('font-size', '16px')
14215
- .style('fill', '#000');
14216
- }
14217
- /**
14218
- * Scale a value to an angle for the gauge chart.
14219
- */
14220
- scaleValueToAngle(value, min, max) {
14221
- const scaledValue = (value - min) / (max - min);
14222
- // Map from -180 to 0 degrees in radians, starting from the left
14223
- return -Math.PI + scaledValue * Math.PI;
14224
- }
14225
- scaleValueToColorAngle(value, min, max) {
14226
- const scaledValue = (value - min) / (max - min);
14227
- // Map from -90 to 90 degrees in radians (-π/2 to π/2), starting from the bottom
14228
- return -Math.PI / 2 + scaledValue * Math.PI;
14229
- }
14230
- /**
14231
- * Convert radians to degrees.
14232
- */
14233
- radiansToDegrees(radians) {
14234
- return radians * (180 / Math.PI);
14235
- }
14236
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPGaugeChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
14237
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.0.3", type: AXPGaugeChartWidgetViewComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }, { propertyName: "chartEl", first: true, predicate: ["chart"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-flex ax-justify-center ax-items-center ax-w-full ax-h-full\" #chartContainer>\n <svg #chart class=\"ax-w-full ax-h-full\"></svg>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
14238
- }
14239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPGaugeChartWidgetViewComponent, decorators: [{
14240
- type: Component,
14241
- args: [{ standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-flex ax-justify-center ax-items-center ax-w-full ax-h-full\" #chartContainer>\n <svg #chart class=\"ax-w-full ax-h-full\"></svg>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
14242
- }] });
14243
-
14244
- var gaugeChartWidget_component = /*#__PURE__*/Object.freeze({
14245
- __proto__: null,
14246
- AXPGaugeChartWidgetViewComponent: AXPGaugeChartWidgetViewComponent
14247
- });
14248
-
14249
- const AXPGaugeChartWidget = {
14250
- name: 'gauge-chart',
14251
- title: 'Gauge Chart Widget',
14252
- categories: [AXP_WIDGETS_CHART_CATEGORY],
14253
- type: 'dashboard',
14254
- icon: 'fa-light fa-gauge',
14255
- properties: [
14256
- // ====== Layout & Dimensions ======
14257
- {
14258
- name: 'height',
14259
- title: 'Height',
14260
- group: AXP_STYLING_PROPERTY_GROUP,
14261
- schema: {
14262
- defaultValue: 300,
14263
- dataType: 'number',
14264
- interface: {
14265
- name: 'height',
14266
- path: 'options.height',
14267
- type: AXPWidgetsCatalog.number,
14268
- options: {
14269
- placeholder: '1-800',
14270
- minValue: 1,
14271
- maxValue: 800,
14272
- },
14273
- },
14274
- },
14275
- visible: true,
14276
- },
14277
- {
14278
- name: 'width',
14279
- title: 'Width',
14280
- group: AXP_STYLING_PROPERTY_GROUP,
14281
- schema: {
14282
- defaultValue: null,
14283
- dataType: 'number',
14284
- interface: {
14285
- name: 'width',
14286
- path: 'options.width',
14287
- type: AXPWidgetsCatalog.number,
14288
- options: {
14289
- placeholder: '1-1200',
14290
- minValue: 1,
14291
- maxValue: 1200,
14292
- },
14293
- },
14294
- },
14295
- visible: true,
14296
- },
14297
- // ====== Gauge Configuration ======
14298
- {
14299
- name: 'minValue',
14300
- title: 'Minimum Value',
14301
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14302
- schema: {
14303
- defaultValue: 0,
14304
- dataType: 'number',
14305
- interface: {
14306
- name: 'minValue',
14307
- path: 'options.minValue',
14308
- type: AXPWidgetsCatalog.number,
14309
- },
14310
- },
14311
- visible: true,
14312
- },
14313
- {
14314
- name: 'maxValue',
14315
- title: 'Maximum Value',
14316
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14317
- schema: {
14318
- defaultValue: 100,
14319
- dataType: 'number',
14320
- interface: {
14321
- name: 'maxValue',
14322
- path: 'options.maxValue',
14323
- type: AXPWidgetsCatalog.number,
14324
- },
14325
- },
14326
- visible: true,
14327
- },
14328
- // ====== Gauge Appearance ======
14329
- {
14330
- name: 'gaugeWidth',
14331
- title: 'Gauge Width',
14332
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14333
- schema: {
14334
- defaultValue: 30,
14335
- dataType: 'number',
14336
- interface: {
14337
- name: 'gaugeWidth',
14338
- path: 'options.gaugeWidth',
14339
- type: AXPWidgetsCatalog.number,
14340
- options: {
14341
- placeholder: '1-100',
14342
- minValue: 1,
14343
- maxValue: 100,
14344
- },
14345
- },
14346
- },
14347
- visible: true,
14348
- },
14349
- {
14350
- name: 'cornerRadius',
14351
- title: 'Corner Radius',
14352
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14353
- schema: {
14354
- defaultValue: 4,
14355
- dataType: 'number',
14356
- interface: {
14357
- name: 'cornerRadius',
14358
- path: 'options.cornerRadius',
14359
- type: AXPWidgetsCatalog.number,
14360
- options: {
14361
- placeholder: '1-20',
14362
- minValue: 0,
14363
- maxValue: 20,
14364
- },
14365
- },
14366
- },
14367
- visible: true,
14368
- },
14369
- // ====== Label Display ======
14370
- {
14371
- name: 'label',
14372
- title: 'Label Text',
14373
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14374
- schema: {
14375
- defaultValue: '',
14376
- dataType: 'string',
14377
- interface: {
14378
- name: 'label',
14379
- path: 'options.label',
14380
- type: AXPWidgetsCatalog.text,
14381
- },
14382
- },
14383
- visible: true,
14384
- },
14385
- ],
14386
- components: {
14387
- view: {
14388
- component: () => Promise.resolve().then(function () { return gaugeChartWidget_component; }).then((c) => c.AXPGaugeChartWidgetViewComponent),
14389
- },
14390
- },
14391
- meta: {
14392
- dimensions: {
14393
- width: 3,
14394
- height: 4,
14395
- minWidth: 2,
14396
- minHeight: 2,
14397
- maxWidth: 4,
14398
- maxHeight: 5,
14399
- },
14400
- },
14401
- };
14402
-
14403
- /**
14404
- * Notification Widget Component
14405
- * Displays notifications in a card with tabs
14406
- */
14407
- class AXPNotificationWidgetViewComponent extends AXPValueWidgetComponent {
14408
- constructor() {
14409
- super(...arguments);
14410
- // Outputs
14411
- this.notificationClick = output();
14412
- this.markAsRead = output();
14413
- // Dependencies
14414
- this.cdr = inject(ChangeDetectorRef);
14415
- this.datePipe = inject(DatePipe);
14416
- // State
14417
- this.activeTab = signal('new');
14418
- // Configuration
14419
- this.maxItems = computed(() => this.options()?.maxItems ?? 10);
14420
- this.showAvatar = computed(() => this.options()?.showAvatar ?? true);
14421
- this.showDate = computed(() => this.options()?.showDate ?? true);
14422
- // Computed data
14423
- this.notificationItems = computed(() => {
14424
- const value = this.getValue();
14425
- if (!value?.data?.length)
14426
- return [];
14427
- // Filter by active tab
14428
- const filtered = this.activeTab() === 'new' ? value.data.filter((n) => !n.readAt) : value.data;
14429
- return filtered.slice(0, this.maxItems());
14430
- });
14431
- }
14432
- /**
14433
- * Get the count of new messages for the badge
14434
- */
14435
- getNewMessageCount() {
14436
- const value = this.getValue();
14437
- if (!value?.data?.length)
14438
- return 0;
14439
- return value.data.filter((n) => !n.readAt).length;
14440
- }
14441
- /**
14442
- * Handle tab change event from ax-tabs component
14443
- * @param index The index of the tab that was activated
14444
- */
14445
- handleTabChange(data) {
14446
- const index = data.index;
14447
- // Map index to tab name: 0 = 'new', 1 = 'all'
14448
- const tabName = index === 0 ? 'new' : 'all';
14449
- this.onTabChange(tabName);
14450
- }
14451
- /**
14452
- * Mark all notifications as read
14453
- */
14454
- markAllAsRead() {
14455
- const value = this.getValue();
14456
- if (!value?.data?.length)
14457
- return;
14458
- const now = new Date();
14459
- const updatedNotifications = value.data.map((n) => {
14460
- if (n.readAt)
14461
- return n;
14462
- return { ...n, readAt: now };
14463
- });
14464
- this.setValue({
14465
- ...value,
14466
- data: updatedNotifications,
14467
- });
14468
- this.cdr.detectChanges();
14469
- }
14470
- /**
14471
- * Change the active tab
14472
- */
14473
- onTabChange(tabName) {
14474
- this.activeTab.set(tabName);
14475
- this.cdr.detectChanges();
14476
- }
14477
- /**
14478
- * Handle notification click event
14479
- */
14480
- onNotificationClick(notification) {
14481
- this.markAsReadIfNeeded(notification);
14482
- this.notificationClick.emit(notification);
14483
- }
14484
- /**
14485
- * Format the timestamp in a user-friendly way
14486
- */
14487
- formatTime(date) {
14488
- if (!date)
14489
- return '';
14490
- const dateObj = typeof date === 'string' ? new Date(date) : date;
14491
- const diffDays = this.getDaysDifference(dateObj);
14492
- // Format based on how recent the date is
14493
- if (diffDays === 0)
14494
- return this.datePipe.transform(dateObj, 'h:mm a') || ''; // Today
14495
- if (diffDays === 1)
14496
- return 'Yesterday';
14497
- if (diffDays < 7)
14498
- return this.datePipe.transform(dateObj, 'EEE') || ''; // Day of week
14499
- return this.datePipe.transform(dateObj, 'MM/dd/yyyy') || ''; // Older date
14500
- }
14501
- /**
14502
- * Mark notification as read if needed
14503
- */
14504
- markAsReadIfNeeded(notification) {
14505
- // Only mark as read if not already read
14506
- if (notification.readAt)
14507
- return;
14508
- const updatedNotification = {
14509
- ...notification,
14510
- readAt: new Date(),
14511
- };
14512
- // Update the model
14513
- const value = this.getValue();
14514
- if (!value?.data)
14515
- return;
14516
- const updatedNotifications = value.data.map((n) => (n.id === notification.id ? updatedNotification : n));
14517
- this.setValue({
14518
- ...value,
14519
- data: updatedNotifications,
14520
- });
14521
- // Notify about the change
14522
- this.markAsRead.emit(updatedNotification);
14523
- }
14524
- /**
14525
- * Calculate days difference from now
14526
- */
14527
- getDaysDifference(date) {
14528
- const now = new Date();
14529
- const diffMs = now.getTime() - date.getTime();
14530
- return Math.floor(diffMs / (1000 * 60 * 60 * 24));
14531
- }
14532
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPNotificationWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
14533
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPNotificationWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { notificationClick: "notificationClick", markAsRead: "markAsRead" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-p-4 ax-size-full\">\n <ax-tabs\n class=\"ax-bg-light-start ax-border-b ax-border-default\"\n [fitParent]=\"true\"\n location=\"bottom\"\n (onActiveTabChanged)=\"handleTabChange($event)\"\n >\n <ax-tab-item [text]=\"('widget.notification.new' | translate | async) ?? 'New'\" class=\"ax-font-medium\">\n <ax-suffix>\n @if (getNewMessageCount() > 0) {\n <ax-badge color=\"primary\" [text]=\"getNewMessageCount().toString()\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </ax-suffix>\n </ax-tab-item>\n <ax-tab-item [text]=\"('widget.notification.all' | translate | async) ?? 'All'\" class=\"ax-font-medium\"></ax-tab-item>\n </ax-tabs>\n <div class=\"ax-space-y-4 ax-mt-4 ax-px-2\">\n @for (item of notificationItems(); track item.id) {\n <ng-container [ngTemplateOutlet]=\"chatItemTemplateRef\" [ngTemplateOutletContext]=\"{ $implicit: item }\">\n </ng-container>\n } @empty {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-bell-slash\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.notification.noNotifications' | translate | async }}</p>\n </div>\n }\n </div>\n</div>\n\n<ng-template #chatItemTemplateRef let-data>\n <div class=\"ax-flex ax-gap-3\">\n @if(showAvatar()){\n <div class=\"ax-rounded-full ax-size-10\">\n <ax-avatar shape=\"rounded\" class=\"ax-shrink-0\" [size]=\"40\">\n @if(data.user?.image){\n <ax-image\n [src]=\"data.user.image\"\n [alt]=\"data.user?.name || ('widget.notification.user' | translate | async)\"\n ></ax-image>\n } @else {\n <ax-icon>\n <i class=\"fa-light fa-user\"></i>\n </ax-icon>\n }\n </ax-avatar>\n </div>\n }\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\">\n <h6 class=\"ax-pb-2 ax-font-semibold ax-truncate\">{{ data.user?.name || data.title }}</h6>\n <p class=\"ax-text-xs ax-truncate\">{{ data.body }}</p>\n </div>\n @if(showDate()){\n <div class=\"ax-text-xs ax-shrink-0\">\n <span>\n {{ formatTime(data.createdAt) }}\n </span>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i4$1.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i4$1.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "component", type: i5$4.AXAvatarComponent, selector: "ax-avatar", inputs: ["color", "size", "shape", "look"], outputs: ["sizeChange"] }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$7.AXImageComponent, selector: "ax-image", inputs: ["overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
14534
- }
14535
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPNotificationWidgetViewComponent, decorators: [{
14536
- type: Component,
14537
- args: [{ standalone: true, imports: [
14538
- CommonModule,
14539
- AXTabsModule,
14540
- AXDecoratorModule,
14541
- AXButtonModule,
14542
- AXBadgeModule,
14543
- AXAvatarModule,
14544
- AXImageModule,
14545
- AXTranslationModule,
14546
- ], providers: [DatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-p-4 ax-size-full\">\n <ax-tabs\n class=\"ax-bg-light-start ax-border-b ax-border-default\"\n [fitParent]=\"true\"\n location=\"bottom\"\n (onActiveTabChanged)=\"handleTabChange($event)\"\n >\n <ax-tab-item [text]=\"('widget.notification.new' | translate | async) ?? 'New'\" class=\"ax-font-medium\">\n <ax-suffix>\n @if (getNewMessageCount() > 0) {\n <ax-badge color=\"primary\" [text]=\"getNewMessageCount().toString()\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </ax-suffix>\n </ax-tab-item>\n <ax-tab-item [text]=\"('widget.notification.all' | translate | async) ?? 'All'\" class=\"ax-font-medium\"></ax-tab-item>\n </ax-tabs>\n <div class=\"ax-space-y-4 ax-mt-4 ax-px-2\">\n @for (item of notificationItems(); track item.id) {\n <ng-container [ngTemplateOutlet]=\"chatItemTemplateRef\" [ngTemplateOutletContext]=\"{ $implicit: item }\">\n </ng-container>\n } @empty {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-bell-slash\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.notification.noNotifications' | translate | async }}</p>\n </div>\n }\n </div>\n</div>\n\n<ng-template #chatItemTemplateRef let-data>\n <div class=\"ax-flex ax-gap-3\">\n @if(showAvatar()){\n <div class=\"ax-rounded-full ax-size-10\">\n <ax-avatar shape=\"rounded\" class=\"ax-shrink-0\" [size]=\"40\">\n @if(data.user?.image){\n <ax-image\n [src]=\"data.user.image\"\n [alt]=\"data.user?.name || ('widget.notification.user' | translate | async)\"\n ></ax-image>\n } @else {\n <ax-icon>\n <i class=\"fa-light fa-user\"></i>\n </ax-icon>\n }\n </ax-avatar>\n </div>\n }\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\">\n <h6 class=\"ax-pb-2 ax-font-semibold ax-truncate\">{{ data.user?.name || data.title }}</h6>\n <p class=\"ax-text-xs ax-truncate\">{{ data.body }}</p>\n </div>\n @if(showDate()){\n <div class=\"ax-text-xs ax-shrink-0\">\n <span>\n {{ formatTime(data.createdAt) }}\n </span>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
14547
- }] });
14548
-
14549
- var notificationWidget_component = /*#__PURE__*/Object.freeze({
14550
- __proto__: null,
14551
- AXPNotificationWidgetViewComponent: AXPNotificationWidgetViewComponent
14552
- });
14553
-
14554
- /**
14555
- * Configuration for the Notification Widget
14556
- */
14557
- const AXPNotificationWidget = {
14558
- name: 'notification',
14559
- title: 'Notification Widget',
14560
- categories: [AXP_WIDGETS_UTILITY_CATEGORY],
14561
- groups: [AXPWidgetGroupEnum.DashboardWidget],
14562
- type: 'dashboard',
14563
- description: 'Displays notifications in a widget format',
14564
- icon: 'fa-regular fa-bell',
14565
- properties: [
14566
- cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
14567
- {
14568
- name: 'maxItems',
14569
- title: 'Max Items',
14570
- description: 'Maximum number of notification items to display',
14571
- group: AXP_STYLING_PROPERTY_GROUP,
14572
- schema: {
14573
- defaultValue: 10,
14574
- dataType: 'number',
14575
- interface: {
14576
- name: 'maxItems',
14577
- path: 'options.maxItems',
14578
- type: AXPWidgetsCatalog.number,
14579
- options: {
14580
- minValue: 1,
14581
- maxValue: 100,
14582
- },
14583
- },
14584
- },
14585
- visible: true,
14586
- },
14587
- {
14588
- name: 'showAvatar',
14589
- title: 'Show Avatar',
14590
- description: 'Whether to show avatars in notifications',
14591
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14592
- schema: {
14593
- defaultValue: true,
14594
- dataType: 'boolean',
14595
- interface: {
14596
- name: 'showAvatar',
14597
- path: 'options.showAvatar',
14598
- type: AXPWidgetsCatalog.toggle,
14599
- },
14600
- },
14601
- visible: true,
14602
- },
14603
- {
14604
- name: 'showDate',
14605
- title: 'Show Date',
14606
- description: 'Whether to show date in notifications',
14607
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14608
- schema: {
14609
- defaultValue: true,
14610
- dataType: 'boolean',
14611
- interface: {
14612
- name: 'showDate',
14613
- path: 'options.showDate',
14614
- type: AXPWidgetsCatalog.toggle,
14615
- },
14616
- },
14617
- visible: true,
14618
- },
14619
- ],
14620
- components: {
14621
- view: {
14622
- component: () => Promise.resolve().then(function () { return notificationWidget_component; }).then((c) => c.AXPNotificationWidgetViewComponent),
14623
- },
14624
- },
14625
- meta: {
14626
- dimensions: {
14627
- width: 3,
14628
- height: 5,
14629
- minWidth: 2,
14630
- minHeight: 4,
14631
- maxWidth: 4,
14632
- maxHeight: 7,
14633
- },
14634
- },
14635
- };
14636
-
14637
- class AXPStickyNoteWidgetViewComponent extends AXPValueWidgetComponent {
14638
- constructor() {
14639
- super(...arguments);
14640
- this.isEditing = signal(false);
14641
- this.wysiwyg = viewChild('wysiwyg');
14642
- this.value = computed(() => this.getValue());
14643
- this.date = computed(() => this.options()?.date ?? new Date());
14644
- this.bgColor = computed(() => this.options()?.backgroundColor ?? '#FFF8B8');
14645
- this.color = signal('#333333');
14646
- this.el = inject(ElementRef);
14647
- // Modern color palette with pastel and vibrant options
14648
- this.colorPresets = [
14649
- '#FFF8B8', // Soft yellow
14650
- '#FFD8E6', // Soft pink
14651
- '#D1F0FF', // Soft blue
14652
- '#E2FFD1', // Soft green
14653
- '#FFE8D1', // Soft orange
14654
- '#F0D1FF', // Soft purple
14655
- '#FFCDD2', // Soft red
14656
- '#D1FFF0', // Soft teal
14657
- '#F5F5F5', // Light gray
14658
- '#FFFFFF', // White
14659
- ];
14660
- }
14661
- // Handle clicks outside the component to cancel editing
14662
- handleClickOutside(event) {
14663
- const clickedInside = this.el.nativeElement.contains(event.target);
14664
- if (!clickedInside && this.isEditing()) {
14665
- this.saveChanges();
14666
- }
14667
- }
14668
- // Handle double-click to activate editing
14669
- activateEdit() {
14670
- //TODO FOCUS WYSIWYG
14671
- this.wysiwyg()?.focus();
14672
- this.isEditing.set(true);
14673
- }
14674
- // Save changes and exit edit mode
14675
- saveChanges() {
14676
- this.isEditing.set(false);
14677
- }
14678
- setColor(color) {
14679
- this.setOptions({ backgroundColor: color });
14680
- }
14681
- valueChange(event) {
14682
- if (event.isUserInteraction) {
14683
- this.setValue(event.value);
14684
- }
14685
- }
14686
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPStickyNoteWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
14687
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPStickyNoteWidgetViewComponent, isStandalone: true, selector: "ng-component", host: { listeners: { "document:click": "handleClickOutside($event)" } }, providers: [
14688
- {
14689
- provide: AXGridLayoutWidgetComponent,
14690
- useExisting: AXPStickyNoteWidgetViewComponent,
14691
- },
14692
- ], viewQueries: [{ propertyName: "wysiwyg", first: true, predicate: ["wysiwyg"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"sticky-note-container ax-size-full ax-rounded-lg ax-flex ax-flex-col ax-p-4 ax-shadow-md ax-transition-all ax-duration-300 hover:ax-shadow-lg\"\n [style.background-color]=\"bgColor()\"\n [style.color]=\"color()\"\n [class.ax-shadow-lg]=\"isEditing()\"\n [class.ax-scale-[1.02]]=\"isEditing()\"\n (dblclick)=\"activateEdit()\"\n>\n <!-- Header with timestamp -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <div class=\"ax-text-xs ax-opacity-70 ax-font-medium ax-flex ax-items-center ax-gap-1\">\n <i class=\"fa-regular fa-clock ax-text-[0.65rem]\"></i>\n {{ date() | format : 'datetime' : 'dd MMM, YY HH:mm' | async }}\n </div>\n </div>\n\n <!-- Content area -->\n <div class=\"ax-flex-1 ax-overflow-auto\">\n <ax-wysiwyg-container\n #wysiwyg\n [class]=\"\n isEditing()\n ? 'ax-pointer-events-auto ax-cursor-text ax-ring-2 ax-ring-black/5 ax-rounded-md'\n : 'ax-pointer-events-none !ax-cursor-pointer'\n \"\n class=\"ax-h-full\"\n placeHolder=\"start writing with double click...\"\n look=\"none\"\n (onValueChanged)=\"valueChange($event)\"\n [ngModel]=\"value()\"\n >\n <ax-wysiwyg-view class=\"!ax-size-full ax-border-b-0\"></ax-wysiwyg-view>\n </ax-wysiwyg-container>\n </div>\n\n <!-- Footer with color selector and save button -->\n @if (isEditing()) {\n <div class=\"ax-absolute ax-bottom-2 ax-left-2 ax-right-2 ax-flex ax-flex-wrap ax-gap-1 ax-text-xs\">\n <!-- Color selection bar when in edit mode -->\n <div class=\"ax-flex ax-w-full ax-mt-2 ax-border ax-border-gray-200 ax-overflow-hidden ax-rounded-md\">\n @for (preset of colorPresets; track preset) {\n <div\n class=\"ax-h-6 ax-flex-1 ax-cursor-pointer ax-transition-all ax-duration-200 ax-border-r ax-border-gray-200 last:ax-border-r-0 hover:ax-brightness-95\"\n [style.background-color]=\"preset\"\n [class.ax-ring-inset]=\"bgColor() === preset\"\n [class.ax-ring-2]=\"bgColor() === preset\"\n [class.ax-ring-primary]=\"bgColor() === preset\"\n (click)=\"setColor(preset)\"\n ></div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%}:host .sticky-note-container{transition:all .2s ease-in-out}:host :host ::ng-deep ax-wysiwyg-view{color:inherit!important}:host :host ::ng-deep ax-wysiwyg-view .ql-editor{padding:0!important;font-size:.95rem;line-height:1.5;color:#2e2e2e}:host :host ::ng-deep ax-wysiwyg-view .ql-editor:before{color:inherit!important;opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: AXWysiwygModule }, { kind: "component", type: i2$3.AXWysiwygContainerComponent, selector: "ax-wysiwyg-container", inputs: ["look", "placeHolder"], outputs: ["onValueChanged"] }, { kind: "component", type: i2$3.AXWysiwygViewComponent, selector: "ax-wysiwyg-view", inputs: ["class"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXToolBarModule }, { kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i2$9.AXFormatPipe, name: "format" }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXColorBoxModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
14693
- }
14694
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPStickyNoteWidgetViewComponent, decorators: [{
14695
- type: Component,
14696
- args: [{ standalone: true, imports: [
14697
- AXWysiwygModule,
14698
- AXDecoratorModule,
14699
- AXToolBarModule,
14700
- FormsModule,
14701
- AXDateTimeModule,
14702
- AXFormatModule,
14703
- AXPopoverModule,
14704
- CommonModule,
14705
- FormsModule,
14706
- AXColorBoxModule,
14707
- ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
14708
- {
14709
- provide: AXGridLayoutWidgetComponent,
14710
- useExisting: AXPStickyNoteWidgetViewComponent,
14711
- },
14712
- ], template: "<div\n class=\"sticky-note-container ax-size-full ax-rounded-lg ax-flex ax-flex-col ax-p-4 ax-shadow-md ax-transition-all ax-duration-300 hover:ax-shadow-lg\"\n [style.background-color]=\"bgColor()\"\n [style.color]=\"color()\"\n [class.ax-shadow-lg]=\"isEditing()\"\n [class.ax-scale-[1.02]]=\"isEditing()\"\n (dblclick)=\"activateEdit()\"\n>\n <!-- Header with timestamp -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <div class=\"ax-text-xs ax-opacity-70 ax-font-medium ax-flex ax-items-center ax-gap-1\">\n <i class=\"fa-regular fa-clock ax-text-[0.65rem]\"></i>\n {{ date() | format : 'datetime' : 'dd MMM, YY HH:mm' | async }}\n </div>\n </div>\n\n <!-- Content area -->\n <div class=\"ax-flex-1 ax-overflow-auto\">\n <ax-wysiwyg-container\n #wysiwyg\n [class]=\"\n isEditing()\n ? 'ax-pointer-events-auto ax-cursor-text ax-ring-2 ax-ring-black/5 ax-rounded-md'\n : 'ax-pointer-events-none !ax-cursor-pointer'\n \"\n class=\"ax-h-full\"\n placeHolder=\"start writing with double click...\"\n look=\"none\"\n (onValueChanged)=\"valueChange($event)\"\n [ngModel]=\"value()\"\n >\n <ax-wysiwyg-view class=\"!ax-size-full ax-border-b-0\"></ax-wysiwyg-view>\n </ax-wysiwyg-container>\n </div>\n\n <!-- Footer with color selector and save button -->\n @if (isEditing()) {\n <div class=\"ax-absolute ax-bottom-2 ax-left-2 ax-right-2 ax-flex ax-flex-wrap ax-gap-1 ax-text-xs\">\n <!-- Color selection bar when in edit mode -->\n <div class=\"ax-flex ax-w-full ax-mt-2 ax-border ax-border-gray-200 ax-overflow-hidden ax-rounded-md\">\n @for (preset of colorPresets; track preset) {\n <div\n class=\"ax-h-6 ax-flex-1 ax-cursor-pointer ax-transition-all ax-duration-200 ax-border-r ax-border-gray-200 last:ax-border-r-0 hover:ax-brightness-95\"\n [style.background-color]=\"preset\"\n [class.ax-ring-inset]=\"bgColor() === preset\"\n [class.ax-ring-2]=\"bgColor() === preset\"\n [class.ax-ring-primary]=\"bgColor() === preset\"\n (click)=\"setColor(preset)\"\n ></div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%}:host .sticky-note-container{transition:all .2s ease-in-out}:host :host ::ng-deep ax-wysiwyg-view{color:inherit!important}:host :host ::ng-deep ax-wysiwyg-view .ql-editor{padding:0!important;font-size:.95rem;line-height:1.5;color:#2e2e2e}:host :host ::ng-deep ax-wysiwyg-view .ql-editor:before{color:inherit!important;opacity:.7}\n"] }]
14713
- }], propDecorators: { handleClickOutside: [{
14714
- type: HostListener,
14715
- args: ['document:click', ['$event']]
14716
- }] } });
14717
-
14718
- var stickyNoteWidget_component = /*#__PURE__*/Object.freeze({
14719
- __proto__: null,
14720
- AXPStickyNoteWidgetViewComponent: AXPStickyNoteWidgetViewComponent
14721
- });
14722
-
14723
- const AXPStickyNoteWidget = {
14724
- name: 'sticky-note',
14725
- title: 'Sticky Note Widget',
14726
- categories: AXP_WIDGETS_UTILITY_CATEGORY,
14727
- groups: [AXPWidgetGroupEnum.DashboardWidget],
14728
- type: 'dashboard',
14729
- icon: 'fa-light fa-sticky-note',
14730
- properties: [AXP_DATA_PATH_PROPERTY, AXP_BG_COLOR_PROPERTY, plainTextDefaultProperty()],
14731
- components: {
14732
- view: {
14733
- component: () => Promise.resolve().then(function () { return stickyNoteWidget_component; }).then((c) => c.AXPStickyNoteWidgetViewComponent),
14734
- },
14735
- },
14736
- meta: {
14737
- dimensions: {
14738
- width: 2,
14739
- height: 3,
14740
- minWidth: 2,
14741
- minHeight: 2,
14742
- maxWidth: 4,
14743
- maxHeight: 4,
14744
- },
14745
- },
14746
- };
14747
-
14748
- /**
14749
- * Task List Widget Component
14750
- * Displays a list of tasks with checkboxes and filtering options
14751
- */
14752
- class AXPTaskListWidgetViewComponent extends AXPValueWidgetComponent {
14753
- constructor() {
14754
- super(...arguments);
14755
- // Outputs
14756
- this.taskClick = output();
14757
- this.taskCompleted = output();
14758
- // Dependencies
14759
- this.cdr = inject(ChangeDetectorRef);
14760
- this.datePipe = inject(DatePipe);
14761
- // Configuration options
14762
- this.maxItems = computed(() => this.options()?.maxItems ?? 10);
14763
- this.showDate = computed(() => this.options()?.showDate ?? true);
14764
- this.showAssignee = computed(() => this.options()?.showAssignee ?? true);
14765
- this.showPriority = computed(() => this.options()?.showPriority ?? true);
14766
- this.allowMarkComplete = computed(() => this.options()?.allowMarkComplete ?? true);
14767
- this.showCategories = computed(() => this.options()?.groupByCategory ?? true);
14768
- // Data computed properties
14769
- this.taskItems = computed(() => {
14770
- const value = this.getValue();
14771
- if (!value?.data?.length)
14772
- return [];
14773
- return value.data.slice(0, this.maxItems());
14774
- });
14775
- }
14776
- // Task counting methods
14777
- getPendingTaskCount() {
14778
- return this.getFilteredTasks((task) => !task.completed).length;
14779
- }
14780
- getCompletedTaskCount() {
14781
- return this.getFilteredTasks((task) => task.completed).length;
14782
- }
14783
- // Category-related methods
14784
- hasCategories() {
14785
- return this.taskItems().some((task) => !!task.category);
14786
- }
14787
- getCategories() {
14788
- const tasks = this.taskItems();
14789
- const categories = new Set();
14790
- let hasUncategorized = false;
14791
- tasks.forEach((task) => {
14792
- if (task.category) {
14793
- categories.add(task.category);
14794
- }
14795
- else {
14796
- hasUncategorized = true;
14797
- }
14798
- });
14799
- const result = Array.from(categories);
14800
- if (hasUncategorized) {
14801
- result.push('Uncategorized');
14802
- }
14803
- return result;
14804
- }
14805
- getTasksByCategory(category) {
14806
- const tasks = this.taskItems();
14807
- if (category === 'Uncategorized') {
14808
- return tasks.filter((task) => !task.category);
14809
- }
14810
- return tasks.filter((task) => task.category === category);
14811
- }
14812
- getCategoryTaskCount(category) {
14813
- return this.getTasksByCategory(category).filter((task) => !task.completed).length;
14814
- }
14815
- // Event handlers
14816
- onTaskClick(task) {
14817
- this.taskClick.emit(task);
14818
- }
14819
- onTaskCompletionChange(task, isCompleted) {
14820
- const updatedTask = { ...task, completed: isCompleted };
14821
- const value = this.getValue();
14822
- if (!value?.data)
14823
- return;
14824
- const updatedTasks = value.data.map((t) => (t.id === task.id ? updatedTask : t));
14825
- this.setValue({ ...value, data: updatedTasks });
14826
- this.taskCompleted.emit(updatedTask);
14827
- this.cdr.detectChanges();
14828
- }
14829
- // Formatting and utility methods
14830
- formatDueDate(date) {
14831
- if (!date)
14832
- return '';
14833
- const dateObj = typeof date === 'string' ? new Date(date) : date;
14834
- const diffDays = this.getDaysDifference(dateObj);
14835
- if (diffDays < 0)
14836
- return 'Overdue!';
14837
- if (diffDays === 0)
14838
- return 'Today';
14839
- if (diffDays === 1)
14840
- return 'Tomorrow';
14841
- if (diffDays < 7)
14842
- return this.datePipe.transform(dateObj, 'EEE') || '';
14843
- return this.datePipe.transform(dateObj, 'MM/dd/yyyy') || '';
14844
- }
14845
- getPriorityColor(priority) {
14846
- if (!priority)
14847
- return '';
14848
- const priorityColors = {
14849
- high: 'danger',
14850
- medium: 'warning',
14851
- low: 'success',
14852
- };
14853
- return priorityColors[priority] || '';
14854
- }
14855
- // Helper methods
14856
- getFilteredTasks(filterFn) {
14857
- const value = this.getValue();
14858
- if (!value?.data?.length)
14859
- return [];
14860
- return value.data.filter(filterFn);
14861
- }
14862
- getDaysDifference(date) {
14863
- const now = new Date();
14864
- now.setHours(0, 0, 0, 0);
14865
- const targetDate = new Date(date);
14866
- targetDate.setHours(0, 0, 0, 0);
14867
- const diffMs = targetDate.getTime() - now.getTime();
14868
- return Math.floor(diffMs / (1000 * 60 * 60 * 24));
14869
- }
14870
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPTaskListWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
14871
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPTaskListWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { taskClick: "taskClick", taskCompleted: "taskCompleted" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-size-full ax-p-4\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <h3 class=\"ax-text-lg ax-font-semibold\">{{ 'widget.tasklist.title' | translate | async }}</h3>\n <div class=\"ax-flex ax-gap-2\">\n @if(getPendingTaskCount() > 0){\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('widget.tasklist.pending' | translate | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n } @if(getCompletedTaskCount() > 0){\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('widget.tasklist.completed' | translate | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-2\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-3\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-2 ax-h-5\">\n <h4 class=\"ax-font-medium ax-text-gray-700\">{{ category }}</h4>\n @if(getCategoryTaskCount(category)){\n <ax-badge [text]=\"getCategoryTaskCount(category).toString()\" [color]=\"'primary'\" size=\"sm\"></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n } } @else {\n <!-- Uncategorized Tasks -->\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.tasklist.noTasks' | translate | async }}</p>\n </div>\n } }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div class=\"ax-flex ax-gap-3 ax-items-center ax-py-2 ax-border-b ax-border-gray-100 last:ax-border-0\">\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6\n class=\"ax-font-semibold ax-truncate ax-pb-1\"\n [class.ax-line-through]=\"task.completed\"\n [class.ax-text-gray-400]=\"task.completed\"\n >\n {{ task.title }}\n </h6>\n @if(showPriority() && task.priority) {\n <ax-badge [color]=\"getPriorityColor(task.priority)\" [text]=\"task.priority\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-1 ax-text-xs ax-text-gray-500\">\n @if(showDate() && task.dueDate) {\n <span class=\"ax-flex ax-items-center ax-gap-1\" [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\">\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n } @if(showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXImageModule }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i1.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "checked", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
14872
- }
14873
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPTaskListWidgetViewComponent, decorators: [{
14874
- type: Component,
14875
- args: [{ standalone: true, imports: [
14876
- CommonModule,
14877
- AXTabsModule,
14878
- AXDecoratorModule,
14879
- AXButtonModule,
14880
- AXBadgeModule,
14881
- AXAvatarModule,
14882
- AXImageModule,
14883
- AXCheckBoxModule,
14884
- AXLabelModule,
14885
- AXTranslationModule,
14886
- ], providers: [DatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-size-full ax-p-4\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <h3 class=\"ax-text-lg ax-font-semibold\">{{ 'widget.tasklist.title' | translate | async }}</h3>\n <div class=\"ax-flex ax-gap-2\">\n @if(getPendingTaskCount() > 0){\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('widget.tasklist.pending' | translate | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n } @if(getCompletedTaskCount() > 0){\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('widget.tasklist.completed' | translate | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-2\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-3\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-2 ax-h-5\">\n <h4 class=\"ax-font-medium ax-text-gray-700\">{{ category }}</h4>\n @if(getCategoryTaskCount(category)){\n <ax-badge [text]=\"getCategoryTaskCount(category).toString()\" [color]=\"'primary'\" size=\"sm\"></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n } } @else {\n <!-- Uncategorized Tasks -->\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.tasklist.noTasks' | translate | async }}</p>\n </div>\n } }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div class=\"ax-flex ax-gap-3 ax-items-center ax-py-2 ax-border-b ax-border-gray-100 last:ax-border-0\">\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6\n class=\"ax-font-semibold ax-truncate ax-pb-1\"\n [class.ax-line-through]=\"task.completed\"\n [class.ax-text-gray-400]=\"task.completed\"\n >\n {{ task.title }}\n </h6>\n @if(showPriority() && task.priority) {\n <ax-badge [color]=\"getPriorityColor(task.priority)\" [text]=\"task.priority\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-1 ax-text-xs ax-text-gray-500\">\n @if(showDate() && task.dueDate) {\n <span class=\"ax-flex ax-items-center ax-gap-1\" [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\">\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n } @if(showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary)}\n"] }]
14887
- }] });
14888
-
14889
- var tasklistWidget_component = /*#__PURE__*/Object.freeze({
14890
- __proto__: null,
14891
- AXPTaskListWidgetViewComponent: AXPTaskListWidgetViewComponent
14892
- });
14893
-
14894
- const AXPTaskListWidget = {
14895
- name: 'task-list',
14896
- title: 'Task List Widget',
14897
- categories: [AXP_WIDGETS_CHART_CATEGORY],
14898
- groups: [AXPWidgetGroupEnum.DashboardWidget],
14899
- type: 'dashboard',
14900
- icon: 'fa-light fa-clipboard-list-check',
14901
- properties: [
14902
- cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
14903
- // Display options
14904
- {
14905
- name: 'maxItems',
14906
- title: 'Max Items',
14907
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14908
- schema: {
14909
- defaultValue: 10,
14910
- dataType: 'number',
14911
- interface: {
14912
- name: 'maxItems',
14913
- path: 'options.maxItems',
14914
- type: AXPWidgetsCatalog.number,
14915
- options: {
14916
- minValue: 1,
14917
- maxValue: 50,
14918
- },
14919
- },
14920
- },
14921
- visible: true,
14922
- },
14923
- {
14924
- name: 'showDate',
14925
- title: 'Show Date',
14926
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14927
- schema: {
14928
- defaultValue: true,
14929
- dataType: 'boolean',
14930
- interface: {
14931
- name: 'showDate',
14932
- path: 'options.showDate',
14933
- type: AXPWidgetsCatalog.toggle,
14934
- },
14935
- },
14936
- visible: true,
14937
- },
14938
- {
14939
- name: 'showAssignee',
14940
- title: 'Show Assignee',
14941
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14942
- schema: {
14943
- defaultValue: true,
14944
- dataType: 'boolean',
14945
- interface: {
14946
- name: 'showAssignee',
14947
- path: 'options.showAssignee',
14948
- type: AXPWidgetsCatalog.toggle,
14949
- },
14950
- },
14951
- visible: true,
14952
- },
14953
- {
14954
- name: 'groupByCategory',
14955
- title: 'Group by Category',
14956
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14957
- schema: {
14958
- defaultValue: true,
14959
- dataType: 'boolean',
14960
- interface: {
14961
- name: 'groupByCategory',
14962
- path: 'options.groupByCategory',
14963
- type: AXPWidgetsCatalog.toggle,
14964
- },
14965
- },
14966
- visible: true,
14967
- },
14968
- {
14969
- name: 'showPriority',
14970
- title: 'Show Priority',
14971
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14972
- schema: {
14973
- defaultValue: true,
14974
- dataType: 'boolean',
14975
- interface: {
14976
- name: 'showPriority',
14977
- path: 'options.showPriority',
14978
- type: AXPWidgetsCatalog.toggle,
14979
- },
14980
- },
14981
- visible: true,
14982
- },
14983
- {
14984
- name: 'allowMarkComplete',
14985
- title: 'Allow Complete',
14986
- group: AXP_APPEARANCE_PROPERTY_GROUP,
14987
- schema: {
14988
- defaultValue: true,
14989
- dataType: 'boolean',
14990
- interface: {
14991
- name: 'allowMarkComplete',
14992
- path: 'options.allowMarkComplete',
14993
- type: AXPWidgetsCatalog.toggle,
14994
- },
14995
- },
14996
- visible: true,
14997
- },
14998
- ],
14999
- components: {
15000
- view: {
15001
- component: () => Promise.resolve().then(function () { return tasklistWidget_component; }).then((c) => c.AXPTaskListWidgetViewComponent),
15002
- },
15003
- },
15004
- meta: {
15005
- dimensions: {
15006
- width: 5,
15007
- height: 7,
15008
- minWidth: 3,
15009
- minHeight: 4,
15010
- maxWidth: 6,
15011
- maxHeight: 8,
15012
- },
15013
- },
15014
- };
15015
-
15016
- /**
15017
- * Abstract Weather API Service
15018
- * Base class that defines the interface and common functionality
15019
- * for weather data providers
15020
- */
15021
- class AXPWeatherApiAbstract {
15022
- constructor() {
15023
- /** Weather condition definitions mapping */
15024
- this.weatherConditions = {
15025
- sunny: {
15026
- id: 'sunny',
15027
- name: 'Sunny',
15028
- icon: 'fa-solid fa-sun',
15029
- color: '#ff9d00',
15030
- },
15031
- clearNight: {
15032
- id: 'clearNight',
15033
- name: 'Clear Night',
15034
- icon: 'fa-solid fa-moon',
15035
- color: '#5d639e',
15036
- },
15037
- partlyCloudy: {
15038
- id: 'partlyCloudy',
15039
- name: 'Partly Cloudy',
15040
- icon: 'fa-solid fa-cloud-sun',
15041
- color: '#6ba4e8',
15042
- },
15043
- partlyCloudyNight: {
15044
- id: 'partlyCloudyNight',
15045
- name: 'Partly Cloudy Night',
15046
- icon: 'fa-solid fa-cloud-moon',
15047
- color: '#5d639e',
15048
- },
15049
- cloudy: {
15050
- id: 'cloudy',
15051
- name: 'Cloudy',
15052
- icon: 'fa-solid fa-cloud',
15053
- color: '#72869d',
15054
- },
15055
- rain: {
15056
- id: 'rain',
15057
- name: 'Rain',
15058
- icon: 'fa-solid fa-cloud-rain',
15059
- color: '#3a74ad',
15060
- },
15061
- showers: {
15062
- id: 'showers',
15063
- name: 'Showers',
15064
- icon: 'fa-solid fa-cloud-showers-heavy',
15065
- color: '#2c5d8c',
15066
- },
15067
- thunderstorm: {
15068
- id: 'thunderstorm',
15069
- name: 'Thunderstorm',
15070
- icon: 'fa-solid fa-bolt-lightning',
15071
- color: '#8834af',
15072
- },
15073
- snow: {
15074
- id: 'snow',
15075
- name: 'Snow',
15076
- icon: 'fa-solid fa-snowflake',
15077
- color: '#68a9cd',
15078
- },
15079
- mist: {
15080
- id: 'mist',
15081
- name: 'Mist',
15082
- icon: 'fa-solid fa-smog',
15083
- color: '#94a3b8',
15084
- },
15085
- };
15086
- /** Day of week mapping */
15087
- this.dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
15088
- }
15089
- /**
15090
- * Get weather condition info by ID
15091
- * @param id Condition ID
15092
- * @returns Weather condition info or default if not found
15093
- */
15094
- getCondition(id) {
15095
- // Normalize condition ID by removing spaces and converting to lowercase
15096
- const normalizedId = id.toLowerCase().replace(/\s+/g, '');
15097
- // Direct match first
15098
- if (this.weatherConditions[normalizedId]) {
15099
- return this.weatherConditions[normalizedId];
15100
- }
15101
- // Check for partial matches or common variants
15102
- if (normalizedId.includes('partly') && normalizedId.includes('cloud')) {
15103
- return this.weatherConditions['partlyCloudy'];
15104
- }
15105
- if (normalizedId.includes('cloud')) {
15106
- return this.weatherConditions['cloudy'];
15107
- }
15108
- if (normalizedId.includes('sun')) {
15109
- return this.weatherConditions['sunny'];
15110
- }
15111
- if (normalizedId.includes('rain')) {
15112
- return this.weatherConditions['rain'];
15113
- }
15114
- if (normalizedId.includes('snow')) {
15115
- return this.weatherConditions['snow'];
15116
- }
15117
- // If no match found, return default unknown condition
15118
- return {
15119
- id: 'unknown',
15120
- name: 'Unknown',
15121
- icon: 'fa-solid fa-question',
15122
- color: '#999999',
15123
- };
15124
- }
15125
- /**
15126
- * Parse location string into city and display components
15127
- * @param location Location query string
15128
- * @returns Parsed location parts
15129
- */
15130
- parseLocation(location) {
15131
- if (!location || location.trim() === '') {
15132
- return { city: 'New York', country: 'USA', display: 'New York' };
15133
- }
15134
- const city = location.trim();
15135
- return { city, country: '', display: city };
15136
- }
15137
- /**
15138
- * Format location name for display
15139
- * @param locationParts Parsed location parts
15140
- * @returns Formatted location name
15141
- */
15142
- formatLocationName(locationParts) {
15143
- return locationParts.city || 'Unknown Location';
15144
- }
15145
- /**
15146
- * Map API condition text to our internal condition IDs
15147
- * @param conditionText Condition text from API
15148
- * @returns Internal condition ID
15149
- */
15150
- mapApiConditionToId(conditionText) {
15151
- const text = conditionText.toLowerCase();
15152
- // Match WeatherAPI.com condition text
15153
- // Reference: https://www.weatherapi.com/docs/#weather-icons
15154
- if (text.includes('sunny') || text.includes('clear')) {
15155
- return 'sunny';
15156
- }
15157
- if (text === 'partly cloudy') {
15158
- return 'partlyCloudy';
15159
- }
15160
- if (text.includes('cloudy') || text.includes('overcast')) {
15161
- return 'cloudy';
15162
- }
15163
- if (text.includes('rain') || text.includes('drizzle') || text.includes('shower')) {
15164
- return 'rain';
15165
- }
15166
- if (text.includes('thunder') || text.includes('lightning')) {
15167
- return 'thunderstorm';
15168
- }
15169
- if (text.includes('snow') || text.includes('sleet') || text.includes('blizzard')) {
15170
- return 'snow';
15171
- }
15172
- if (text.includes('mist') || text.includes('fog')) {
15173
- return 'mist';
15174
- }
15175
- // Default to partly cloudy if we don't have a specific mapping
15176
- return 'partlyCloudy';
15177
- }
15178
- /**
15179
- * Generate random integer between min and max (inclusive)
15180
- * Helper method for implementations
15181
- * @param min Minimum value
15182
- * @param max Maximum value
15183
- * @returns Random integer
15184
- */
15185
- getRandomInt(min, max) {
15186
- return Math.floor(Math.random() * (max - min + 1)) + min;
15187
- }
15188
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiAbstract, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
15189
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiAbstract }); }
15190
- }
15191
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiAbstract, decorators: [{
15192
- type: Injectable
15193
- }] });
15194
-
15195
- /**
15196
- * Mock Weather API Service
15197
- * Provides simulated weather data for development and testing
15198
- */
15199
- class AXPWeatherApiMockService extends AXPWeatherApiAbstract {
15200
- constructor() {
15201
- super(...arguments);
15202
- // Mock configuration
15203
- this.mockDelay = 500;
15204
- }
15205
- /**
15206
- * Get current weather data for given location
15207
- * @param options Weather request options
15208
- * @returns Observable with weather data
15209
- */
15210
- getWeather(options) {
15211
- const locationParts = this.parseLocation(options.location || '');
15212
- const displayName = this.formatLocationName(locationParts);
15213
- return this.getMockWeatherData(locationParts.city, options).pipe(map((mockData) => ({
15214
- ...mockData,
15215
- location: {
15216
- city: locationParts.city,
15217
- country: '',
15218
- displayName: displayName,
15219
- },
15220
- })));
15221
- }
15222
- /**
15223
- * Get weather forecast for a location
15224
- * @param options Weather request options with days
15225
- * @returns Observable of weather data with forecast
15226
- */
15227
- getForecast(options) {
15228
- const days = options.days || 5;
15229
- return this.getMockForecast(options.location || '', days, options);
15230
- }
15231
- /**
15232
- * Get mock weather data for demo/development
15233
- * @param location Location query
15234
- * @param options Request options
15235
- * @returns Observable of mock weather data
15236
- */
15237
- getMockWeatherData(location, options) {
15238
- return new Observable((observer) => {
15239
- setTimeout(() => {
15240
- try {
15241
- const locationParts = this.parseLocation(location);
15242
- const tempUnit = options?.tempUnit || '°C';
15243
- const isCelsius = tempUnit === '°C';
15244
- // Generate more realistic weather data based on location and current date
15245
- const now = new Date();
15246
- const month = now.getMonth(); // 0-11
15247
- // Seasonally appropriate temperature range
15248
- let minRange = 15;
15249
- let maxRange = 25;
15250
- // Northern hemisphere seasonal adjustments
15251
- if (month >= 11 || month <= 1) {
15252
- // Winter
15253
- minRange = -5;
15254
- maxRange = 10;
15255
- }
15256
- else if (month >= 2 && month <= 4) {
15257
- // Spring
15258
- minRange = 10;
15259
- maxRange = 20;
15260
- }
15261
- else if (month >= 5 && month <= 7) {
15262
- // Summer
15263
- minRange = 20;
15264
- maxRange = 35;
15265
- }
15266
- else if (month >= 8 && month <= 10) {
15267
- // Fall/Autumn
15268
- minRange = 10;
15269
- maxRange = 25;
15270
- }
15271
- // Generate current temperature - more likely to be in the middle of the range
15272
- const tempC = Math.round(minRange + (this.getRandomInt(4, 8) / 10) * (maxRange - minRange));
15273
- const tempF = Math.round((tempC * 9) / 5 + 32);
15274
- const humidity = this.getRandomInt(30, 90);
15275
- const windKph = this.getRandomInt(5, 30);
15276
- const windMph = Math.round(windKph * 0.621371);
15277
- // Temperature-based conditions with randomization
15278
- let conditionId = 'partlyCloudy';
15279
- if (tempC > 25)
15280
- conditionId = 'sunny';
15281
- else if (tempC < 10)
15282
- conditionId = 'cloudy';
15283
- if (this.getRandomInt(1, 10) > 7)
15284
- conditionId = 'rain';
15285
- observer.next({
15286
- location: {
15287
- city: locationParts.city,
15288
- country: '',
15289
- displayName: this.formatLocationName(locationParts),
15290
- },
15291
- current: {
15292
- condition: conditionId,
15293
- conditionCode: 0,
15294
- iconUrl: '', // Would be set from API
15295
- tempC: tempC,
15296
- tempF: tempF,
15297
- feelsLikeC: tempC + this.getRandomInt(-3, 2),
15298
- feelsLikeF: tempF + this.getRandomInt(-5, 3),
15299
- humidity: humidity,
15300
- windKph: windKph,
15301
- windMph: windMph,
15302
- windDirection: ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'][this.getRandomInt(0, 7)],
15303
- uv: this.getRandomInt(0, 10),
15304
- lastUpdated: new Date().toISOString(),
15305
- },
15306
- forecast: [],
15307
- });
15308
- observer.complete();
15309
- }
15310
- catch (error) {
15311
- observer.error(error);
15312
- }
15313
- }, this.mockDelay);
15314
- }).pipe(catchError((error) => throwError(() => new Error(`Failed to get weather data: ${error.message}`))));
15315
- }
15316
- /**
15317
- * Get mock forecast data for demo/development
15318
- * @param location Location query
15319
- * @param days Number of forecast days
15320
- * @param options Request options
15321
- * @returns Observable of mock weather data with forecast
15322
- */
15323
- getMockForecast(location, days = 5, options) {
15324
- return this.getMockWeatherData(location, options).pipe(map((data) => {
15325
- const currentCondition = data.current.condition;
15326
- const currentTemp = data.current.tempC;
15327
- // Use the current weather as a base for the forecast trend
15328
- const forecast = Array.from({ length: days }, (_, i) => {
15329
- // Create forecast date for each day (starting from tomorrow)
15330
- const forecastDate = new Date();
15331
- forecastDate.setDate(new Date().getDate() + i + 1);
15332
- const dateStr = forecastDate.toISOString().split('T')[0];
15333
- const dayName = this.dayNames[forecastDate.getDay()];
15334
- // Generate condition with some continuity from current weather
15335
- // Weather tends to be similar for a few days with gradual changes
15336
- let conditionId;
15337
- if (i === 0) {
15338
- // Tomorrow's weather has 60% chance of being similar to today
15339
- conditionId =
15340
- this.getRandomInt(1, 10) <= 6
15341
- ? currentCondition
15342
- : ['sunny', 'partlyCloudy', 'cloudy', 'rain', 'snow'][this.getRandomInt(0, 4)];
15343
- }
15344
- else {
15345
- // Subsequent days have 70% chance of being similar to previous day
15346
- const previousCondition = forecast[i - 1]?.condition || currentCondition;
15347
- conditionId =
15348
- this.getRandomInt(1, 10) <= 7
15349
- ? previousCondition
15350
- : ['sunny', 'partlyCloudy', 'cloudy', 'rain', 'snow'][this.getRandomInt(0, 4)];
15351
- }
15352
- // Generate temperatures with realistic variance
15353
- // Max is typically higher than current temperature
15354
- // Min is typically lower than current temperature
15355
- const tempVariance = this.getRandomInt(-3, 3); // Small day-to-day change
15356
- const baseMaxC = currentTemp + this.getRandomInt(0, 5); // Max is higher than current
15357
- const maxTempC = baseMaxC + tempVariance;
15358
- const minTempC = maxTempC - this.getRandomInt(5, 10); // Min is lower than max
15359
- const maxTempF = Math.round((maxTempC * 9) / 5 + 32);
15360
- const minTempF = Math.round((minTempC * 9) / 5 + 32);
15361
- return {
15362
- date: dateStr,
15363
- day: dayName,
15364
- condition: conditionId,
15365
- iconUrl: '', // Would be set from API
15366
- maxTempC,
15367
- maxTempF,
15368
- minTempC,
15369
- minTempF,
15370
- };
15371
- });
15372
- return { ...data, forecast };
15373
- }));
15374
- }
15375
- /**
15376
- * Set the API key for the weather service
15377
- * No-op in the mock implementation
15378
- * @param key The API key
15379
- */
15380
- setApiKey(key) {
15381
- // No-op for mock service
15382
- console.log('API key setting is ignored in mock weather service');
15383
- }
15384
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiMockService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
15385
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiMockService }); }
15386
- }
15387
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiMockService, decorators: [{
15388
- type: Injectable
15389
- }] });
15390
-
15391
- const AXP_WEATHER_API_KEY = new InjectionToken('AXP_WEATHER_API_KEY', {
15392
- providedIn: 'root',
15393
- factory: () => {
15394
- return '40281dc1e31749edb6c104828250604';
15395
- },
15396
- });
15397
-
15398
- /**
15399
- * Real Weather API Service
15400
- * Fetches actual weather data from a weather API service
15401
- */
15402
- class AXPWeatherApiService extends AXPWeatherApiAbstract {
15403
- constructor() {
15404
- super(...arguments);
15405
- this.http = inject(HttpClient);
15406
- // API configuration
15407
- this.baseApiUrl = 'https://api.weatherapi.com/v1';
15408
- this.apiKeyToken = inject(AXP_WEATHER_API_KEY, { optional: true });
15409
- }
15410
- /**
15411
- * Set the API key for the weather service
15412
- * @param key The API key
15413
- */
15414
- setApiKey(key) {
15415
- if (key && key.trim() !== '') {
15416
- this.apiKeyToken = key;
15417
- }
15418
- }
15419
- /**
15420
- * Get current weather data for given location
15421
- * @param options Weather request options
15422
- * @returns Observable with weather data
15423
- */
15424
- getWeather(options) {
15425
- // If forecast is likely needed, we should fetch it all at once
15426
- if (options.useMockData === false || options.useMockData === undefined) {
15427
- // For real API, use the forecast endpoint which includes current data
15428
- return this.getForecast({
15429
- ...options,
15430
- days: 1, // Request minimal forecast data
15431
- });
15432
- }
15433
- // For mock data, we'll continue using separate calls for backward compatibility
15434
- const locationParts = this.parseLocation(options.location || '');
15435
- const displayName = this.formatLocationName(locationParts);
15436
- // Use real API with query based on city only
15437
- const query = encodeURIComponent(locationParts.city);
15438
- const url = `${this.baseApiUrl}/current.json?key=${this.apiKeyToken}&q=${query}&aqi=no`;
15439
- return this.http.get(url).pipe(map((data) => this.transformApiResponse(data, displayName)), catchError((error) => {
15440
- console.error('Weather API error:', error);
15441
- // Check for location not found error
15442
- if (error.error?.error?.code === 1006) {
15443
- return throwError(() => new Error(`Location "${locationParts.city}" not found. Please check the city name and try again.`));
15444
- }
15445
- return throwError(() => new Error(`Failed to fetch weather data: ${error.message}`));
15446
- }));
15447
- }
15448
- /**
15449
- * Get weather forecast for a location
15450
- * @param options Weather request options with days
15451
- * @returns Observable of weather data with forecast
15452
- */
15453
- getForecast(options) {
15454
- const locationParts = this.parseLocation(options.location || '');
15455
- const displayName = this.formatLocationName(locationParts);
15456
- const days = options.days || 5;
15457
- // Build forecast API URL
15458
- const query = encodeURIComponent(locationParts.city);
15459
- const url = `${this.baseApiUrl}/forecast.json?key=${this.apiKeyToken}&q=${query}&days=${days}&aqi=no`;
15460
- return this.http.get(url).pipe(map((data) => this.transformForecastResponse(data, displayName, days)), catchError((error) => {
15461
- console.error('Weather API error:', error);
15462
- // Check for location not found error
15463
- if (error.error?.error?.code === 1006) {
15464
- return throwError(() => new Error(`Location "${locationParts.city}" not found. Please check the city name and try again.`));
15465
- }
15466
- return throwError(() => new Error(`Failed to fetch forecast data: ${error.message}`));
15467
- }));
15468
- }
15469
- /**
15470
- * Transform API response to our internal data model
15471
- * @param apiData Raw API response
15472
- * @param displayName Formatted location name
15473
- * @returns Normalized weather data
15474
- */
15475
- transformApiResponse(apiData, displayName) {
15476
- // Map API condition text to our condition IDs
15477
- const conditionText = apiData.current?.condition?.text || '';
15478
- const conditionId = this.mapApiConditionToId(conditionText);
15479
- return {
15480
- location: {
15481
- city: apiData.location?.name || '',
15482
- country: apiData.location?.country || '',
15483
- displayName: displayName,
15484
- },
15485
- current: {
15486
- condition: conditionId, // Use our mapped condition ID
15487
- conditionCode: apiData.current?.condition?.code || 0,
15488
- iconUrl: apiData.current?.condition?.icon || '',
15489
- tempC: apiData.current?.temp_c || 0,
15490
- tempF: apiData.current?.temp_f || 0,
15491
- feelsLikeC: apiData.current?.feelslike_c || 0,
15492
- feelsLikeF: apiData.current?.feelslike_f || 0,
15493
- humidity: apiData.current?.humidity || 0,
15494
- windKph: apiData.current?.wind_kph || 0,
15495
- windMph: apiData.current?.wind_mph || 0,
15496
- windDirection: apiData.current?.wind_dir || '',
15497
- uv: apiData.current?.uv || 0,
15498
- lastUpdated: apiData.current?.last_updated || new Date().toISOString(),
15499
- },
15500
- forecast: [],
15501
- };
15502
- }
15503
- /**
15504
- * Transform forecast API response to our internal data model
15505
- * @param apiData Raw API response with forecast
15506
- * @param displayName Formatted location name
15507
- * @param days Number of forecast days
15508
- * @returns Normalized weather data with forecast
15509
- */
15510
- transformForecastResponse(apiData, displayName, days) {
15511
- // First transform the current weather data using the current field of the forecast response
15512
- const weatherData = this.transformApiResponse(apiData, displayName);
15513
- // Then add the forecast data
15514
- const forecastDays = apiData.forecast?.forecastday || [];
15515
- weatherData.forecast = forecastDays.slice(0, days).map((day) => {
15516
- // Parse the date for day name
15517
- const date = new Date(day.date);
15518
- const dayName = date.toLocaleDateString('en-US', { weekday: 'short' });
15519
- // Map condition to our internal ID
15520
- const conditionText = day.day?.condition?.text || '';
15521
- const conditionId = this.mapApiConditionToId(conditionText);
15522
- return {
15523
- date: day.date,
15524
- day: dayName,
15525
- condition: conditionId,
15526
- iconUrl: day.day?.condition?.icon || '',
15527
- maxTempC: day.day?.maxtemp_c || 0,
15528
- maxTempF: day.day?.maxtemp_f || 0,
15529
- minTempC: day.day?.mintemp_c || 0,
15530
- minTempF: day.day?.mintemp_f || 0,
15531
- };
15532
- });
15533
- return weatherData;
15534
- }
15535
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
15536
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiService }); }
15537
- }
15538
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherApiService, decorators: [{
15539
- type: Injectable
15540
- }] });
15541
-
15542
- /**
15543
- * Weather Widget Component
15544
- * Displays current weather conditions and optional forecast data
15545
- * for a specified location with customizable display options.
15546
- */
15547
- class AXPWeatherWidgetViewComponent extends AXPValueWidgetComponent {
15548
- /**
15549
- * Component constructor
15550
- * @param cdr ChangeDetectorRef for triggering view updates
15551
- */
15552
- constructor(cdr) {
15553
- super();
15554
- this.cdr = cdr;
15555
- // Container element reference
15556
- this.containerEl = viewChild.required('containerElement');
15557
- // Weather API service instance
15558
- this.weatherService = inject(AXPWeatherApiAbstract);
15559
- // State signals
15560
- this.weatherData = signal(null);
15561
- this.isLoading = signal(true);
15562
- this.hasError = signal(false);
15563
- this.errorMessage = signal('');
15564
- this.isForecastLoading = signal(false);
15565
- // Auto-refresh subscription
15566
- this.refreshSubscription = null;
15567
- // Option-derived computed properties
15568
- this.city = computed(() => {
15569
- return this.options()['city'] || 'Newyork';
15570
- });
15571
- this.temperatureUnit = computed(() => this.options()['temperatureUnit']?.id || '°C');
15572
- this.windSpeedUnit = computed(() => this.options()['windSpeedUnit']?.id || 'km/h');
15573
- // Display option flags
15574
- this.showCurrentCondition = computed(() => this.options()['showCurrentCondition'] !== false);
15575
- this.showTemperature = computed(() => this.options()['showTemperature'] !== false);
15576
- this.showHumidity = computed(() => this.options()['showHumidity'] !== false);
15577
- this.showWind = computed(() => this.options()['showWind'] !== false);
15578
- this.showForecast = computed(() => this.options()['showForecast'] !== false);
15579
- this.forecastDays = computed(() => this.options()['forecastDays'] ?? 5);
15580
- // Refresh settings
15581
- this.autoRefresh = computed(() => this.options()['autoRefresh'] !== false);
15582
- this.refreshInterval = computed(() => this.options()['refreshInterval']?.id ?? 15);
15583
- // Reactivity effects
15584
- this.optionsEffect = effect(() => {
15585
- const opts = this.options();
15586
- this.loadWeatherData();
15587
- this.setupRefreshTimer();
15588
- });
15589
- this.valueEffect = effect(() => {
15590
- this.city();
15591
- this.loadWeatherData();
15592
- });
15593
- this.displayedForecast = computed(() => {
15594
- const weatherData = this.weatherData();
15595
- if (!weatherData?.forecast)
15596
- return [];
15597
- const forecastDays = this.forecastDays();
15598
- return weatherData.forecast.slice(0, forecastDays);
15599
- });
15600
- // Inject the abstract service which will resolve to either the mock or real implementation
15601
- this.weatherService = inject(AXPWeatherApiAbstract);
15602
- setTimeout(() => {
15603
- this.loadWeatherData();
15604
- this.setupRefreshTimer();
15605
- }, 0);
15606
- }
15607
- /**
15608
- * Component cleanup on destroy
15609
- */
15610
- ngOnDestroy() {
15611
- this.clearRefreshTimer();
15612
- }
15613
- /**
15614
- * Loads weather data from the API
15615
- * Sets loading state and handles errors
15616
- */
15617
- loadWeatherData() {
15618
- this.isLoading.set(true);
15619
- this.hasError.set(false);
15620
- this.errorMessage.set('');
15621
- const locationQuery = this.city();
15622
- const shouldShowForecast = this.showForecast();
15623
- // If we need forecast, request it directly to avoid duplicate calls
15624
- // The forecast endpoint also returns current weather
15625
- if (shouldShowForecast) {
15626
- const forecastOptions = {
15627
- location: locationQuery,
15628
- tempUnit: this.temperatureUnit(),
15629
- useMockData: false, // Use real API, signals to use forecast endpoint
15630
- days: this.forecastDays(),
15631
- };
15632
- this.isForecastLoading.set(true);
15633
- this.weatherService.getForecast(forecastOptions).subscribe({
15634
- next: (data) => {
15635
- this.weatherData.set(data);
15636
- this.isLoading.set(false);
15637
- this.isForecastLoading.set(false);
15638
- setTimeout(() => this.cdr.detectChanges());
15639
- },
15640
- error: (error) => {
15641
- this.hasError.set(true);
15642
- this.errorMessage.set(error.message || 'Failed to load weather data. Please try again.');
15643
- this.isLoading.set(false);
15644
- this.isForecastLoading.set(false);
15645
- this.cdr.detectChanges();
15646
- },
15647
- });
15648
- return;
15649
- }
15650
- // If we only need current weather, use getWeather
15651
- const requestOptions = {
15652
- location: locationQuery,
15653
- tempUnit: this.temperatureUnit(),
15654
- useMockData: false, // Use real API
15655
- };
15656
- this.weatherService.getWeather(requestOptions).subscribe({
15657
- next: (data) => {
15658
- this.weatherData.set(data);
15659
- this.isLoading.set(false);
15660
- setTimeout(() => this.cdr.detectChanges());
15661
- },
15662
- error: (error) => {
15663
- this.hasError.set(true);
15664
- this.errorMessage.set(error.message || 'Failed to load weather data. Please try again.');
15665
- this.isLoading.set(false);
15666
- this.cdr.detectChanges();
15667
- },
15668
- });
15669
- }
15670
- /**
15671
- * Sets up the auto-refresh timer based on configuration
15672
- */
15673
- setupRefreshTimer() {
15674
- this.clearRefreshTimer();
15675
- if (!this.autoRefresh())
15676
- return;
15677
- const minInterval = 5; // 5 minutes minimum
15678
- const intervalValue = Math.max(this.refreshInterval(), minInterval);
15679
- const intervalMs = intervalValue * 60 * 1000;
15680
- this.refreshSubscription = interval(intervalMs)
15681
- .pipe(switchMap(() => {
15682
- // Always use the loadWeatherData method to determine the correct API call
15683
- this.loadWeatherData();
15684
- // Return an empty observable to satisfy the switchMap typing
15685
- return new Observable((observer) => {
15686
- observer.complete();
15687
- });
15688
- }))
15689
- .subscribe();
15690
- }
15691
- /**
15692
- * Clears the refresh timer subscription
15693
- */
15694
- clearRefreshTimer() {
15695
- if (this.refreshSubscription) {
15696
- this.refreshSubscription.unsubscribe();
15697
- this.refreshSubscription = null;
15698
- }
15699
- }
15700
- /**
15701
- * Manually refreshes the weather data
15702
- */
15703
- refreshWeather() {
15704
- this.loadWeatherData();
15705
- }
15706
- /**
15707
- * Gets the current temperature based on selected unit
15708
- */
15709
- getCurrentTemperature() {
15710
- if (!this.weatherData())
15711
- return 0;
15712
- return this.temperatureUnit() === '°C' ? this.weatherData().current.tempC : this.weatherData().current.tempF;
15713
- }
15714
- /**
15715
- * Gets the feels like temperature based on selected unit
15716
- */
15717
- getFeelsLikeTemperature() {
15718
- if (!this.weatherData())
15719
- return 0;
15720
- return this.temperatureUnit() === '°C'
15721
- ? this.weatherData().current.feelsLikeC
15722
- : this.weatherData().current.feelsLikeF;
15723
- }
15724
- /**
15725
- * Gets the humidity percentage
15726
- */
15727
- getHumidity() {
15728
- return this.weatherData()?.current.humidity || 0;
15729
- }
15730
- /**
15731
- * Gets the wind speed based on selected unit
15732
- */
15733
- getWindSpeed() {
15734
- if (!this.weatherData())
15735
- return 0;
15736
- return this.windSpeedUnit() === 'km/h' ? this.weatherData().current.windKph : this.weatherData().current.windMph;
15737
- }
15738
- /**
15739
- * Gets the current weather condition
15740
- */
15741
- getCurrentCondition() {
15742
- const conditionId = this.weatherData()?.current.condition || '';
15743
- return this.getConditionName(conditionId);
15744
- }
15745
- /**
15746
- * Gets the formatted last updated time
15747
- */
15748
- getLastUpdated() {
15749
- if (!this.weatherData()?.current.lastUpdated)
15750
- return '';
15751
- return new Date(this.weatherData().current.lastUpdated).toLocaleTimeString();
15752
- }
15753
- /**
15754
- * Gets the icon class for a weather condition
15755
- * @param conditionId Weather condition ID
15756
- * @returns Font Awesome icon class
15757
- */
15758
- getConditionIcon(conditionId) {
15759
- const condition = this.weatherService.getCondition(conditionId);
15760
- return condition?.icon || 'fa-solid fa-question';
15761
- }
15762
- /**
15763
- * Gets the display name for a weather condition
15764
- * @param conditionId Weather condition ID
15765
- * @returns Condition display name
15766
- */
15767
- getConditionName(conditionId) {
15768
- const condition = this.weatherService.getCondition(conditionId);
15769
- return condition?.name || 'Unknown';
15770
- }
15771
- /**
15772
- * Gets the color for a weather condition
15773
- * @param conditionId Weather condition ID
15774
- * @returns CSS color value
15775
- */
15776
- getConditionColor(conditionId) {
15777
- const condition = this.weatherService.getCondition(conditionId);
15778
- return condition?.color || '#999999';
15779
- }
15780
- /**
15781
- * Cleans up chart resources
15782
- * Required by AXPChartBaseComponent
15783
- */
15784
- cleanupChart() {
15785
- this.clearRefreshTimer();
15786
- }
15787
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherWidgetViewComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
15788
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPWeatherWidgetViewComponent, isStandalone: true, selector: "ng-component", providers: [
15789
- {
15790
- provide: AXPWeatherApiAbstract,
15791
- useClass: AXPWeatherApiService,
15792
- },
15793
- ], viewQueries: [{ propertyName: "containerEl", first: true, predicate: ["containerElement"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading weather data...</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Retry</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <i\n [class]=\"getConditionIcon(weatherData()?.current?.condition || '')\"\n [style.color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></i>\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">{{ getCurrentCondition() }}</div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{ temperatureUnit() }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">Humidity</div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">Wind</div>\n <div class=\"axp-weather-detail-value\">{{ getWindSpeed() }} {{ windSpeedUnit() }}</div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span>Forecast</span>\n </h3>\n <!-- <div class=\"axp-weather-scroll-indicator\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </div> -->\n </div>\n <!-- Loading indicator for forecast -->\n @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading forecast...</span>\n </div>\n }\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">{{ day.day }}</div>\n <div class=\"axp-weather-forecast-icon\" title=\"{{ getConditionName(day.condition) }}\">\n <i [class]=\"getConditionIcon(day.condition)\" [style.color]=\"getConditionColor(day.condition)\"></i>\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF }}\u00B0\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF }}\u00B0\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>Last updated: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'Refresh weather data'\"\n title=\"Refresh weather data\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Refresh</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>No weather data available</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Load Data</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;border-radius:8px;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);color:#fff;min-height:300px;background-color:#2c3e50}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-decoration.sunny{background:linear-gradient(135deg,#ff7e00,#f7d358)}.axp-weather-decoration.partlyCloudy{background:linear-gradient(135deg,#7ba2e7,#b4d2f7)}.axp-weather-decoration.cloudy{background:linear-gradient(135deg,#717e8c,#919eab)}.axp-weather-decoration.rain{background:linear-gradient(135deg,#6a8caf,#567a9e)}.axp-weather-decoration.snow{background:linear-gradient(135deg,#99b3cc,#c6d4e1)}.axp-weather-decoration.thunder{background:linear-gradient(135deg,#425777,#2c3e50)}.axp-weather-decoration.mist{background:linear-gradient(135deg,#94a3b8,#cbd5e1)}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.5))}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.75}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1.5rem;padding:1rem;background-color:rgba(0,0,0,.15);border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;color:rgba(255,255,255,.8);margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{margin-top:auto;margin-bottom:1rem;background-color:rgba(0,0,0,.15);border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{min-width:80px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;background-color:rgba(255,255,255,.1);border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{background-color:rgba(255,255,255,.15);transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.875rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.6rem}.axp-weather-location-name{font-size:1.1rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}@media (max-width: 400px){.axp-weather-current-weather{flex-direction:column;gap:.8rem;align-items:center}.axp-weather-temperature{font-size:2.2rem}.axp-weather-forecast-day{min-width:55px}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: HttpClientModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
15794
- }
15795
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherWidgetViewComponent, decorators: [{
15796
- type: Component,
15797
- args: [{ standalone: true, imports: [CommonModule, AXDateTimeModule, AXFormatModule, HttpClientModule], providers: [
15798
- {
15799
- provide: AXPWeatherApiAbstract,
15800
- useClass: AXPWeatherApiService,
15801
- },
15802
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading weather data...</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Retry</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <i\n [class]=\"getConditionIcon(weatherData()?.current?.condition || '')\"\n [style.color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></i>\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">{{ getCurrentCondition() }}</div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{ temperatureUnit() }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">Humidity</div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">Wind</div>\n <div class=\"axp-weather-detail-value\">{{ getWindSpeed() }} {{ windSpeedUnit() }}</div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span>Forecast</span>\n </h3>\n <!-- <div class=\"axp-weather-scroll-indicator\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </div> -->\n </div>\n <!-- Loading indicator for forecast -->\n @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading forecast...</span>\n </div>\n }\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">{{ day.day }}</div>\n <div class=\"axp-weather-forecast-icon\" title=\"{{ getConditionName(day.condition) }}\">\n <i [class]=\"getConditionIcon(day.condition)\" [style.color]=\"getConditionColor(day.condition)\"></i>\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF }}\u00B0\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF }}\u00B0\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>Last updated: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'Refresh weather data'\"\n title=\"Refresh weather data\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Refresh</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>No weather data available</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Load Data</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;border-radius:8px;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);color:#fff;min-height:300px;background-color:#2c3e50}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-decoration.sunny{background:linear-gradient(135deg,#ff7e00,#f7d358)}.axp-weather-decoration.partlyCloudy{background:linear-gradient(135deg,#7ba2e7,#b4d2f7)}.axp-weather-decoration.cloudy{background:linear-gradient(135deg,#717e8c,#919eab)}.axp-weather-decoration.rain{background:linear-gradient(135deg,#6a8caf,#567a9e)}.axp-weather-decoration.snow{background:linear-gradient(135deg,#99b3cc,#c6d4e1)}.axp-weather-decoration.thunder{background:linear-gradient(135deg,#425777,#2c3e50)}.axp-weather-decoration.mist{background:linear-gradient(135deg,#94a3b8,#cbd5e1)}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.5))}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.75}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1.5rem;padding:1rem;background-color:rgba(0,0,0,.15);border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;color:rgba(255,255,255,.8);margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{margin-top:auto;margin-bottom:1rem;background-color:rgba(0,0,0,.15);border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{min-width:80px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;background-color:rgba(255,255,255,.1);border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{background-color:rgba(255,255,255,.15);transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.875rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.6rem}.axp-weather-location-name{font-size:1.1rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}@media (max-width: 400px){.axp-weather-current-weather{flex-direction:column;gap:.8rem;align-items:center}.axp-weather-temperature{font-size:2.2rem}.axp-weather-forecast-day{min-width:55px}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"] }]
15803
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
15804
-
15805
- var weatherWidget_component = /*#__PURE__*/Object.freeze({
15806
- __proto__: null,
15807
- AXPWeatherWidgetViewComponent: AXPWeatherWidgetViewComponent
15808
- });
15809
-
15810
- /**
15811
- * Weather Widget Configuration
15812
- * Provides customization options for displaying weather data and forecast
15813
- */
15814
- const AXPWeatherWidget = {
15815
- name: 'weather',
15816
- title: 'Weather Widget',
15817
- categories: [AXP_WIDGETS_UTILITY_CATEGORY],
15818
- groups: [AXPWidgetGroupEnum.DashboardWidget],
15819
- type: 'dashboard',
15820
- icon: 'fa-light fa-cloud-sun',
15821
- properties: [
15822
- /* Location Settings */
15823
- {
15824
- name: 'city',
15825
- title: 'City',
15826
- group: AXP_DATA_PROPERTY_GROUP,
15827
- schema: {
15828
- defaultValue: 'New York',
15829
- dataType: 'string',
15830
- interface: {
15831
- name: 'city',
15832
- path: 'options.city',
15833
- type: AXPWidgetsCatalog.text,
15834
- },
15835
- },
15836
- visible: true,
15837
- },
15838
- /* Display Options */
15839
- // {
15840
- // name: 'showCurrentCondition',
15841
- // title: 'Show Current Condition',
15842
- // group: AXP_APPEARANCE_PROPERTY_GROUP,
15843
- // schema: {
15844
- // defaultValue: true,
15845
- // dataType: 'boolean',
15846
- // interface: {
15847
- // name: 'showCurrentCondition',
15848
- // path: 'options.showCurrentCondition',
15849
- // type: AXPWidgetsCatalog.toggle,
15850
- // },
15851
- // },
15852
- // visible: true,
15853
- // },
15854
- // {
15855
- // name: 'showTemperature',
15856
- // title: 'Show Temperature',
15857
- // group: AXP_APPEARANCE_PROPERTY_GROUP,
15858
- // schema: {
15859
- // defaultValue: true,
15860
- // dataType: 'boolean',
15861
- // interface: {
15862
- // name: 'showTemperature',
15863
- // path: 'options.showTemperature',
15864
- // type: AXPWidgetsCatalog.toggle,
15865
- // },
15866
- // },
15867
- // visible: true,
15868
- // },
15869
- // {
15870
- // name: 'showCurrentCondition',
15871
- // title: 'Show Current Condition',
15872
- // group: AXP_APPEARANCE_PROPERTY_GROUP,
15873
- // schema: {
15874
- // defaultValue: true,
15875
- // dataType: 'boolean',
15876
- // interface: {
15877
- // name: 'showCurrentCondition',
15878
- // path: 'options.showCurrentCondition',
15879
- // type: AXPWidgetsCatalog.toggle,
15880
- // },
15881
- // },
15882
- // visible: true,
15883
- // },
15884
- // {
15885
- // name: 'showTemperature',
15886
- // title: 'Show Temperature',
15887
- // group: AXP_APPEARANCE_PROPERTY_GROUP,
15888
- // schema: {
15889
- // defaultValue: true,
15890
- // dataType: 'boolean',
15891
- // interface: {
15892
- // name: 'showTemperature',
15893
- // path: 'options.showTemperature',
15894
- // type: AXPWidgetsCatalog.toggle,
15895
- // },
15896
- // },
15897
- // visible: true,
15898
- // },
15899
- {
15900
- name: 'showHumidity',
15901
- title: 'Show Humidity',
15902
- group: AXP_APPEARANCE_PROPERTY_GROUP,
15903
- schema: {
15904
- defaultValue: true,
15905
- dataType: 'boolean',
15906
- interface: {
15907
- name: 'showHumidity',
15908
- path: 'options.showHumidity',
15909
- type: AXPWidgetsCatalog.toggle,
15910
- },
15911
- },
15912
- visible: true,
15913
- },
15914
- {
15915
- name: 'showWind',
15916
- title: 'Show Wind Speed',
15917
- group: AXP_APPEARANCE_PROPERTY_GROUP,
15918
- schema: {
15919
- defaultValue: true,
15920
- dataType: 'boolean',
15921
- interface: {
15922
- name: 'showWind',
15923
- path: 'options.showWind',
15924
- type: AXPWidgetsCatalog.toggle,
15925
- },
15926
- },
15927
- visible: true,
15928
- },
15929
- {
15930
- name: 'showForecast',
15931
- title: 'Show Forecast',
15932
- group: AXP_APPEARANCE_PROPERTY_GROUP,
15933
- schema: {
15934
- defaultValue: true,
15935
- dataType: 'boolean',
15936
- interface: {
15937
- name: 'showForecast',
15938
- path: 'options.showForecast',
15939
- type: AXPWidgetsCatalog.toggle,
15940
- },
15941
- },
15942
- visible: true,
15943
- },
15944
- {
15945
- name: 'forecastDays',
15946
- title: 'Forecast Days',
15947
- group: AXP_APPEARANCE_PROPERTY_GROUP,
15948
- schema: {
15949
- defaultValue: 5,
15950
- dataType: 'number',
15951
- interface: {
15952
- name: 'forecastDays',
15953
- path: 'options.forecastDays',
15954
- type: AXPWidgetsCatalog.number,
15955
- options: {
15956
- minValue: 1,
15957
- maxValue: 7,
15958
- step: 1,
15959
- },
15960
- },
15961
- },
15962
- visible: true,
15963
- },
15964
- /* Units Settings */
15965
- {
15966
- name: 'temperatureUnit',
15967
- title: 'Temperature Unit',
15968
- group: AXP_DATA_PROPERTY_GROUP,
15969
- schema: {
15970
- defaultValue: '°C',
15971
- dataType: 'string',
15972
- interface: {
15973
- name: 'temperatureUnit',
15974
- path: 'options.temperatureUnit',
15975
- type: AXPWidgetsCatalog.select,
15976
- options: {
15977
- dataSource: ['°C', '°F'],
15978
- },
15979
- },
15980
- },
15981
- visible: true,
15982
- },
15983
- {
15984
- name: 'windSpeedUnit',
15985
- title: 'Wind Speed Unit',
15986
- group: AXP_DATA_PROPERTY_GROUP,
15987
- schema: {
15988
- defaultValue: 'km/h',
15989
- dataType: 'string',
15990
- interface: {
15991
- name: 'windSpeedUnit',
15992
- path: 'options.windSpeedUnit',
15993
- type: AXPWidgetsCatalog.select,
15994
- options: {
15995
- dataSource: ['km/h', 'mph', 'm/s'],
15996
- },
15997
- },
15998
- },
15999
- visible: true,
16000
- },
16001
- /* Refresh Settings */
16002
- {
16003
- name: 'autoRefresh',
16004
- title: 'Auto Refresh',
16005
- group: AXP_BEHAVIOR_PROPERTY_GROUP,
16006
- schema: {
16007
- defaultValue: true,
16008
- dataType: 'boolean',
16009
- interface: {
16010
- name: 'autoRefresh',
16011
- path: 'options.autoRefresh',
16012
- type: AXPWidgetsCatalog.toggle,
16013
- },
16014
- },
16015
- visible: true,
16016
- },
16017
- {
16018
- name: 'refreshInterval',
16019
- title: 'Refresh Interval (minutes)',
16020
- group: AXP_BEHAVIOR_PROPERTY_GROUP,
16021
- schema: {
16022
- defaultValue: 15,
16023
- dataType: 'number',
16024
- interface: {
16025
- name: 'refreshInterval',
16026
- path: 'options.refreshInterval',
16027
- type: AXPWidgetsCatalog.select,
16028
- options: {
16029
- dataSource: [5, 10, 15, 30, 60],
16030
- },
16031
- },
16032
- },
16033
- visible: true,
16034
- },
16035
- ],
16036
- components: {
16037
- view: {
16038
- component: () => Promise.resolve().then(function () { return weatherWidget_component; }).then((c) => c.AXPWeatherWidgetViewComponent),
16039
- },
16040
- },
16041
- meta: {
16042
- dimensions: {
16043
- width: 3,
16044
- height: 7,
16045
- minWidth: 2,
16046
- minHeight: 4,
16047
- maxWidth: 4,
16048
- maxHeight: 8,
16049
- },
16050
- },
16051
- };
16052
-
16053
- /**
16054
- * Weather Widget Module
16055
- * Provides weather display functionality as a dashboard widget
16056
- */
16057
- class AXPWeatherWidgetModule {
16058
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherWidgetModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
16059
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherWidgetModule, imports: [HttpClientModule] }); }
16060
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherWidgetModule, providers: [
16061
- // You can choose which implementation to use:
16062
- // Option 1: Use the mock service for development/testing
16063
- {
16064
- provide: AXPWeatherApiAbstract,
16065
- useClass: AXPWeatherApiMockService,
16066
- },
16067
- // Option 2: Use the real API service for production (uncomment to use)
16068
- // {
16069
- // provide: AXPWeatherApiAbstract,
16070
- // useClass: AXPWeatherApiService
16071
- // }
16072
- ], imports: [HttpClientModule] }); }
16073
- }
16074
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPWeatherWidgetModule, decorators: [{
16075
- type: NgModule,
16076
- args: [{
16077
- imports: [HttpClientModule],
16078
- declarations: [],
16079
- providers: [
16080
- // You can choose which implementation to use:
16081
- // Option 1: Use the mock service for development/testing
16082
- {
16083
- provide: AXPWeatherApiAbstract,
16084
- useClass: AXPWeatherApiMockService,
16085
- },
16086
- // Option 2: Use the real API service for production (uncomment to use)
16087
- // {
16088
- // provide: AXPWeatherApiAbstract,
16089
- // useClass: AXPWeatherApiService
16090
- // }
16091
- ],
16092
- exports: [],
16093
- }]
16094
- }] });
16095
-
16096
- // export interface AXPWidgetOptions {
16097
- // }
16098
- // export interface AXPWidgetConfig<T extends AXPWidgetOptions> {
16099
- // name: string;
16100
- // options: T;
16101
- // }
16102
- // export interface AXpTextBoxWidget {
16103
- // }
16104
- // export interface AXPTextBoxWidgetOptions {
16105
- // disabled?: boolean;
16106
- // readonly?: boolean;
16107
- // hasClearButton?: boolean;
16108
- // placeholder?: string;
16109
- // }
16110
-
16111
12389
  class AXPCronJobWidgetViewComponent extends AXPValueWidgetComponent {
16112
12390
  constructor() {
16113
12391
  super(...arguments);
@@ -17174,7 +13452,7 @@ class AXPTabularDataWidgetEditComponent extends AXPValueWidgetComponent {
17174
13452
  this.platform = inject(AXPlatform);
17175
13453
  }
17176
13454
  async openPopup() {
17177
- const { AXPTabularDataPopupComponent } = await import('./acorex-platform-widgets-tabular-data-edit-popup.component-CybYV1Kf.mjs');
13455
+ const { AXPTabularDataPopupComponent } = await import('./acorex-platform-widgets-tabular-data-edit-popup.component-1IseEVXQ.mjs');
17178
13456
  const popupData = await this.popupService.open(AXPTabularDataPopupComponent, {
17179
13457
  size: this.platform.is('Mobile') || this.platform.is('SM') ? 'full' : this.columns().length > 3 ? 'lg' : 'md',
17180
13458
  header: true,
@@ -17656,7 +13934,7 @@ class AXPDateTimeFilterWidgetEditComponent extends AXPValueWidgetComponent {
17656
13934
  </div>
17657
13935
  }
17658
13936
  </div>
17659
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i3$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDateTimeBoxModule }, { kind: "component", type: i3$2.AXDateTimeBoxComponent, selector: "ax-datetime-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "depth", "id", "type", "look", "holidayDates", "allowTyping", "format"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "onOpened", "onClosed", "readonlyChange", "disabledChange", "formatChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13937
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i3$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDateTimeBoxModule }, { kind: "component", type: i3$2.AXDateTimeBoxComponent, selector: "ax-datetime-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "depth", "id", "type", "look", "holidayDates", "allowTyping", "calendar", "picker", "format"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "onOpened", "onClosed", "readonlyChange", "disabledChange", "formatChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
17660
13938
  }
17661
13939
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPDateTimeFilterWidgetEditComponent, decorators: [{
17662
13940
  type: Component,
@@ -19329,19 +15607,10 @@ class AXPWidgetsModule {
19329
15607
  AXPBetweenExpressionValidationWidget,
19330
15608
  AXPEqualValidationWidget,
19331
15609
  AXPCallbackValidationWidget,
19332
- //charts
19333
- AXPDonutChartWidget,
19334
- AXPBarChartWidget,
19335
- AXPGaugeChartWidget,
19336
- AXPStickyNoteWidget,
19337
- AXPClockCalendarWidget,
19338
- AXPWeatherWidget,
19339
15610
  AXPMetaDataWidget,
19340
15611
  //Custom Widgets
19341
15612
  AXPNumberUnitBoxWidget,
19342
15613
  AXPPanelWidget,
19343
- AXPNotificationWidget,
19344
- AXPTaskListWidget,
19345
15614
  ],
19346
15615
  })] }); }
19347
15616
  }
@@ -19409,19 +15678,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
19409
15678
  AXPBetweenExpressionValidationWidget,
19410
15679
  AXPEqualValidationWidget,
19411
15680
  AXPCallbackValidationWidget,
19412
- //charts
19413
- AXPDonutChartWidget,
19414
- AXPBarChartWidget,
19415
- AXPGaugeChartWidget,
19416
- AXPStickyNoteWidget,
19417
- AXPClockCalendarWidget,
19418
- AXPWeatherWidget,
19419
15681
  AXPMetaDataWidget,
19420
15682
  //Custom Widgets
19421
15683
  AXPNumberUnitBoxWidget,
19422
15684
  AXPPanelWidget,
19423
- AXPNotificationWidget,
19424
- AXPTaskListWidget,
19425
15685
  ],
19426
15686
  }),
19427
15687
  ],
@@ -19438,5 +15698,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
19438
15698
  * Generated bundle index. Do not edit.
19439
15699
  */
19440
15700
 
19441
- export { AXPAdvancedGridItemWidget, AXPAdvancedGridItemWidgetDesignerComponent, AXPAdvancedGridItemWidgetPrintComponent, AXPAdvancedGridItemWidgetViewComponent, AXPAdvancedGridOptionsWidget, AXPAdvancedGridOptionsWidgetEditComponent, AXPAdvancedGridWidget, AXPAdvancedGridWidgetDesignerComponent, AXPAdvancedGridWidgetViewComponent, AXPAvatarWidget, AXPAvatarWidgetColumnComponent, AXPAvatarWidgetDesignerComponent, AXPAvatarWidgetEditComponent, AXPAvatarWidgetPrintComponent, AXPAvatarWidgetViewComponent, AXPBarChartWidget, AXPBarChartWidgetViewComponent, AXPBetweenExpressionValidationWidget, AXPBetweenValidationWidgetEditComponent, AXPBlockWidget, AXPBlockWidgetDesignerComponent, AXPBlockWidgetViewComponent, AXPBorderWidget, AXPBorderWidgetEditComponent, AXPButtonWidget, AXPButtonWidgetViewComponent, AXPCallbackValidationWidget, AXPCallbackValidationWidgetEditComponent, AXPCheckBoxWidget, AXPCheckBoxWidgetEditComponent, AXPClockCalendarWidget, AXPClockCalendarWidgetViewComponent, AXPContactWidget, AXPContactWidgetColumnComponent, AXPContactWidgetEditComponent, AXPContactWidgetPrintComponent, AXPContactWidgetViewComponent, AXPDateTimeBoxWidget, AXPDateTimeBoxWidgetColumnComponent, AXPDateTimeBoxWidgetEditComponent, AXPDateTimeBoxWidgetFilterComponent, AXPDateTimeBoxWidgetPrintComponent, AXPDateTimeBoxWidgetViewComponent, AXPDonutChartWidget, AXPDonutChartWidgetViewComponent, AXPEmailBoxWidget, AXPEmailBoxWidgetColumnComponent, AXPEmailBoxWidgetEditComponent, AXPEmailBoxWidgetFilterComponent, AXPEmailBoxWidgetPrintComponent, AXPEmailBoxWidgetViewComponent, AXPEqualValidationWidget, AXPEqualValidationWidgetEditComponent, AXPFileBoxWidget, AXPFileBoxWidgetColumnComponent, AXPFileBoxWidgetEditComponent, AXPFileBoxWidgetFilterComponent, AXPFileBoxWidgetPrintComponent, AXPFileBoxWidgetViewComponent, AXPFileManagementService, AXPFlexOptionsWidget, AXPFlexOptionsWidgetEditComponent, AXPGalleryWidget, AXPGalleryWidgetEditComponent, AXPGalleryWidgetPrintComponent, AXPGalleryWidgetViewComponent, AXPGaugeChartWidget, AXPGaugeChartWidgetViewComponent, AXPGreaterThanExpressionValidationWidget, AXPGreaterThanValidationWidgetEditComponent, AXPGridOptionsWidget, AXPGridOptionsWidgetEditComponent, AXPLargeTextWidget, AXPLargeTextWidgetColumnComponent, AXPLargeTextWidgetEditComponent, AXPLargeTextWidgetFilterComponent, AXPLargeTextWidgetPrintComponent, AXPLargeTextWidgetViewComponent, AXPLessThanExpressionValidationWidget, AXPLessThanValidationWidgetEditComponent, AXPLinkWidget, AXPLinkWidgetColumnComponent, AXPLinkWidgetEditComponent, AXPLinkWidgetFilterComponent, AXPLinkWidgetPrintComponent, AXPLinkWidgetViewComponent, AXPMapBoxWidget, AXPMapBoxWidgetEditComponent, AXPMapBoxWidgetViewComponent, AXPMaxLengthExpressionValidationWidget, AXPMaxLengthValidationWidgetEditComponent, AXPMinLengthExpressionValidationWidget, AXPMinLengthValidationWidgetEditComponent, AXPNotificationWidget, AXPNotificationWidgetViewComponent, AXPNumberBoxWidget, AXPNumberBoxWidgetColumnComponent, AXPNumberBoxWidgetEditComponent, AXPNumberBoxWidgetFilterComponent, AXPNumberBoxWidgetPrintComponent, AXPNumberBoxWidgetViewComponent, AXPPageWidget, AXPPageWidgetViewComponent, AXPPasswordBoxWidget, AXPPasswordBoxWidgetColumnComponent, AXPPasswordBoxWidgetEditComponent, AXPPasswordBoxWidgetFilterComponent, AXPPasswordBoxWidgetPrintComponent, AXPPasswordBoxWidgetViewComponent, AXPPhoneBoxWidget, AXPPhoneBoxWidgetColumnComponent, AXPPhoneBoxWidgetEditComponent, AXPPhoneBoxWidgetFilterComponent, AXPPhoneBoxWidgetPrintComponent, AXPPhoneBoxWidgetViewComponent, AXPPropertyEditorHelper, AXPRegularExpressionValidationWidget, AXPRegularExpressionValidationWidgetEditComponent, AXPRepeaterWidget, AXPRepeaterWidgetDesignerComponent, AXPRepeaterWidgetEditComponent, AXPRepeaterWidgetPrintComponent, AXPRepeaterWidgetViewComponent, AXPRequiredValidationWidget, AXPRequiredValidationWidgetEditComponent, AXPRichTextWidget, AXPRichTextWidgetColumnComponent, AXPRichTextWidgetEditComponent, AXPRichTextWidgetFilterComponent, AXPRichTextWidgetPrintComponent, AXPRichTextWidgetViewComponent, AXPSelectBoxWidget, AXPSelectBoxWidgetColumnComponent, AXPSelectBoxWidgetEditComponent, AXPSelectBoxWidgetFilterComponent, AXPSelectBoxWidgetPrintComponent, AXPSelectBoxWidgetViewComponent, AXPSelectionListWidget, AXPSelectionListWidgetColumnComponent, AXPSelectionListWidgetDesignerComponent, AXPSelectionListWidgetEditComponent, AXPSelectionListWidgetFilterComponent, AXPSelectionListWidgetPrintComponent, AXPSelectionListWidgetViewComponent, AXPSignatureWidget, AXPSignatureWidgetColumnComponent, AXPSignatureWidgetEditComponent, AXPSignatureWidgetFilterComponent, AXPSignatureWidgetPrintComponent, AXPSignatureWidgetViewComponent, AXPSingleFileBoxWidget, AXPSingleFileBoxWidgetColumnComponent, AXPSingleFileBoxWidgetEditComponent, AXPSingleFileBoxWidgetFilterComponent, AXPSingleFileBoxWidgetPrintComponent, AXPSingleFileBoxWidgetViewComponent, AXPSpacingWidget, AXPSpacingWidgetEditComponent, AXPStickyNoteWidget, AXPStickyNoteWidgetViewComponent, AXPTaskListWidget, AXPTaskListWidgetViewComponent, AXPTemplateBoxWidget, AXPTemplateBoxWidgetColumnComponent, AXPTemplateBoxWidgetEditComponent, AXPTemplateBoxWidgetFilterComponent, AXPTemplateBoxWidgetPrintComponent, AXPTemplateBoxWidgetViewComponent, AXPTextBoxWidget, AXPTextBoxWidgetColumnComponent, AXPTextBoxWidgetEditComponent, AXPTextBoxWidgetFilterComponent, AXPTextBoxWidgetPrintComponent$1 as AXPTextBoxWidgetPrintComponent, AXPTextBoxWidgetViewComponent, AXPToggleWidget, AXPToggleWidgetColumnComponent, AXPToggleWidgetEditComponent, AXPToggleWidgetFilterComponent, AXPToggleWidgetPrintComponent, AXPToggleWidgetViewComponent, AXPWeatherApiAbstract, AXPWeatherApiMockService, AXPWeatherApiService, AXPWeatherWidget, AXPWeatherWidgetModule, AXPWeatherWidgetViewComponent, AXPWidgetsModule, AXP_ALLOW_MULTIPLE_PROPERTY, AXP_ALLOW_SEARCH_PROPERTY, AXP_ANIMATION_PROPERTY_GROUP, AXP_APPEARANCE_PROPERTY_GROUP, AXP_BEHAVIOR_PROPERTY_GROUP, AXP_BETWEEN_VALIDATION_PROPERTY, AXP_BG_COLOR_PROPERTY, AXP_BOX_MODEL_PROPERTY_GROUP, AXP_CALLBACK_VALIDATION_PROPERTY, AXP_COLOR_PROPERTY, AXP_CONTENT_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_DATA_SOURCE_PROPERTIES, AXP_DATA_SOURCE_PROPERTY, AXP_DATA_SOURCE_TEXT_FIELD, AXP_DATA_SOURCE_VALUE_FIELD, AXP_DATE_FORMAT_OPTIONS, AXP_DATE_FORMAT_PROPERTY, AXP_DESCRIPTION_PROPERTY, AXP_DIRECTION_PROPERTY, AXP_DISABLED_PROPERTY, AXP_DOWNLOADABLE_PROPERTY, AXP_EQUAL_VALIDATION_PROPERTY, AXP_FALSY_TEXT_PROPERTY, AXP_FONT_SIZE_PROPERTY, AXP_Flex_Box_Align_Options, AXP_Flex_Box_Alignments, AXP_Flex_Box_Justify_Options, AXP_GREATER_THAN_VALIDATION_PROPERTY, AXP_Grid_Box_Align_Items_Options, AXP_Grid_Box_Alignments, AXP_Grid_Box_Justify_Items_Options, AXP_HAS_CLEAR_BUTTON_PROPERTY, AXP_HAS_COPY_ICON_PROPERTY, AXP_HAS_EYE_ICON_PROPERTY, AXP_HAS_ICON_PROPERTY, AXP_HAS_LABEL_PROPERTY, AXP_ICON_PROPERTY, AXP_IS_LOADING_PROPERTY, AXP_LABEL_PROPERTY, AXP_LAYOUT_ADVANCED_GRID_PROPERTY, AXP_LAYOUT_BORDER_PROPERTY, AXP_LAYOUT_COLUMNS_PROPERTY, AXP_LAYOUT_COL_END_PROPERTY, AXP_LAYOUT_COL_SPAN_PROPERTY, AXP_LAYOUT_COL_START_PROPERTY, AXP_LAYOUT_FLEX_PROPERTY, AXP_LAYOUT_FLEX_PROPERTY_GROUP, AXP_LAYOUT_GAP_PROPERTY, AXP_LAYOUT_GRID_ITEM_PROPERTIES, AXP_LAYOUT_GRID_PROPERTIES, AXP_LAYOUT_GRID_PROPERTY, AXP_LAYOUT_GRID_PROPERTY_GROUP, AXP_LAYOUT_GRID_ROW_PROPERTIES, AXP_LAYOUT_ROWS_PROPERTY, AXP_LAYOUT_SPACING_PROPERTY, AXP_LESS_THAN_VALIDATION_PROPERTY, AXP_MAX_LENGTH_VALIDATION_PROPERTY, AXP_MIN_LENGTH_VALIDATION_PROPERTY, AXP_NAME_PROPERTY, AXP_PLACEHOLDER_PROPERTY, AXP_READONLY_PROPERTY, AXP_REGULAR_EXPRESSION_VALIDATION_PROPERTY, AXP_REQUIRED_VALIDATION_PROPERTY, AXP_STYLE_COLOR_PROPERTY, AXP_STYLE_LOOK_PROPERTY, AXP_STYLING_PROPERTY_GROUP, AXP_TABLE_COLUMN_HEIGHT_PROPERTY, AXP_TABLE_COLUMN_WIDTH_PROPERTY, AXP_TEXT_FIELD_PROPERTY, AXP_TEXT_PROPERTY, AXP_THEME_PROPERTY, AXP_TIMEZONE_OPTIONS, AXP_TITLE_PROPERTY, AXP_TRULY_TEXT_PROPERTY, AXP_VALIDATION_PROPERTY_GROUP, AXP_VALUE_FIELD_PROPERTY, AXP_WIDGETS_CHART_CATEGORY, AXP_WIDGETS_UTILITY_CATEGORY, AXP_WIDGET_PROPERTY_GROUP, AXP_default_Border_Box_Units, AXP_default_Border_Box_Value, AXP_default_Spacing_Box_Units, AXP_default_Spacing_Box_Value, DEFAULT_STRATEGY_CONFIG, STRATEGY_CONFIG_TOKEN, booleanDefaultProperty, findNonEmptyBreakpoints, largeTextDefaultProperty, numberDefaultProperty, numberMaxValueProperty, numberMinValueProperty, plainTextDefaultProperty };
15701
+ export { AXPAdvancedGridItemWidget, AXPAdvancedGridItemWidgetDesignerComponent, AXPAdvancedGridItemWidgetPrintComponent, AXPAdvancedGridItemWidgetViewComponent, AXPAdvancedGridOptionsWidget, AXPAdvancedGridOptionsWidgetEditComponent, AXPAdvancedGridWidget, AXPAdvancedGridWidgetDesignerComponent, AXPAdvancedGridWidgetViewComponent, AXPAvatarWidget, AXPAvatarWidgetColumnComponent, AXPAvatarWidgetDesignerComponent, AXPAvatarWidgetEditComponent, AXPAvatarWidgetPrintComponent, AXPAvatarWidgetViewComponent, AXPBetweenExpressionValidationWidget, AXPBetweenValidationWidgetEditComponent, AXPBlockWidget, AXPBlockWidgetDesignerComponent, AXPBlockWidgetViewComponent, AXPBorderWidget, AXPBorderWidgetEditComponent, AXPButtonWidget, AXPButtonWidgetViewComponent, AXPCallbackValidationWidget, AXPCallbackValidationWidgetEditComponent, AXPCheckBoxWidget, AXPCheckBoxWidgetEditComponent, AXPContactWidget, AXPContactWidgetColumnComponent, AXPContactWidgetEditComponent, AXPContactWidgetPrintComponent, AXPContactWidgetViewComponent, AXPDateTimeBoxWidget, AXPDateTimeBoxWidgetColumnComponent, AXPDateTimeBoxWidgetEditComponent, AXPDateTimeBoxWidgetFilterComponent, AXPDateTimeBoxWidgetPrintComponent, AXPDateTimeBoxWidgetViewComponent, AXPEmailBoxWidget, AXPEmailBoxWidgetColumnComponent, AXPEmailBoxWidgetEditComponent, AXPEmailBoxWidgetFilterComponent, AXPEmailBoxWidgetPrintComponent, AXPEmailBoxWidgetViewComponent, AXPEqualValidationWidget, AXPEqualValidationWidgetEditComponent, AXPFileBoxWidget, AXPFileBoxWidgetColumnComponent, AXPFileBoxWidgetEditComponent, AXPFileBoxWidgetFilterComponent, AXPFileBoxWidgetPrintComponent, AXPFileBoxWidgetViewComponent, AXPFileManagementService, AXPFlexOptionsWidget, AXPFlexOptionsWidgetEditComponent, AXPGalleryWidget, AXPGalleryWidgetEditComponent, AXPGalleryWidgetPrintComponent, AXPGalleryWidgetViewComponent, AXPGreaterThanExpressionValidationWidget, AXPGreaterThanValidationWidgetEditComponent, AXPGridOptionsWidget, AXPGridOptionsWidgetEditComponent, AXPLargeTextWidget, AXPLargeTextWidgetColumnComponent, AXPLargeTextWidgetEditComponent, AXPLargeTextWidgetFilterComponent, AXPLargeTextWidgetPrintComponent, AXPLargeTextWidgetViewComponent, AXPLessThanExpressionValidationWidget, AXPLessThanValidationWidgetEditComponent, AXPLinkWidget, AXPLinkWidgetColumnComponent, AXPLinkWidgetEditComponent, AXPLinkWidgetFilterComponent, AXPLinkWidgetPrintComponent, AXPLinkWidgetViewComponent, AXPMapBoxWidget, AXPMapBoxWidgetEditComponent, AXPMapBoxWidgetViewComponent, AXPMaxLengthExpressionValidationWidget, AXPMaxLengthValidationWidgetEditComponent, AXPMinLengthExpressionValidationWidget, AXPMinLengthValidationWidgetEditComponent, AXPNumberBoxWidget, AXPNumberBoxWidgetColumnComponent, AXPNumberBoxWidgetEditComponent, AXPNumberBoxWidgetFilterComponent, AXPNumberBoxWidgetPrintComponent, AXPNumberBoxWidgetViewComponent, AXPPageWidget, AXPPageWidgetViewComponent, AXPPasswordBoxWidget, AXPPasswordBoxWidgetColumnComponent, AXPPasswordBoxWidgetEditComponent, AXPPasswordBoxWidgetFilterComponent, AXPPasswordBoxWidgetPrintComponent, AXPPasswordBoxWidgetViewComponent, AXPPhoneBoxWidget, AXPPhoneBoxWidgetColumnComponent, AXPPhoneBoxWidgetEditComponent, AXPPhoneBoxWidgetFilterComponent, AXPPhoneBoxWidgetPrintComponent, AXPPhoneBoxWidgetViewComponent, AXPPropertyEditorHelper, AXPRegularExpressionValidationWidget, AXPRegularExpressionValidationWidgetEditComponent, AXPRepeaterWidget, AXPRepeaterWidgetDesignerComponent, AXPRepeaterWidgetEditComponent, AXPRepeaterWidgetPrintComponent, AXPRepeaterWidgetViewComponent, AXPRequiredValidationWidget, AXPRequiredValidationWidgetEditComponent, AXPRichTextWidget, AXPRichTextWidgetColumnComponent, AXPRichTextWidgetEditComponent, AXPRichTextWidgetFilterComponent, AXPRichTextWidgetPrintComponent, AXPRichTextWidgetViewComponent, AXPSelectBoxWidget, AXPSelectBoxWidgetColumnComponent, AXPSelectBoxWidgetEditComponent, AXPSelectBoxWidgetFilterComponent, AXPSelectBoxWidgetPrintComponent, AXPSelectBoxWidgetViewComponent, AXPSelectionListWidget, AXPSelectionListWidgetColumnComponent, AXPSelectionListWidgetDesignerComponent, AXPSelectionListWidgetEditComponent, AXPSelectionListWidgetFilterComponent, AXPSelectionListWidgetPrintComponent, AXPSelectionListWidgetViewComponent, AXPSignatureWidget, AXPSignatureWidgetColumnComponent, AXPSignatureWidgetEditComponent, AXPSignatureWidgetFilterComponent, AXPSignatureWidgetPrintComponent, AXPSignatureWidgetViewComponent, AXPSingleFileBoxWidget, AXPSingleFileBoxWidgetColumnComponent, AXPSingleFileBoxWidgetEditComponent, AXPSingleFileBoxWidgetFilterComponent, AXPSingleFileBoxWidgetPrintComponent, AXPSingleFileBoxWidgetViewComponent, AXPSpacingWidget, AXPSpacingWidgetEditComponent, AXPTemplateBoxWidget, AXPTemplateBoxWidgetColumnComponent, AXPTemplateBoxWidgetEditComponent, AXPTemplateBoxWidgetFilterComponent, AXPTemplateBoxWidgetPrintComponent, AXPTemplateBoxWidgetViewComponent, AXPTextBoxWidget, AXPTextBoxWidgetColumnComponent, AXPTextBoxWidgetEditComponent, AXPTextBoxWidgetFilterComponent, AXPTextBoxWidgetPrintComponent$1 as AXPTextBoxWidgetPrintComponent, AXPTextBoxWidgetViewComponent, AXPToggleWidget, AXPToggleWidgetColumnComponent, AXPToggleWidgetEditComponent, AXPToggleWidgetFilterComponent, AXPToggleWidgetPrintComponent, AXPToggleWidgetViewComponent, AXPWidgetsModule, AXP_ALLOW_MULTIPLE_PROPERTY, AXP_ALLOW_SEARCH_PROPERTY, AXP_ANIMATION_PROPERTY_GROUP, AXP_APPEARANCE_PROPERTY_GROUP, AXP_BEHAVIOR_PROPERTY_GROUP, AXP_BETWEEN_VALIDATION_PROPERTY, AXP_BG_COLOR_PROPERTY, AXP_BOX_MODEL_PROPERTY_GROUP, AXP_CALLBACK_VALIDATION_PROPERTY, AXP_COLOR_PROPERTY, AXP_CONTENT_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_DATA_SOURCE_PROPERTIES, AXP_DATA_SOURCE_PROPERTY, AXP_DATA_SOURCE_TEXT_FIELD, AXP_DATA_SOURCE_VALUE_FIELD, AXP_DATE_FORMAT_PROPERTY, AXP_DESCRIPTION_PROPERTY, AXP_DIRECTION_PROPERTY, AXP_DISABLED_PROPERTY, AXP_DOWNLOADABLE_PROPERTY, AXP_EQUAL_VALIDATION_PROPERTY, AXP_FALSY_TEXT_PROPERTY, AXP_FONT_SIZE_PROPERTY, AXP_Flex_Box_Align_Options, AXP_Flex_Box_Alignments, AXP_Flex_Box_Justify_Options, AXP_GREATER_THAN_VALIDATION_PROPERTY, AXP_Grid_Box_Align_Items_Options, AXP_Grid_Box_Alignments, AXP_Grid_Box_Justify_Items_Options, AXP_HAS_CLEAR_BUTTON_PROPERTY, AXP_HAS_COPY_ICON_PROPERTY, AXP_HAS_EYE_ICON_PROPERTY, AXP_HAS_ICON_PROPERTY, AXP_HAS_LABEL_PROPERTY, AXP_ICON_PROPERTY, AXP_IS_LOADING_PROPERTY, AXP_LABEL_PROPERTY, AXP_LAYOUT_ADVANCED_GRID_PROPERTY, AXP_LAYOUT_BORDER_PROPERTY, AXP_LAYOUT_COLUMNS_PROPERTY, AXP_LAYOUT_COL_END_PROPERTY, AXP_LAYOUT_COL_SPAN_PROPERTY, AXP_LAYOUT_COL_START_PROPERTY, AXP_LAYOUT_FLEX_PROPERTY, AXP_LAYOUT_FLEX_PROPERTY_GROUP, AXP_LAYOUT_GAP_PROPERTY, AXP_LAYOUT_GRID_ITEM_PROPERTIES, AXP_LAYOUT_GRID_PROPERTIES, AXP_LAYOUT_GRID_PROPERTY, AXP_LAYOUT_GRID_PROPERTY_GROUP, AXP_LAYOUT_GRID_ROW_PROPERTIES, AXP_LAYOUT_ROWS_PROPERTY, AXP_LAYOUT_SPACING_PROPERTY, AXP_LESS_THAN_VALIDATION_PROPERTY, AXP_MAX_LENGTH_VALIDATION_PROPERTY, AXP_MIN_LENGTH_VALIDATION_PROPERTY, AXP_NAME_PROPERTY, AXP_PLACEHOLDER_PROPERTY, AXP_READONLY_PROPERTY, AXP_REGULAR_EXPRESSION_VALIDATION_PROPERTY, AXP_REQUIRED_VALIDATION_PROPERTY, AXP_STYLE_COLOR_PROPERTY, AXP_STYLE_LOOK_PROPERTY, AXP_STYLING_PROPERTY_GROUP, AXP_TABLE_COLUMN_HEIGHT_PROPERTY, AXP_TABLE_COLUMN_WIDTH_PROPERTY, AXP_TEXT_FIELD_PROPERTY, AXP_TEXT_PROPERTY, AXP_THEME_PROPERTY, AXP_TITLE_PROPERTY, AXP_TRULY_TEXT_PROPERTY, AXP_VALIDATION_PROPERTY_GROUP, AXP_VALUE_FIELD_PROPERTY, AXP_WIDGET_PROPERTY_GROUP, AXP_default_Border_Box_Units, AXP_default_Border_Box_Value, AXP_default_Spacing_Box_Units, AXP_default_Spacing_Box_Value, DEFAULT_STRATEGY_CONFIG, STRATEGY_CONFIG_TOKEN, booleanDefaultProperty, findNonEmptyBreakpoints, largeTextDefaultProperty, numberDefaultProperty, numberMaxValueProperty, numberMinValueProperty, plainTextDefaultProperty };
19442
15702
  //# sourceMappingURL=acorex-platform-widgets.mjs.map