@dragonworks/ngx-dashboard-widgets 20.0.5 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, signal, computed, Component, input, numberAttribute, booleanAttribute, ElementRef, NgZone, PLATFORM_ID, DestroyRef, Directive, ChangeDetectionStrategy, Renderer2, viewChild, effect } from '@angular/core';
2
+ import { inject, signal, computed, Component, input, numberAttribute, booleanAttribute, ElementRef, NgZone, PLATFORM_ID, DestroyRef, Directive, ChangeDetectionStrategy, Renderer2, viewChild, effect, LOCALE_ID, afterNextRender } from '@angular/core';
3
3
  import { DomSanitizer } from '@angular/platform-browser';
4
4
  import * as i2 from '@angular/material/dialog';
5
5
  import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule, MatDialog } from '@angular/material/dialog';
@@ -20,18 +20,20 @@ import * as i5$1 from '@angular/material/input';
20
20
  import { MatInputModule } from '@angular/material/input';
21
21
  import * as i3$1 from '@angular/material/radio';
22
22
  import { MatRadioModule } from '@angular/material/radio';
23
+ import { from, map, of } from 'rxjs';
24
+ import { toSignal } from '@angular/core/rxjs-interop';
23
25
 
24
26
  // arrow-widget.metadata.ts
25
- const svgIcon$2 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M320-120v-320H120l360-440 360 440H640v320H320Zm80-80h160v-320h111L480-754 289-520h111v320Zm80-320Z"/></svg>';
27
+ const svgIcon$3 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M320-120v-320H120l360-440 360 440H640v320H320Zm80-80h160v-320h111L480-754 289-520h111v320Zm80-320Z"/></svg>';
26
28
 
27
29
  class ArrowStateDialogComponent {
28
30
  data = inject(MAT_DIALOG_DATA);
29
31
  dialogRef = inject((MatDialogRef));
30
32
  // State signals
31
- direction = signal(this.data.direction);
32
- opacity = signal(this.data.opacity ?? 1);
33
- hasBackground = signal(this.data.hasBackground ?? true);
34
- transparentBackground = signal(!(this.data.hasBackground ?? true));
33
+ direction = signal(this.data.direction, ...(ngDevMode ? [{ debugName: "direction" }] : []));
34
+ opacity = signal(this.data.opacity ?? 1, ...(ngDevMode ? [{ debugName: "opacity" }] : []));
35
+ hasBackground = signal(this.data.hasBackground ?? true, ...(ngDevMode ? [{ debugName: "hasBackground" }] : []));
36
+ transparentBackground = signal(!(this.data.hasBackground ?? true), ...(ngDevMode ? [{ debugName: "transparentBackground" }] : []));
35
37
  // Store original values for comparison
36
38
  originalDirection = this.data.direction;
37
39
  originalOpacity = this.data.opacity ?? 1;
@@ -45,8 +47,8 @@ class ArrowStateDialogComponent {
45
47
  left: 270,
46
48
  };
47
49
  return rotationMap[this.direction()];
48
- });
49
- rotationTransform = computed(() => `rotate(${this.rotation()}deg)`);
50
+ }, ...(ngDevMode ? [{ debugName: "rotation" }] : []));
51
+ rotationTransform = computed(() => `rotate(${this.rotation()}deg)`, ...(ngDevMode ? [{ debugName: "rotationTransform" }] : []));
50
52
  directionName = computed(() => {
51
53
  const nameMap = {
52
54
  up: 'Up',
@@ -55,10 +57,10 @@ class ArrowStateDialogComponent {
55
57
  left: 'Left',
56
58
  };
57
59
  return nameMap[this.direction()];
58
- });
60
+ }, ...(ngDevMode ? [{ debugName: "directionName" }] : []));
59
61
  hasChanged = computed(() => this.direction() !== this.originalDirection ||
60
62
  this.opacity() !== this.originalOpacity ||
61
- this.hasBackground() !== this.originalHasBackground);
63
+ this.hasBackground() !== this.originalHasBackground, ...(ngDevMode ? [{ debugName: "hasChanged" }] : []));
62
64
  formatOpacity(value) {
63
65
  return Math.round(value * 100);
64
66
  }
@@ -76,8 +78,8 @@ class ArrowStateDialogComponent {
76
78
  hasBackground: this.hasBackground(),
77
79
  });
78
80
  }
79
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ArrowStateDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
80
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: ArrowStateDialogComponent, isStandalone: true, selector: "lib-arrow-state-dialog", ngImport: i0, template: `
81
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ArrowStateDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
82
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.2.1", type: ArrowStateDialogComponent, isStandalone: true, selector: "lib-arrow-state-dialog", ngImport: i0, template: `
81
83
  <h2 mat-dialog-title>Arrow Settings</h2>
82
84
  <mat-dialog-content>
83
85
  <!-- Direction Selection -->
@@ -121,7 +123,7 @@ class ArrowStateDialogComponent {
121
123
  </mat-dialog-actions>
122
124
  `, isInline: true, styles: ["mat-dialog-content{display:block;overflow-y:auto;overflow-x:hidden}mat-form-field{width:100%;display:block;margin-bottom:1rem}.direction-field{margin-top:1rem}.slider-field{margin-bottom:1.5rem;margin-right:1rem}.field-label{display:block;margin-bottom:.5rem}mat-slider{width:100%;display:block}.toggle-field{display:flex;align-items:center;gap:.75rem;margin-bottom:.5rem}.toggle-hint{margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSliderModule }, { kind: "component", type: i6.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i6.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] });
123
125
  }
124
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ArrowStateDialogComponent, decorators: [{
126
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ArrowStateDialogComponent, decorators: [{
125
127
  type: Component,
126
128
  args: [{ selector: 'lib-arrow-state-dialog', standalone: true, imports: [
127
129
  CommonModule,
@@ -183,16 +185,16 @@ class ArrowWidgetComponent {
183
185
  widgetTypeid: '@default/arrow-widget',
184
186
  name: 'Arrow',
185
187
  description: 'A generic arrow',
186
- svgIcon: svgIcon$2,
188
+ svgIcon: svgIcon$3,
187
189
  };
188
190
  #sanitizer = inject(DomSanitizer);
189
191
  #dialog = inject(MatDialog);
190
- safeSvgIcon = this.#sanitizer.bypassSecurityTrustHtml(svgIcon$2);
192
+ safeSvgIcon = this.#sanitizer.bypassSecurityTrustHtml(svgIcon$3);
191
193
  state = signal({
192
194
  direction: 'up',
193
195
  opacity: 0.3,
194
196
  hasBackground: true,
195
- });
197
+ }, ...(ngDevMode ? [{ debugName: "state" }] : []));
196
198
  // Computed rotation
197
199
  rotationAngle = computed(() => {
198
200
  const rotationMap = {
@@ -202,7 +204,7 @@ class ArrowWidgetComponent {
202
204
  left: 270,
203
205
  };
204
206
  return rotationMap[this.state().direction];
205
- });
207
+ }, ...(ngDevMode ? [{ debugName: "rotationAngle" }] : []));
206
208
  dashboardSetState(state) {
207
209
  if (state) {
208
210
  this.state.update((current) => ({
@@ -228,32 +230,32 @@ class ArrowWidgetComponent {
228
230
  }
229
231
  });
230
232
  }
231
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ArrowWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
232
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: ArrowWidgetComponent, isStandalone: true, selector: "ngx-dashboard-arrow-widget", ngImport: i0, template: "<!-- arrow-widget.component.html -->\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div\r\n class=\"svg-placeholder\"\r\n [innerHTML]=\"safeSvgIcon\"\r\n [style.transform]=\"'rotate(' + rotationAngle() + 'deg)'\"\r\n [style.opacity]=\"state().opacity\"\r\n ></div>\r\n</div>\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.svg-wrapper.has-background{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease;transform-origin:center center}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block;fill:var(--mat-sys-on-surface-variant, #6c757d);transition:fill .2s ease}.has-background .svg-placeholder ::ng-deep svg{fill:var(--mat-sys-on-surface, #1f1f1f)}.svg-wrapper:hover .svg-placeholder ::ng-deep svg{fill:var(--mat-sys-primary, #6750a4)}\n"] });
233
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ArrowWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
234
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.2.1", type: ArrowWidgetComponent, isStandalone: true, selector: "ngx-dashboard-arrow-widget", ngImport: i0, template: "<!-- arrow-widget.component.html -->\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div\r\n class=\"svg-placeholder\"\r\n [innerHTML]=\"safeSvgIcon\"\r\n [style.transform]=\"'rotate(' + rotationAngle() + 'deg)'\"\r\n [style.opacity]=\"state().opacity\"\r\n ></div>\r\n</div>\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.svg-wrapper.has-background{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease,color .2s ease;transform-origin:center center;color:var(--mat-sys-on-surface-variant, #6c757d)}.has-background .svg-placeholder{color:var(--mat-sys-on-surface, #1f1f1f)}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block}.svg-wrapper:hover .svg-placeholder{color:var(--mat-sys-primary, #6750a4)}\n"] });
233
235
  }
234
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ArrowWidgetComponent, decorators: [{
236
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ArrowWidgetComponent, decorators: [{
235
237
  type: Component,
236
- args: [{ selector: 'ngx-dashboard-arrow-widget', imports: [], template: "<!-- arrow-widget.component.html -->\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div\r\n class=\"svg-placeholder\"\r\n [innerHTML]=\"safeSvgIcon\"\r\n [style.transform]=\"'rotate(' + rotationAngle() + 'deg)'\"\r\n [style.opacity]=\"state().opacity\"\r\n ></div>\r\n</div>\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.svg-wrapper.has-background{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease;transform-origin:center center}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block;fill:var(--mat-sys-on-surface-variant, #6c757d);transition:fill .2s ease}.has-background .svg-placeholder ::ng-deep svg{fill:var(--mat-sys-on-surface, #1f1f1f)}.svg-wrapper:hover .svg-placeholder ::ng-deep svg{fill:var(--mat-sys-primary, #6750a4)}\n"] }]
238
+ args: [{ selector: 'ngx-dashboard-arrow-widget', imports: [], template: "<!-- arrow-widget.component.html -->\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div\r\n class=\"svg-placeholder\"\r\n [innerHTML]=\"safeSvgIcon\"\r\n [style.transform]=\"'rotate(' + rotationAngle() + 'deg)'\"\r\n [style.opacity]=\"state().opacity\"\r\n ></div>\r\n</div>\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.svg-wrapper.has-background{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease,color .2s ease;transform-origin:center center;color:var(--mat-sys-on-surface-variant, #6c757d)}.has-background .svg-placeholder{color:var(--mat-sys-on-surface, #1f1f1f)}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block}.svg-wrapper:hover .svg-placeholder{color:var(--mat-sys-primary, #6750a4)}\n"] }]
237
239
  }] });
238
240
 
239
241
  // label-widget.metadata.ts
240
- const svgIcon$1 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M280-280h280v-80H280v80Zm0-160h400v-80H280v80Zm0-160h400v-80H280v80Zm-80 480q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z"/></svg>';
242
+ const svgIcon$2 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M280-280h280v-80H280v80Zm0-160h400v-80H280v80Zm0-160h400v-80H280v80Zm-80 480q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z"/></svg>';
241
243
 
242
244
  class LabelStateDialogComponent {
243
245
  data = inject(MAT_DIALOG_DATA);
244
246
  dialogRef = inject((MatDialogRef));
245
247
  // State signals
246
- label = signal(this.data.label ?? '');
247
- fontSize = signal(this.data.fontSize ?? 16);
248
- alignment = signal(this.data.alignment ?? 'center');
249
- fontWeight = signal(this.data.fontWeight ?? 'normal');
250
- opacity = signal(this.data.opacity ?? 1);
251
- hasBackground = signal(this.data.hasBackground ?? true);
252
- transparentBackground = signal(!(this.data.hasBackground ?? true));
253
- responsive = signal(this.data.responsive ?? false);
248
+ label = signal(this.data.label ?? '', ...(ngDevMode ? [{ debugName: "label" }] : []));
249
+ fontSize = signal(this.data.fontSize ?? 16, ...(ngDevMode ? [{ debugName: "fontSize" }] : []));
250
+ alignment = signal(this.data.alignment ?? 'center', ...(ngDevMode ? [{ debugName: "alignment" }] : []));
251
+ fontWeight = signal(this.data.fontWeight ?? 'normal', ...(ngDevMode ? [{ debugName: "fontWeight" }] : []));
252
+ opacity = signal(this.data.opacity ?? 1, ...(ngDevMode ? [{ debugName: "opacity" }] : []));
253
+ hasBackground = signal(this.data.hasBackground ?? true, ...(ngDevMode ? [{ debugName: "hasBackground" }] : []));
254
+ transparentBackground = signal(!(this.data.hasBackground ?? true), ...(ngDevMode ? [{ debugName: "transparentBackground" }] : []));
255
+ responsive = signal(this.data.responsive ?? false, ...(ngDevMode ? [{ debugName: "responsive" }] : []));
254
256
  // Responsive font size constraints
255
- minFontSize = signal(this.data.minFontSize ?? 8);
256
- maxFontSize = signal(this.data.maxFontSize ?? 64);
257
+ minFontSize = signal(this.data.minFontSize ?? 8, ...(ngDevMode ? [{ debugName: "minFontSize" }] : []));
258
+ maxFontSize = signal(this.data.maxFontSize ?? 64, ...(ngDevMode ? [{ debugName: "maxFontSize" }] : []));
257
259
  // Store original values for comparison
258
260
  originalLabel = this.data.label ?? '';
259
261
  originalFontSize = this.data.fontSize ?? 16;
@@ -268,15 +270,15 @@ class LabelStateDialogComponent {
268
270
  isMinFontSizeValid = computed(() => {
269
271
  const min = this.minFontSize();
270
272
  return min >= 8 && min <= 24;
271
- });
273
+ }, ...(ngDevMode ? [{ debugName: "isMinFontSizeValid" }] : []));
272
274
  isMaxFontSizeValid = computed(() => {
273
275
  const max = this.maxFontSize();
274
276
  return max >= 16 && max <= 128;
275
- });
276
- isFontSizeRangeValid = computed(() => this.minFontSize() < this.maxFontSize());
277
+ }, ...(ngDevMode ? [{ debugName: "isMaxFontSizeValid" }] : []));
278
+ isFontSizeRangeValid = computed(() => this.minFontSize() < this.maxFontSize(), ...(ngDevMode ? [{ debugName: "isFontSizeRangeValid" }] : []));
277
279
  isFormValid = computed(() => this.isMinFontSizeValid() &&
278
280
  this.isMaxFontSizeValid() &&
279
- this.isFontSizeRangeValid());
281
+ this.isFontSizeRangeValid(), ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
280
282
  // Computed values
281
283
  hasChanged = computed(() => this.label() !== this.originalLabel ||
282
284
  this.fontSize() !== this.originalFontSize ||
@@ -286,7 +288,7 @@ class LabelStateDialogComponent {
286
288
  this.hasBackground() !== this.originalHasBackground ||
287
289
  this.responsive() !== this.originalResponsive ||
288
290
  this.minFontSize() !== this.originalMinFontSize ||
289
- this.maxFontSize() !== this.originalMaxFontSize);
291
+ this.maxFontSize() !== this.originalMaxFontSize, ...(ngDevMode ? [{ debugName: "hasChanged" }] : []));
290
292
  formatOpacity(value) {
291
293
  return Math.round(value * 100);
292
294
  }
@@ -334,8 +336,8 @@ class LabelStateDialogComponent {
334
336
  maxFontSize: this.maxFontSize(),
335
337
  });
336
338
  }
337
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LabelStateDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
338
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: LabelStateDialogComponent, isStandalone: true, selector: "lib-label-state-dialog", ngImport: i0, template: `
339
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: LabelStateDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
340
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: LabelStateDialogComponent, isStandalone: true, selector: "lib-label-state-dialog", ngImport: i0, template: `
339
341
  <h2 mat-dialog-title>Label Settings</h2>
340
342
  <mat-dialog-content>
341
343
  <mat-form-field appearance="outline" class="label-text-field">
@@ -487,7 +489,7 @@ class LabelStateDialogComponent {
487
489
  </mat-dialog-actions>
488
490
  `, isInline: true, styles: ["mat-dialog-content{display:block;overflow-y:auto;overflow-x:hidden}mat-form-field{width:100%;display:block;margin-bottom:1rem}.label-text-field{margin-top:1rem}.row-layout{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin-bottom:1rem}.row-layout mat-form-field{margin-bottom:0}.slider-section{margin-bottom:1.5rem;margin-right:1rem}.slider-label{display:block;margin-bottom:.5rem}mat-slider{width:100%;display:block}.toggle-section{display:flex;align-items:center;gap:.75rem;margin-bottom:1rem}.toggle-description{margin:0}.responsive-section{margin-bottom:1.5rem;padding:1rem;border-radius:12px;background-color:var(--mat-app-surface-variant, rgba(var(--mat-app-on-surface-rgb, 0, 0, 0), .05));border:1px solid var(--mat-app-outline-variant, rgba(var(--mat-app-on-surface-rgb, 0, 0, 0), .12))}.section-label{display:block;margin-bottom:.75rem;font-weight:500;color:var(--mat-app-on-surface-variant, rgba(var(--mat-app-on-surface-rgb, 0, 0, 0), .6))}.responsive-section .row-layout{margin-bottom:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSliderModule }, { kind: "component", type: i6.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i6.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] });
489
491
  }
490
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LabelStateDialogComponent, decorators: [{
492
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: LabelStateDialogComponent, decorators: [{
491
493
  type: Component,
492
494
  args: [{ selector: 'lib-label-state-dialog', standalone: true, imports: [
493
495
  CommonModule,
@@ -664,18 +666,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
664
666
  class ResponsiveTextDirective {
665
667
  /* ───────────────────────── Inputs with transforms ─────────────── */
666
668
  /** Minimum font-size in pixels (accessibility floor) */
667
- minFontSize = input(8, { transform: numberAttribute });
669
+ minFontSize = input(8, ...(ngDevMode ? [{ debugName: "minFontSize", transform: numberAttribute }] : [{ transform: numberAttribute }]));
668
670
  /** Maximum font-size in pixels (layout ceiling) */
669
- maxFontSize = input(512, { transform: numberAttribute });
671
+ maxFontSize = input(512, ...(ngDevMode ? [{ debugName: "maxFontSize", transform: numberAttribute }] : [{ transform: numberAttribute }]));
670
672
  /**
671
673
  * Line-height: pass a multiplier (e.g. 1.1) or absolute px value.
672
674
  * For single-line text a multiplier < 10 is treated as unitless.
673
675
  */
674
- lineHeight = input(1.1, { transform: numberAttribute });
676
+ lineHeight = input(1.1, ...(ngDevMode ? [{ debugName: "lineHeight", transform: numberAttribute }] : [{ transform: numberAttribute }]));
675
677
  /** Whether to observe text mutations after first render */
676
- observeMutations = input(true, { transform: booleanAttribute });
678
+ observeMutations = input(true, ...(ngDevMode ? [{ debugName: "observeMutations", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
677
679
  /** Debounce delay in ms for resize/mutation callbacks */
678
- debounceMs = input(16, { transform: numberAttribute });
680
+ debounceMs = input(16, ...(ngDevMode ? [{ debugName: "debounceMs", transform: numberAttribute }] : [{ transform: numberAttribute }]));
679
681
  /* ───────────────────────── Private state ───────────────────────── */
680
682
  el = inject(ElementRef);
681
683
  zone = inject(NgZone);
@@ -701,7 +703,12 @@ class ResponsiveTextDirective {
701
703
  lastMaxW = 0;
702
704
  lastMaxH = 0;
703
705
  lastFontSize = 0;
704
- /* ───────────────────────── Lifecycle ──────────────────────────── */
706
+ constructor() {
707
+ // Set up cleanup on component destruction using modern DestroyRef
708
+ this.destroyRef.onDestroy(() => {
709
+ this.cleanup();
710
+ });
711
+ }
705
712
  ngAfterViewInit() {
706
713
  if (!isPlatformBrowser(this.platformId))
707
714
  return;
@@ -717,9 +724,6 @@ class ResponsiveTextDirective {
717
724
  }
718
725
  });
719
726
  }
720
- ngOnDestroy() {
721
- this.cleanup();
722
- }
723
727
  /* ───────────────────── Core fitting logic ───────────────────── */
724
728
  /**
725
729
  * Debounced fit handler to prevent excessive recalculations
@@ -896,13 +900,13 @@ class ResponsiveTextDirective {
896
900
  // Clear canvas context
897
901
  this._ctx = undefined;
898
902
  }
899
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ResponsiveTextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
900
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.6", type: ResponsiveTextDirective, isStandalone: true, selector: "[responsiveText]", inputs: { minFontSize: { classPropertyName: "minFontSize", publicName: "minFontSize", isSignal: true, isRequired: false, transformFunction: null }, maxFontSize: { classPropertyName: "maxFontSize", publicName: "maxFontSize", isSignal: true, isRequired: false, transformFunction: null }, lineHeight: { classPropertyName: "lineHeight", publicName: "lineHeight", isSignal: true, isRequired: false, transformFunction: null }, observeMutations: { classPropertyName: "observeMutations", publicName: "observeMutations", isSignal: true, isRequired: false, transformFunction: null }, debounceMs: { classPropertyName: "debounceMs", publicName: "debounceMs", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.display": "\"block\"", "style.width": "\"100%\"", "style.white-space": "\"nowrap\"", "style.overflow": "\"visible\"" } }, ngImport: i0 });
903
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ResponsiveTextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
904
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.1", type: ResponsiveTextDirective, isStandalone: true, selector: "[libResponsiveText]", inputs: { minFontSize: { classPropertyName: "minFontSize", publicName: "minFontSize", isSignal: true, isRequired: false, transformFunction: null }, maxFontSize: { classPropertyName: "maxFontSize", publicName: "maxFontSize", isSignal: true, isRequired: false, transformFunction: null }, lineHeight: { classPropertyName: "lineHeight", publicName: "lineHeight", isSignal: true, isRequired: false, transformFunction: null }, observeMutations: { classPropertyName: "observeMutations", publicName: "observeMutations", isSignal: true, isRequired: false, transformFunction: null }, debounceMs: { classPropertyName: "debounceMs", publicName: "debounceMs", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.display": "\"block\"", "style.width": "\"100%\"", "style.white-space": "\"nowrap\"", "style.overflow": "\"visible\"" } }, ngImport: i0 });
901
905
  }
902
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ResponsiveTextDirective, decorators: [{
906
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ResponsiveTextDirective, decorators: [{
903
907
  type: Directive,
904
908
  args: [{
905
- selector: '[responsiveText]',
909
+ selector: '[libResponsiveText]',
906
910
  standalone: true,
907
911
  host: {
908
912
  '[style.display]': '"block"',
@@ -911,7 +915,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
911
915
  '[style.overflow]': '"visible"',
912
916
  },
913
917
  }]
914
- }] });
918
+ }], ctorParameters: () => [] });
915
919
 
916
920
  // label-widget.component.ts
917
921
  class LabelWidgetComponent {
@@ -919,11 +923,11 @@ class LabelWidgetComponent {
919
923
  widgetTypeid: '@default/label-widget',
920
924
  name: 'Label',
921
925
  description: 'A generic text label',
922
- svgIcon: svgIcon$1,
926
+ svgIcon: svgIcon$2,
923
927
  };
924
928
  #sanitizer = inject(DomSanitizer);
925
929
  #dialog = inject(MatDialog);
926
- safeSvgIcon = this.#sanitizer.bypassSecurityTrustHtml(svgIcon$1);
930
+ safeSvgIcon = this.#sanitizer.bypassSecurityTrustHtml(svgIcon$2);
927
931
  state = signal({
928
932
  label: '',
929
933
  fontSize: 16,
@@ -934,7 +938,7 @@ class LabelWidgetComponent {
934
938
  responsive: false,
935
939
  minFontSize: 8, // Accessible minimum for responsive text
936
940
  maxFontSize: 64, // Practical maximum for widget display
937
- });
941
+ }, ...(ngDevMode ? [{ debugName: "state" }] : []));
938
942
  dashboardSetState(state) {
939
943
  if (state) {
940
944
  this.state.update((current) => ({
@@ -969,17 +973,17 @@ class LabelWidgetComponent {
969
973
  return this.state().label?.trim();
970
974
  }
971
975
  // Computed properties for responsive font size limits with fallbacks
972
- minFontSize = computed(() => this.state().minFontSize ?? 8);
973
- maxFontSize = computed(() => this.state().maxFontSize ?? 64);
974
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LabelWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
975
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: LabelWidgetComponent, isStandalone: true, selector: "ngx-dashboard-label-widget", ngImport: i0, template: "@if (hasContent) {\r\n<div\r\n class=\"label-widget\"\r\n [style.fontSize.rem]=\"state().responsive ? null : state().fontSize! / 16\"\r\n [style.--widget-opacity]=\"state().opacity\"\r\n [class.text-left]=\"state().alignment === 'left'\"\r\n [class.text-right]=\"state().alignment === 'right'\"\r\n [class.font-bold]=\"state().fontWeight === 'bold'\"\r\n [class.has-background]=\"state().hasBackground\"\r\n>\r\n @if (state().responsive) {\r\n <div class=\"label-text\" responsiveText [minFontSize]=\"minFontSize()\" [maxFontSize]=\"maxFontSize()\">{{ label }}</div>\r\n } @else {\r\n <div class=\"label-text\">{{ label }}</div>\r\n }\r\n</div>\r\n} @else {\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n</div>\r\n}\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper,.label-widget{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.has-background.svg-wrapper,.has-background.label-widget{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.label-widget{overflow:hidden;container-type:size;padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d);opacity:var(--widget-opacity, 1)}.label-widget.text-left{justify-content:flex-start}.label-widget.text-right{justify-content:flex-end}.label-widget.has-background{color:var(--mat-sys-on-surface, #1f1f1f)}.label-widget:hover{opacity:.3;color:var(--mat-sys-primary, #6750a4)}.label-text{width:100%;text-align:center;overflow-wrap:break-word;transition:color .2s ease}.text-left .label-text{text-align:left}.text-right .label-text{text-align:right}.font-bold .label-text{font-weight:700}.label-text[responsiveText]{overflow-wrap:normal}.svg-wrapper{overflow:hidden}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease;transform-origin:center center}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block;fill:var(--mat-sys-on-surface-variant, #6c757d);transition:fill .2s ease}.has-background .svg-placeholder ::ng-deep svg{fill:var(--mat-sys-on-surface, #1f1f1f)}.svg-wrapper:hover .svg-placeholder ::ng-deep svg{fill:var(--mat-sys-primary, #6750a4)}\n"], dependencies: [{ kind: "directive", type: ResponsiveTextDirective, selector: "[responsiveText]", inputs: ["minFontSize", "maxFontSize", "lineHeight", "observeMutations", "debounceMs"] }] });
976
+ minFontSize = computed(() => this.state().minFontSize ?? 8, ...(ngDevMode ? [{ debugName: "minFontSize" }] : []));
977
+ maxFontSize = computed(() => this.state().maxFontSize ?? 64, ...(ngDevMode ? [{ debugName: "maxFontSize" }] : []));
978
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: LabelWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
979
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: LabelWidgetComponent, isStandalone: true, selector: "ngx-dashboard-label-widget", ngImport: i0, template: "@if (hasContent) {\r\n<div\r\n class=\"label-widget\"\r\n [style.fontSize.rem]=\"state().responsive ? null : state().fontSize! / 16\"\r\n [style.--widget-opacity]=\"state().opacity\"\r\n [class.text-left]=\"state().alignment === 'left'\"\r\n [class.text-right]=\"state().alignment === 'right'\"\r\n [class.font-bold]=\"state().fontWeight === 'bold'\"\r\n [class.has-background]=\"state().hasBackground\"\r\n>\r\n @if (state().responsive) {\r\n <div class=\"label-text\" libResponsiveText [minFontSize]=\"minFontSize()\" [maxFontSize]=\"maxFontSize()\">{{ label }}</div>\r\n } @else {\r\n <div class=\"label-text\">{{ label }}</div>\r\n }\r\n</div>\r\n} @else {\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n</div>\r\n}\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper,.label-widget{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.has-background.svg-wrapper,.has-background.label-widget{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.label-widget{overflow:hidden;container-type:size;padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d);opacity:var(--widget-opacity, 1)}.label-widget.text-left{justify-content:flex-start}.label-widget.text-right{justify-content:flex-end}.label-widget.has-background{color:var(--mat-sys-on-surface, #1f1f1f)}.label-widget:hover{opacity:.3;color:var(--mat-sys-primary, #6750a4)}.label-text{width:100%;text-align:center;overflow-wrap:break-word;transition:color .2s ease}.text-left .label-text{text-align:left}.text-right .label-text{text-align:right}.font-bold .label-text{font-weight:700}.label-text[responsiveText]{overflow-wrap:normal}.svg-wrapper{overflow:hidden}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease,color .2s ease;transform-origin:center center;color:var(--mat-sys-on-surface-variant, #6c757d)}.has-background .svg-placeholder{color:var(--mat-sys-on-surface, #1f1f1f)}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block}.svg-wrapper:hover .svg-placeholder{color:var(--mat-sys-primary, #6750a4)}\n"], dependencies: [{ kind: "directive", type: ResponsiveTextDirective, selector: "[libResponsiveText]", inputs: ["minFontSize", "maxFontSize", "lineHeight", "observeMutations", "debounceMs"] }] });
976
980
  }
977
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LabelWidgetComponent, decorators: [{
981
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: LabelWidgetComponent, decorators: [{
978
982
  type: Component,
979
- args: [{ selector: 'ngx-dashboard-label-widget', imports: [ResponsiveTextDirective], template: "@if (hasContent) {\r\n<div\r\n class=\"label-widget\"\r\n [style.fontSize.rem]=\"state().responsive ? null : state().fontSize! / 16\"\r\n [style.--widget-opacity]=\"state().opacity\"\r\n [class.text-left]=\"state().alignment === 'left'\"\r\n [class.text-right]=\"state().alignment === 'right'\"\r\n [class.font-bold]=\"state().fontWeight === 'bold'\"\r\n [class.has-background]=\"state().hasBackground\"\r\n>\r\n @if (state().responsive) {\r\n <div class=\"label-text\" responsiveText [minFontSize]=\"minFontSize()\" [maxFontSize]=\"maxFontSize()\">{{ label }}</div>\r\n } @else {\r\n <div class=\"label-text\">{{ label }}</div>\r\n }\r\n</div>\r\n} @else {\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n</div>\r\n}\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper,.label-widget{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.has-background.svg-wrapper,.has-background.label-widget{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.label-widget{overflow:hidden;container-type:size;padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d);opacity:var(--widget-opacity, 1)}.label-widget.text-left{justify-content:flex-start}.label-widget.text-right{justify-content:flex-end}.label-widget.has-background{color:var(--mat-sys-on-surface, #1f1f1f)}.label-widget:hover{opacity:.3;color:var(--mat-sys-primary, #6750a4)}.label-text{width:100%;text-align:center;overflow-wrap:break-word;transition:color .2s ease}.text-left .label-text{text-align:left}.text-right .label-text{text-align:right}.font-bold .label-text{font-weight:700}.label-text[responsiveText]{overflow-wrap:normal}.svg-wrapper{overflow:hidden}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease;transform-origin:center center}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block;fill:var(--mat-sys-on-surface-variant, #6c757d);transition:fill .2s ease}.has-background .svg-placeholder ::ng-deep svg{fill:var(--mat-sys-on-surface, #1f1f1f)}.svg-wrapper:hover .svg-placeholder ::ng-deep svg{fill:var(--mat-sys-primary, #6750a4)}\n"] }]
983
+ args: [{ selector: 'ngx-dashboard-label-widget', imports: [ResponsiveTextDirective], template: "@if (hasContent) {\r\n<div\r\n class=\"label-widget\"\r\n [style.fontSize.rem]=\"state().responsive ? null : state().fontSize! / 16\"\r\n [style.--widget-opacity]=\"state().opacity\"\r\n [class.text-left]=\"state().alignment === 'left'\"\r\n [class.text-right]=\"state().alignment === 'right'\"\r\n [class.font-bold]=\"state().fontWeight === 'bold'\"\r\n [class.has-background]=\"state().hasBackground\"\r\n>\r\n @if (state().responsive) {\r\n <div class=\"label-text\" libResponsiveText [minFontSize]=\"minFontSize()\" [maxFontSize]=\"maxFontSize()\">{{ label }}</div>\r\n } @else {\r\n <div class=\"label-text\">{{ label }}</div>\r\n }\r\n</div>\r\n} @else {\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n</div>\r\n}\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper,.label-widget{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.has-background.svg-wrapper,.has-background.label-widget{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.label-widget{overflow:hidden;container-type:size;padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d);opacity:var(--widget-opacity, 1)}.label-widget.text-left{justify-content:flex-start}.label-widget.text-right{justify-content:flex-end}.label-widget.has-background{color:var(--mat-sys-on-surface, #1f1f1f)}.label-widget:hover{opacity:.3;color:var(--mat-sys-primary, #6750a4)}.label-text{width:100%;text-align:center;overflow-wrap:break-word;transition:color .2s ease}.text-left .label-text{text-align:left}.text-right .label-text{text-align:right}.font-bold .label-text{font-weight:700}.label-text[responsiveText]{overflow-wrap:normal}.svg-wrapper{overflow:hidden}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease,color .2s ease;transform-origin:center center;color:var(--mat-sys-on-surface-variant, #6c757d)}.has-background .svg-placeholder{color:var(--mat-sys-on-surface, #1f1f1f)}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block}.svg-wrapper:hover .svg-placeholder{color:var(--mat-sys-primary, #6750a4)}\n"] }]
980
984
  }] });
981
985
 
982
- const svgIcon = `
986
+ const svgIcon$1 = `
983
987
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" preserveAspectRatio="xMidYMid meet">
984
988
  <use transform="matrix(-1,0,0,1,800,0)" href="#one-half" />
985
989
  <g id="one-half">
@@ -1010,12 +1014,14 @@ const svgIcon = `
1010
1014
  <path
1011
1015
  class="clock-hour-hand"
1012
1016
  id="anim-clock-hour-hand"
1017
+ fill="currentColor"
1013
1018
  d="m 381.925,476 h 36.15 l 5e-4,-300.03008 L 400,156.25 381.9245,175.96992 Z"
1014
1019
  transform="rotate(110.2650694444, 400, 400)"
1015
1020
  />
1016
1021
  <path
1017
1022
  class="clock-minute-hand"
1018
1023
  id="anim-clock-minute-hand"
1024
+ fill="currentColor"
1019
1025
  d="M 412.063,496.87456 H 387.937 L 385.249,65.68306 400,52.75 414.751,65.68306 Z"
1020
1026
  transform="rotate(243.1808333333, 400, 400)"
1021
1027
  />
@@ -1026,10 +1032,10 @@ class ClockStateDialogComponent {
1026
1032
  data = inject(MAT_DIALOG_DATA);
1027
1033
  dialogRef = inject((MatDialogRef));
1028
1034
  // State signals
1029
- mode = signal(this.data.mode ?? 'digital');
1030
- hasBackground = signal(this.data.hasBackground ?? true);
1031
- timeFormat = signal(this.data.timeFormat ?? '24h');
1032
- showSeconds = signal(this.data.showSeconds ?? true);
1035
+ mode = signal(this.data.mode ?? 'digital', ...(ngDevMode ? [{ debugName: "mode" }] : []));
1036
+ hasBackground = signal(this.data.hasBackground ?? true, ...(ngDevMode ? [{ debugName: "hasBackground" }] : []));
1037
+ timeFormat = signal(this.data.timeFormat ?? '24h', ...(ngDevMode ? [{ debugName: "timeFormat" }] : []));
1038
+ showSeconds = signal(this.data.showSeconds ?? true, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
1033
1039
  // Store original values for comparison
1034
1040
  originalMode = this.data.mode ?? 'digital';
1035
1041
  originalHasBackground = this.data.hasBackground ?? true;
@@ -1039,7 +1045,7 @@ class ClockStateDialogComponent {
1039
1045
  hasChanged = computed(() => this.mode() !== this.originalMode ||
1040
1046
  this.hasBackground() !== this.originalHasBackground ||
1041
1047
  this.timeFormat() !== this.originalTimeFormat ||
1042
- this.showSeconds() !== this.originalShowSeconds);
1048
+ this.showSeconds() !== this.originalShowSeconds, ...(ngDevMode ? [{ debugName: "hasChanged" }] : []));
1043
1049
  onCancel() {
1044
1050
  this.dialogRef.close();
1045
1051
  }
@@ -1051,13 +1057,14 @@ class ClockStateDialogComponent {
1051
1057
  showSeconds: this.showSeconds(),
1052
1058
  });
1053
1059
  }
1054
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ClockStateDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1055
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: ClockStateDialogComponent, isStandalone: true, selector: "demo-clock-state-dialog", ngImport: i0, template: `
1060
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ClockStateDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1061
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: ClockStateDialogComponent, isStandalone: true, selector: "lib-clock-state-dialog", ngImport: i0, template: `
1056
1062
  <h2 mat-dialog-title>Clock Settings</h2>
1057
1063
  <mat-dialog-content>
1058
1064
  <div class="mode-selection">
1059
- <label class="section-label">Display Mode</label>
1065
+ <label class="section-label" for="mode-selection-group">Display Mode</label>
1060
1066
  <mat-radio-group
1067
+ id="mode-selection-group"
1061
1068
  [value]="mode()"
1062
1069
  (change)="mode.set($any($event.value))"
1063
1070
  >
@@ -1069,8 +1076,9 @@ class ClockStateDialogComponent {
1069
1076
  <!-- Time Format (only for digital mode) -->
1070
1077
  @if (mode() === 'digital') {
1071
1078
  <div class="format-selection">
1072
- <label class="section-label">Time Format</label>
1079
+ <label class="section-label" for="time-format-group">Time Format</label>
1073
1080
  <mat-radio-group
1081
+ id="time-format-group"
1074
1082
  [value]="timeFormat()"
1075
1083
  (change)="timeFormat.set($any($event.value))"
1076
1084
  >
@@ -1117,9 +1125,9 @@ class ClockStateDialogComponent {
1117
1125
  </mat-dialog-actions>
1118
1126
  `, isInline: true, styles: ["mat-dialog-content{display:block;overflow-y:auto;overflow-x:hidden}.mode-selection,.format-selection{margin-top:1rem;margin-bottom:2rem}.section-label{display:block;margin-bottom:.75rem;font-weight:500}mat-radio-group{display:flex;flex-direction:column;gap:.75rem}mat-radio-button{margin:0}.toggle-section{display:flex;align-items:center;gap:.75rem;margin-bottom:.5rem}.toggle-description{margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i3$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i3$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] });
1119
1127
  }
1120
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ClockStateDialogComponent, decorators: [{
1128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ClockStateDialogComponent, decorators: [{
1121
1129
  type: Component,
1122
- args: [{ selector: 'demo-clock-state-dialog', standalone: true, imports: [
1130
+ args: [{ selector: 'lib-clock-state-dialog', standalone: true, imports: [
1123
1131
  CommonModule,
1124
1132
  FormsModule,
1125
1133
  MatDialogModule,
@@ -1130,8 +1138,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1130
1138
  <h2 mat-dialog-title>Clock Settings</h2>
1131
1139
  <mat-dialog-content>
1132
1140
  <div class="mode-selection">
1133
- <label class="section-label">Display Mode</label>
1141
+ <label class="section-label" for="mode-selection-group">Display Mode</label>
1134
1142
  <mat-radio-group
1143
+ id="mode-selection-group"
1135
1144
  [value]="mode()"
1136
1145
  (change)="mode.set($any($event.value))"
1137
1146
  >
@@ -1143,8 +1152,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1143
1152
  <!-- Time Format (only for digital mode) -->
1144
1153
  @if (mode() === 'digital') {
1145
1154
  <div class="format-selection">
1146
- <label class="section-label">Time Format</label>
1155
+ <label class="section-label" for="time-format-group">Time Format</label>
1147
1156
  <mat-radio-group
1157
+ id="time-format-group"
1148
1158
  [value]="timeFormat()"
1149
1159
  (change)="timeFormat.set($any($event.value))"
1150
1160
  >
@@ -1195,17 +1205,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1195
1205
  class DigitalClockComponent {
1196
1206
  #destroyRef = inject(DestroyRef);
1197
1207
  // Inputs
1198
- timeFormat = input('24h');
1199
- showSeconds = input(true);
1200
- hasBackground = input(false);
1208
+ timeFormat = input('24h', ...(ngDevMode ? [{ debugName: "timeFormat" }] : []));
1209
+ showSeconds = input(true, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
1210
+ hasBackground = input(false, ...(ngDevMode ? [{ debugName: "hasBackground" }] : []));
1201
1211
  // Time tracking
1202
- currentTime = signal(new Date());
1212
+ currentTime = signal(new Date(), ...(ngDevMode ? [{ debugName: "currentTime" }] : []));
1203
1213
  formattedTime = computed(() => {
1204
1214
  const time = this.currentTime();
1205
1215
  const format = this.timeFormat();
1206
1216
  const showSecs = this.showSeconds();
1207
1217
  return this.#formatTime(time, format, showSecs);
1208
- });
1218
+ }, ...(ngDevMode ? [{ debugName: "formattedTime" }] : []));
1209
1219
  #intervalId = null;
1210
1220
  #formatTime(time, format, showSecs) {
1211
1221
  let hours = time.getHours();
@@ -1255,12 +1265,12 @@ class DigitalClockComponent {
1255
1265
  this.#intervalId = null;
1256
1266
  }
1257
1267
  }
1258
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DigitalClockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1259
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: DigitalClockComponent, isStandalone: true, selector: "ngx-digital-clock", inputs: { timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, hasBackground: { classPropertyName: "hasBackground", publicName: "hasBackground", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.has-background": "hasBackground()", "class.show-pm": "timeFormat() === \"12h\"", "class.show-seconds": "showSeconds()" }, classAttribute: "clock-widget digital" }, ngImport: i0, template: "<div responsiveText class=\"digital-time\">{{ formattedTime() }}</div>\r\n", styles: [":host{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard);padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d)}:host.has-background{background-color:var(--mat-sys-surface-container-high);border-radius:4px;color:var(--mat-sys-on-surface, #1f1f1f)}:host:hover{opacity:.8;color:var(--mat-sys-primary, #6750a4)}.digital-time{font-size:clamp(8px,min(20cqw,50cqh),200px);font-family:monospace;font-weight:500;letter-spacing:.05em;transition:color .2s ease}:host.show-pm.show-seconds .digital-time{font-size:clamp(8px,min(15cqw,50cqh),200px)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1268
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DigitalClockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1269
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.2.1", type: DigitalClockComponent, isStandalone: true, selector: "lib-digital-clock", inputs: { timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, hasBackground: { classPropertyName: "hasBackground", publicName: "hasBackground", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.has-background": "hasBackground()", "class.show-pm": "timeFormat() === \"12h\"", "class.show-seconds": "showSeconds()" }, classAttribute: "clock-widget digital" }, ngImport: i0, template: "<div responsiveText class=\"digital-time\">{{ formattedTime() }}</div>\r\n", styles: [":host{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard);padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d)}:host.has-background{background-color:var(--mat-sys-surface-container-high);border-radius:4px;color:var(--mat-sys-on-surface, #1f1f1f)}:host:hover{opacity:.8;color:var(--mat-sys-primary, #6750a4)}.digital-time{font-size:clamp(8px,min(20cqw,50cqh),200px);font-family:monospace;font-weight:500;letter-spacing:.05em;transition:color .2s ease}:host.show-pm.show-seconds .digital-time{font-size:clamp(8px,min(15cqw,50cqh),200px)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1260
1270
  }
1261
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DigitalClockComponent, decorators: [{
1271
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DigitalClockComponent, decorators: [{
1262
1272
  type: Component,
1263
- args: [{ selector: 'ngx-digital-clock', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
1273
+ args: [{ selector: 'lib-digital-clock', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
1264
1274
  '[class.has-background]': 'hasBackground()',
1265
1275
  '[class.show-pm]': 'timeFormat() === "12h"',
1266
1276
  '[class.show-seconds]': 'showSeconds()',
@@ -1272,32 +1282,32 @@ class AnalogClockComponent {
1272
1282
  #destroyRef = inject(DestroyRef);
1273
1283
  #renderer = inject(Renderer2);
1274
1284
  // Inputs
1275
- hasBackground = input(false);
1276
- showSeconds = input(true);
1285
+ hasBackground = input(false, ...(ngDevMode ? [{ debugName: "hasBackground" }] : []));
1286
+ showSeconds = input(true, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
1277
1287
  // ViewChild references for clock hands
1278
- hourHand = viewChild('hourHand');
1279
- minuteHand = viewChild('minuteHand');
1280
- secondHand = viewChild('secondHand');
1288
+ hourHand = viewChild('hourHand', ...(ngDevMode ? [{ debugName: "hourHand" }] : []));
1289
+ minuteHand = viewChild('minuteHand', ...(ngDevMode ? [{ debugName: "minuteHand" }] : []));
1290
+ secondHand = viewChild('secondHand', ...(ngDevMode ? [{ debugName: "secondHand" }] : []));
1281
1291
  // Time tracking
1282
- currentTime = signal(new Date());
1292
+ currentTime = signal(new Date(), ...(ngDevMode ? [{ debugName: "currentTime" }] : []));
1283
1293
  // Computed rotation signals
1284
1294
  secondHandRotation = computed(() => {
1285
1295
  const seconds = this.currentTime().getSeconds();
1286
1296
  return seconds * 6; // 360° / 60s = 6° per second
1287
- });
1297
+ }, ...(ngDevMode ? [{ debugName: "secondHandRotation" }] : []));
1288
1298
  minuteHandRotation = computed(() => {
1289
1299
  const time = this.currentTime();
1290
1300
  const minutes = time.getMinutes();
1291
1301
  const seconds = time.getSeconds();
1292
1302
  return minutes * 6 + seconds / 10; // Smooth minute hand movement
1293
- });
1303
+ }, ...(ngDevMode ? [{ debugName: "minuteHandRotation" }] : []));
1294
1304
  hourHandRotation = computed(() => {
1295
1305
  const time = this.currentTime();
1296
1306
  const hours = time.getHours() % 12;
1297
1307
  const minutes = time.getMinutes();
1298
1308
  const seconds = time.getSeconds();
1299
1309
  return hours * 30 + minutes / 2 + seconds / 120; // Smooth hour hand movement
1300
- });
1310
+ }, ...(ngDevMode ? [{ debugName: "hourHandRotation" }] : []));
1301
1311
  #intervalId = null;
1302
1312
  constructor() {
1303
1313
  // Set up time update timer
@@ -1343,12 +1353,12 @@ class AnalogClockComponent {
1343
1353
  this.#renderer.setAttribute(secondElement, 'transform', `rotate(${this.secondHandRotation()}, 400, 400)`);
1344
1354
  }
1345
1355
  }
1346
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AnalogClockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1347
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.6", type: AnalogClockComponent, isStandalone: true, selector: "ngx-analog-clock", inputs: { hasBackground: { classPropertyName: "hasBackground", publicName: "hasBackground", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.has-background": "hasBackground()", "class.show-seconds": "showSeconds()" }, classAttribute: "clock-widget analog" }, viewQueries: [{ propertyName: "hourHand", first: true, predicate: ["hourHand"], descendants: true, isSignal: true }, { propertyName: "minuteHand", first: true, predicate: ["minuteHand"], descendants: true, isSignal: true }, { propertyName: "secondHand", first: true, predicate: ["secondHand"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"analog-clock-container\">\r\n <div class=\"aspect-ratio-box\">\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 800 800\"\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n >\r\n <!-- Optional face circle; uncomment if you want a visible outline by default -->\r\n <!-- <circle cx=\"400\" cy=\"400\" r=\"400\" fill=\"transparent\" stroke=\"currentColor\" stroke-width=\"2\" /> -->\r\n\r\n <use transform=\"matrix(-1,0,0,1,800,0)\" href=\"#one-half\" />\r\n <g id=\"one-half\">\r\n <g id=\"one-fourth\">\r\n <!-- 12 / 3 / 6 / 9 heavy marks -->\r\n <path d=\"m400 40v107\" stroke-width=\"26.7\" stroke=\"currentColor\" />\r\n <g id=\"one-twelfth\">\r\n <!-- 30\u00B0 heavy marks -->\r\n <path\r\n d=\"m580 88.233-42.5 73.612\"\r\n stroke-width=\"26.7\"\r\n stroke=\"currentColor\"\r\n />\r\n <g id=\"one-thirtieth\">\r\n <!-- minute/second ticks -->\r\n <path\r\n id=\"one-sixtieth\"\r\n d=\"m437.63 41.974-3.6585 34.808\"\r\n stroke-width=\"13.6\"\r\n stroke=\"currentColor\"\r\n />\r\n <use transform=\"rotate(6 400 400)\" href=\"#one-sixtieth\" />\r\n </g>\r\n <use transform=\"rotate(12 400 400)\" href=\"#one-thirtieth\" />\r\n </g>\r\n <use transform=\"rotate(30 400 400)\" href=\"#one-twelfth\" />\r\n <use transform=\"rotate(60 400 400)\" href=\"#one-twelfth\" />\r\n </g>\r\n <use transform=\"rotate(90 400 400)\" href=\"#one-fourth\" />\r\n </g>\r\n\r\n <!-- Hands -->\r\n <path\r\n class=\"clock-hour-hand\"\r\n id=\"anim-clock-hour-hand\"\r\n #hourHand\r\n d=\"m 381.925,476 h 36.15 l 5e-4,-300.03008 L 400,156.25 381.9245,175.96992 Z\"\r\n transform=\"rotate(110.2650694444, 400, 400)\"\r\n />\r\n <path\r\n class=\"clock-minute-hand\"\r\n id=\"anim-clock-minute-hand\"\r\n #minuteHand\r\n d=\"M 412.063,496.87456 H 387.937 L 385.249,65.68306 400,52.75 414.751,65.68306 Z\"\r\n transform=\"rotate(243.1808333333, 400, 400)\"\r\n />\r\n <path\r\n class=\"clock-second-hand\"\r\n id=\"anim-clock-second-hand\"\r\n #secondHand\r\n d=\"M 397.317,63.51744 395.91962,168.4 C 374.575,170.5125 358.2,188.365 358.2,210 c 0,21.635 16.3,39 36.61214,41.47594 L 391.52847,498 h 16.94306 L 405.1868,251.47593 C 425.5,249 441.8,231.635 441.8,210 c 2e-5,-21.635 -16.375,-39.4875 -37.71971,-41.6 L 402.683,63.51744 400,60 Z M 400,190.534 c 10.888,0 19.466,8.866 19.466,19.466 0,10.6 -8.578,19.466 -19.466,19.466 -10.888,0 -19.466,-8.866 -19.466,-19.466 0,-10.6 8.578,-19.466 19.466,-19.466 z\"\r\n transform=\"rotate(190.85, 400, 400)\"\r\n />\r\n </svg>\r\n </div>\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%}.analog-clock-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.analog-clock-container .aspect-ratio-box{position:relative;width:100%;max-width:100%;max-height:100%;aspect-ratio:1/1}@supports not (aspect-ratio: 1/1){.analog-clock-container .aspect-ratio-box:before{content:\"\";display:block;padding-bottom:100%}.analog-clock-container .aspect-ratio-box svg{position:absolute;top:0;left:0;width:100%;height:100%}}.analog-clock-container .aspect-ratio-box svg{display:block;width:100%;height:100%}.analog-clock-container .aspect-ratio-box svg path:not(.clock-hour-hand):not(.clock-minute-hand):not(.clock-second-hand){stroke:var(--mat-sys-on-surface, #1d1b20)}.analog-clock-container .aspect-ratio-box svg .clock-hour-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.analog-clock-container .aspect-ratio-box svg .clock-minute-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.analog-clock-container .aspect-ratio-box svg .clock-second-hand{fill:var(--mat-sys-primary, #6750a4)}:host:not(.show-seconds) .clock-second-hand{display:none}:host.has-background svg circle{fill:var(--mat-sys-surface, #fffbfe)}:host:hover{opacity:.8}:host:hover svg .clock-hour-hand,:host:hover svg .clock-minute-hand{fill:var(--mat-sys-primary, #6750a4)}:host.clock-widget.analog{container-type:size;container-name:analog-clock}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1356
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: AnalogClockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1357
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.2.1", type: AnalogClockComponent, isStandalone: true, selector: "lib-analog-clock", inputs: { hasBackground: { classPropertyName: "hasBackground", publicName: "hasBackground", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.has-background": "hasBackground()", "class.show-seconds": "showSeconds()" }, classAttribute: "clock-widget analog" }, viewQueries: [{ propertyName: "hourHand", first: true, predicate: ["hourHand"], descendants: true, isSignal: true }, { propertyName: "minuteHand", first: true, predicate: ["minuteHand"], descendants: true, isSignal: true }, { propertyName: "secondHand", first: true, predicate: ["secondHand"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"analog-clock-container\">\r\n <div class=\"aspect-ratio-box\">\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 800 800\"\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n >\r\n <!-- Optional face circle; uncomment if you want a visible outline by default -->\r\n <!-- <circle cx=\"400\" cy=\"400\" r=\"400\" fill=\"transparent\" stroke=\"currentColor\" stroke-width=\"2\" /> -->\r\n\r\n <use transform=\"matrix(-1,0,0,1,800,0)\" href=\"#one-half\" />\r\n <g id=\"one-half\">\r\n <g id=\"one-fourth\">\r\n <!-- 12 / 3 / 6 / 9 heavy marks -->\r\n <path d=\"m400 40v107\" stroke-width=\"26.7\" stroke=\"currentColor\" />\r\n <g id=\"one-twelfth\">\r\n <!-- 30\u00B0 heavy marks -->\r\n <path\r\n d=\"m580 88.233-42.5 73.612\"\r\n stroke-width=\"26.7\"\r\n stroke=\"currentColor\"\r\n />\r\n <g id=\"one-thirtieth\">\r\n <!-- minute/second ticks -->\r\n <path\r\n id=\"one-sixtieth\"\r\n d=\"m437.63 41.974-3.6585 34.808\"\r\n stroke-width=\"13.6\"\r\n stroke=\"currentColor\"\r\n />\r\n <use transform=\"rotate(6 400 400)\" href=\"#one-sixtieth\" />\r\n </g>\r\n <use transform=\"rotate(12 400 400)\" href=\"#one-thirtieth\" />\r\n </g>\r\n <use transform=\"rotate(30 400 400)\" href=\"#one-twelfth\" />\r\n <use transform=\"rotate(60 400 400)\" href=\"#one-twelfth\" />\r\n </g>\r\n <use transform=\"rotate(90 400 400)\" href=\"#one-fourth\" />\r\n </g>\r\n\r\n <!-- Hands -->\r\n <path\r\n class=\"clock-hour-hand\"\r\n id=\"anim-clock-hour-hand\"\r\n #hourHand\r\n d=\"m 381.925,476 h 36.15 l 5e-4,-300.03008 L 400,156.25 381.9245,175.96992 Z\"\r\n transform=\"rotate(110.2650694444, 400, 400)\"\r\n />\r\n <path\r\n class=\"clock-minute-hand\"\r\n id=\"anim-clock-minute-hand\"\r\n #minuteHand\r\n d=\"M 412.063,496.87456 H 387.937 L 385.249,65.68306 400,52.75 414.751,65.68306 Z\"\r\n transform=\"rotate(243.1808333333, 400, 400)\"\r\n />\r\n <path\r\n class=\"clock-second-hand\"\r\n id=\"anim-clock-second-hand\"\r\n #secondHand\r\n d=\"M 397.317,63.51744 395.91962,168.4 C 374.575,170.5125 358.2,188.365 358.2,210 c 0,21.635 16.3,39 36.61214,41.47594 L 391.52847,498 h 16.94306 L 405.1868,251.47593 C 425.5,249 441.8,231.635 441.8,210 c 2e-5,-21.635 -16.375,-39.4875 -37.71971,-41.6 L 402.683,63.51744 400,60 Z M 400,190.534 c 10.888,0 19.466,8.866 19.466,19.466 0,10.6 -8.578,19.466 -19.466,19.466 -10.888,0 -19.466,-8.866 -19.466,-19.466 0,-10.6 8.578,-19.466 19.466,-19.466 z\"\r\n transform=\"rotate(190.85, 400, 400)\"\r\n />\r\n </svg>\r\n </div>\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%}.analog-clock-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.analog-clock-container .aspect-ratio-box{position:relative;width:100%;max-width:100%;max-height:100%;aspect-ratio:1/1}@supports not (aspect-ratio: 1/1){.analog-clock-container .aspect-ratio-box:before{content:\"\";display:block;padding-bottom:100%}.analog-clock-container .aspect-ratio-box svg{position:absolute;top:0;left:0;width:100%;height:100%}}.analog-clock-container .aspect-ratio-box svg{display:block;width:100%;height:100%}.analog-clock-container .aspect-ratio-box svg path:not(.clock-hour-hand):not(.clock-minute-hand):not(.clock-second-hand){stroke:var(--mat-sys-on-surface, #1d1b20)}.analog-clock-container .aspect-ratio-box svg .clock-hour-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.analog-clock-container .aspect-ratio-box svg .clock-minute-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.analog-clock-container .aspect-ratio-box svg .clock-second-hand{fill:var(--mat-sys-primary, #6750a4)}:host:not(.show-seconds) .clock-second-hand{display:none}:host.has-background svg circle{fill:var(--mat-sys-surface, #fffbfe)}:host:hover{opacity:.8}:host:hover svg .clock-hour-hand,:host:hover svg .clock-minute-hand{fill:var(--mat-sys-primary, #6750a4)}:host.clock-widget.analog{container-type:size;container-name:analog-clock}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1348
1358
  }
1349
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: AnalogClockComponent, decorators: [{
1359
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: AnalogClockComponent, decorators: [{
1350
1360
  type: Component,
1351
- args: [{ selector: 'ngx-analog-clock', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
1361
+ args: [{ selector: 'lib-analog-clock', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
1352
1362
  '[class.has-background]': 'hasBackground()',
1353
1363
  '[class.show-seconds]': 'showSeconds()',
1354
1364
  'class': 'clock-widget analog'
@@ -1361,17 +1371,17 @@ class ClockWidgetComponent {
1361
1371
  widgetTypeid: '@default/clock-widget',
1362
1372
  name: 'Clock',
1363
1373
  description: 'Display time in analog or digital format',
1364
- svgIcon,
1374
+ svgIcon: svgIcon$1,
1365
1375
  };
1366
1376
  #sanitizer = inject(DomSanitizer);
1367
1377
  #dialog = inject(MatDialog);
1368
- safeSvgIcon = this.#sanitizer.bypassSecurityTrustHtml(svgIcon);
1378
+ safeSvgIcon = this.#sanitizer.bypassSecurityTrustHtml(svgIcon$1);
1369
1379
  state = signal({
1370
1380
  mode: 'analog',
1371
1381
  hasBackground: true,
1372
1382
  timeFormat: '24h',
1373
1383
  showSeconds: true,
1374
- });
1384
+ }, ...(ngDevMode ? [{ debugName: "state" }] : []));
1375
1385
  constructor() {
1376
1386
  // No timer logic needed - DigitalClock manages its own time
1377
1387
  }
@@ -1408,14 +1418,827 @@ class ClockWidgetComponent {
1408
1418
  get isDigital() {
1409
1419
  return this.state().mode === 'digital';
1410
1420
  }
1411
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ClockWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1412
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: ClockWidgetComponent, isStandalone: true, selector: "ngx-dashboard-clock-widget", ngImport: i0, template: "@if (isDigital) {\r\n <ngx-digital-clock\r\n [timeFormat]=\"state().timeFormat || '24h'\"\r\n [showSeconds]=\"state().showSeconds ?? true\"\r\n [hasBackground]=\"state().hasBackground ?? false\"\r\n />\r\n} @else if (isAnalog) {\r\n <ngx-analog-clock\r\n [hasBackground]=\"state().hasBackground ?? false\"\r\n [showSeconds]=\"state().showSeconds ?? true\"\r\n />\r\n} @else {\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n</div>\r\n}", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper,.clock-widget{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.has-background.svg-wrapper,.has-background.clock-widget{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.clock-widget{padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d)}.clock-widget.has-background{color:var(--mat-sys-on-surface, #1f1f1f)}.clock-widget:hover{opacity:.8;color:var(--mat-sys-primary, #6750a4)}.analog-clock{width:min(80cqw,80cqh);aspect-ratio:1/1;position:relative}.clock-face{width:100%;height:100%;border:2px solid currentColor;border-radius:50%;position:relative}.clock-face:before,.clock-face:after{content:\"\";position:absolute;background-color:currentColor;left:50%;transform:translate(-50%)}.clock-face:before{width:2px;height:10%;top:0}.clock-face:after{width:2px;height:10%;bottom:0}.hour-hand,.minute-hand{position:absolute;background-color:currentColor;left:50%;bottom:50%;transform-origin:50% 100%;border-radius:2px}.hour-hand{width:4px;height:25%;transform:translate(-50%) rotate(30deg)}.minute-hand{width:2px;height:35%;transform:translate(-50%) rotate(90deg)}.center-dot{position:absolute;width:8px;height:8px;background-color:currentColor;border-radius:50%;top:50%;left:50%;transform:translate(-50%,-50%)}.svg-wrapper{overflow:hidden}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease;transform-origin:center center}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block}.svg-placeholder ::ng-deep svg .clock-face{stroke:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-hour-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-minute-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-second-hand{fill:var(--mat-sys-primary, #6750a4)}.has-background .svg-placeholder ::ng-deep svg circle{fill:var(--mat-sys-surface, #fffbfe)}\n"], dependencies: [{ kind: "component", type: DigitalClockComponent, selector: "ngx-digital-clock", inputs: ["timeFormat", "showSeconds", "hasBackground"] }, { kind: "component", type: AnalogClockComponent, selector: "ngx-analog-clock", inputs: ["hasBackground", "showSeconds"] }] });
1421
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ClockWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1422
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: ClockWidgetComponent, isStandalone: true, selector: "ngx-dashboard-clock-widget", ngImport: i0, template: "@if (isDigital) {\r\n <lib-digital-clock\r\n [timeFormat]=\"state().timeFormat || '24h'\"\r\n [showSeconds]=\"state().showSeconds ?? true\"\r\n [hasBackground]=\"state().hasBackground ?? false\"\r\n />\r\n} @else if (isAnalog) {\r\n <lib-analog-clock\r\n [hasBackground]=\"state().hasBackground ?? false\"\r\n [showSeconds]=\"state().showSeconds ?? true\"\r\n />\r\n} @else {\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n</div>\r\n}", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper,.clock-widget{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.has-background.svg-wrapper,.has-background.clock-widget{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.clock-widget{padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d)}.clock-widget.has-background{color:var(--mat-sys-on-surface, #1f1f1f)}.clock-widget:hover{opacity:.8;color:var(--mat-sys-primary, #6750a4)}.analog-clock{width:min(80cqw,80cqh);aspect-ratio:1/1;position:relative}.clock-face{width:100%;height:100%;border:2px solid currentColor;border-radius:50%;position:relative}.clock-face:before,.clock-face:after{content:\"\";position:absolute;background-color:currentColor;left:50%;transform:translate(-50%)}.clock-face:before{width:2px;height:10%;top:0}.clock-face:after{width:2px;height:10%;bottom:0}.hour-hand,.minute-hand{position:absolute;background-color:currentColor;left:50%;bottom:50%;transform-origin:50% 100%;border-radius:2px}.hour-hand{width:4px;height:25%;transform:translate(-50%) rotate(30deg)}.minute-hand{width:2px;height:35%;transform:translate(-50%) rotate(90deg)}.center-dot{position:absolute;width:8px;height:8px;background-color:currentColor;border-radius:50%;top:50%;left:50%;transform:translate(-50%,-50%)}.svg-wrapper{overflow:hidden}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease;transform-origin:center center}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block}.svg-placeholder ::ng-deep svg .clock-face{stroke:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-hour-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-minute-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-second-hand{fill:var(--mat-sys-primary, #6750a4)}.has-background .svg-placeholder ::ng-deep svg circle{fill:var(--mat-sys-surface, #fffbfe)}\n"], dependencies: [{ kind: "component", type: DigitalClockComponent, selector: "lib-digital-clock", inputs: ["timeFormat", "showSeconds", "hasBackground"] }, { kind: "component", type: AnalogClockComponent, selector: "lib-analog-clock", inputs: ["hasBackground", "showSeconds"] }] });
1423
+ }
1424
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: ClockWidgetComponent, decorators: [{
1425
+ type: Component,
1426
+ args: [{ selector: 'ngx-dashboard-clock-widget', standalone: true, imports: [DigitalClockComponent, AnalogClockComponent], template: "@if (isDigital) {\r\n <lib-digital-clock\r\n [timeFormat]=\"state().timeFormat || '24h'\"\r\n [showSeconds]=\"state().showSeconds ?? true\"\r\n [hasBackground]=\"state().hasBackground ?? false\"\r\n />\r\n} @else if (isAnalog) {\r\n <lib-analog-clock\r\n [hasBackground]=\"state().hasBackground ?? false\"\r\n [showSeconds]=\"state().showSeconds ?? true\"\r\n />\r\n} @else {\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n</div>\r\n}", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper,.clock-widget{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.has-background.svg-wrapper,.has-background.clock-widget{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.clock-widget{padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d)}.clock-widget.has-background{color:var(--mat-sys-on-surface, #1f1f1f)}.clock-widget:hover{opacity:.8;color:var(--mat-sys-primary, #6750a4)}.analog-clock{width:min(80cqw,80cqh);aspect-ratio:1/1;position:relative}.clock-face{width:100%;height:100%;border:2px solid currentColor;border-radius:50%;position:relative}.clock-face:before,.clock-face:after{content:\"\";position:absolute;background-color:currentColor;left:50%;transform:translate(-50%)}.clock-face:before{width:2px;height:10%;top:0}.clock-face:after{width:2px;height:10%;bottom:0}.hour-hand,.minute-hand{position:absolute;background-color:currentColor;left:50%;bottom:50%;transform-origin:50% 100%;border-radius:2px}.hour-hand{width:4px;height:25%;transform:translate(-50%) rotate(30deg)}.minute-hand{width:2px;height:35%;transform:translate(-50%) rotate(90deg)}.center-dot{position:absolute;width:8px;height:8px;background-color:currentColor;border-radius:50%;top:50%;left:50%;transform:translate(-50%,-50%)}.svg-wrapper{overflow:hidden}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease;transform-origin:center center}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block}.svg-placeholder ::ng-deep svg .clock-face{stroke:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-hour-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-minute-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-second-hand{fill:var(--mat-sys-primary, #6750a4)}.has-background .svg-placeholder ::ng-deep svg circle{fill:var(--mat-sys-surface, #fffbfe)}\n"] }]
1427
+ }], ctorParameters: () => [] });
1428
+
1429
+ /**
1430
+ * Responsive radial gauge component with hybrid sizing and thickness control.
1431
+ *
1432
+ * This component provides a highly flexible gauge system with three independent
1433
+ * control dimensions that can be mixed and matched for different use cases:
1434
+ *
1435
+ * ## Size Control:
1436
+ * - **Fixed Size**: Use manual `size` input (traditional behavior)
1437
+ * - **Container Responsive**: Enable `fitToContainer` for automatic sizing
1438
+ *
1439
+ * ## Thickness Control:
1440
+ * - **Manual Thickness**: Use individual thickness inputs (traditional behavior)
1441
+ * - **Proportional Thickness**: Enable `responsiveMode` for size-based scaling
1442
+ *
1443
+ * ## Usage Scenarios:
1444
+ *
1445
+ * ### 1. Dashboard Widgets (Recommended)
1446
+ * ```html
1447
+ * <ngx-radial-gauge
1448
+ * [value]="cpuUsage"
1449
+ * [fitToContainer]="true"
1450
+ * [responsiveMode]="true"
1451
+ * [sizeToThicknessRatio]="12" />
1452
+ * ```
1453
+ * **Best for**: Grid layouts, dashboard panels, adaptive containers
1454
+ * **Behavior**: Automatically resizes to fit available space while maintaining
1455
+ * consistent proportional appearance across all sizes.
1456
+ *
1457
+ * ### 2. Fixed Layouts (Traditional)
1458
+ * ```html
1459
+ * <ngx-radial-gauge
1460
+ * [value]="temperature"
1461
+ * [size]="300"
1462
+ * [outerThickness]="36"
1463
+ * [innerThickness]="12" />
1464
+ * ```
1465
+ * **Best for**: Static designs, precise sizing requirements, print layouts
1466
+ * **Behavior**: Exact pixel control over all dimensions, predictable appearance.
1467
+ *
1468
+ * ### 3. Scalable Designs
1469
+ * ```html
1470
+ * <ngx-radial-gauge
1471
+ * [value]="batteryLevel"
1472
+ * [size]="gaugeSize"
1473
+ * [responsiveMode]="true"
1474
+ * [sizeToThicknessRatio]="20" />
1475
+ * ```
1476
+ * **Best for**: User-configurable sizing, responsive breakpoints, zoom interfaces
1477
+ * **Behavior**: Manual size control with automatic thickness scaling. As size
1478
+ * increases/decreases, ring thickness scales proportionally to maintain visual balance.
1479
+ *
1480
+ * ## Mathematical Relationships:
1481
+ *
1482
+ * When `responsiveMode=true`, thickness follows this formula:
1483
+ * ```
1484
+ * baseThickness = effectiveSize / sizeToThicknessRatio
1485
+ * outerThickness = baseThickness × responsiveProportions.outer (default: 3)
1486
+ * innerThickness = baseThickness × responsiveProportions.inner (default: 1)
1487
+ * gap = baseThickness × responsiveProportions.gap (default: 0.5)
1488
+ * totalThickness = baseThickness × 4.5 (outer + inner + gap)
1489
+ * ```
1490
+ *
1491
+ * Example with 300px gauge and ratio=20 (ultra-thin):
1492
+ * - baseThickness = 15px
1493
+ * - outerThickness = 45px (15×3)
1494
+ * - innerThickness = 15px (15×1)
1495
+ * - gap = 7.5px (15×0.5)
1496
+ * - totalThickness = 67.5px (22.5% of diameter)
1497
+ *
1498
+ * ## Container Responsiveness:
1499
+ *
1500
+ * When `fitToContainer=true`, the component uses ResizeObserver to:
1501
+ * 1. Monitor parent container dimension changes
1502
+ * 2. Calculate maximum diameter maintaining 2:1 aspect ratio (width:height)
1503
+ * 3. Apply containerPadding for safe margins
1504
+ * 4. Update gauge size in real-time
1505
+ *
1506
+ * This provides true responsive behavior for dashboard widgets, grid layouts,
1507
+ * and adaptive interfaces.
1508
+ *
1509
+ * ## Accessibility:
1510
+ *
1511
+ * The component implements ARIA meter role with proper labeling:
1512
+ * - `role="meter"` for semantic meaning
1513
+ * - `aria-valuemin/max/now` for screen readers
1514
+ * - `aria-label` with contextual information
1515
+ * - Internationalized number formatting
1516
+ *
1517
+ */
1518
+ class RadialGaugeComponent {
1519
+ valueTextEl = viewChild('valueText', ...(ngDevMode ? [{ debugName: "valueTextEl" }] : []));
1520
+ valueGroupEl = viewChild('valueGroup', ...(ngDevMode ? [{ debugName: "valueGroupEl" }] : []));
1521
+ refTextEl = viewChild.required('refText');
1522
+ // Core Inputs - Value and Range
1523
+ value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : []));
1524
+ min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : []));
1525
+ max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : []));
1526
+ segments = input(...(ngDevMode ? [undefined, { debugName: "segments" }] : []));
1527
+ title = input('Gauge', ...(ngDevMode ? [{ debugName: "title" }] : []));
1528
+ description = input('', ...(ngDevMode ? [{ debugName: "description" }] : []));
1529
+ segmentGapPx = input(4, ...(ngDevMode ? [{ debugName: "segmentGapPx" }] : []));
1530
+ // Widget styling inputs
1531
+ /**
1532
+ * Whether the gauge should display with a background.
1533
+ * Affects text color contrast and other visual elements.
1534
+ * @default false
1535
+ */
1536
+ hasBackground = input(false, ...(ngDevMode ? [{ debugName: "hasBackground" }] : []));
1537
+ /**
1538
+ * Whether to display the numeric value label in the center of the gauge.
1539
+ * @default true
1540
+ */
1541
+ showValueLabel = input(true, ...(ngDevMode ? [{ debugName: "showValueLabel" }] : []));
1542
+ // Size Control Inputs
1543
+ /**
1544
+ * Base gauge diameter in pixels. Used as fallback when fitToContainer is false.
1545
+ * @default 300
1546
+ */
1547
+ size = input(300, ...(ngDevMode ? [{ debugName: "size" }] : []));
1548
+ /**
1549
+ * Automatically resize gauge to fit its container dimensions.
1550
+ * When true, the gauge will observe container size changes and adjust accordingly.
1551
+ * Maintains semicircle aspect ratio (2:1 width:height).
1552
+ * @default false
1553
+ */
1554
+ fitToContainer = input(false, ...(ngDevMode ? [{ debugName: "fitToContainer" }] : []));
1555
+ /**
1556
+ * Padding in pixels to maintain from container edges when fitToContainer is true.
1557
+ * @default 10
1558
+ */
1559
+ containerPadding = input(10, ...(ngDevMode ? [{ debugName: "containerPadding" }] : []));
1560
+ // Thickness Control Inputs
1561
+ /**
1562
+ * Use proportional thickness scaling based on gauge size.
1563
+ * When true, all thickness values are calculated as multiples of baseThickness.
1564
+ * Overrides manual outerThickness, innerThickness, and gap inputs.
1565
+ * @default false
1566
+ */
1567
+ responsiveMode = input(false, ...(ngDevMode ? [{ debugName: "responsiveMode" }] : []));
1568
+ /**
1569
+ * Ratio used to calculate base thickness from gauge size.
1570
+ * baseThickness = effectiveSize / sizeToThicknessRatio
1571
+ * Higher values create thinner gauge rings for ultra-thin appearance.
1572
+ * @default 20
1573
+ * @example
1574
+ * - ratio=15: thicker rings (bt = size/15)
1575
+ * - ratio=20: ultra-thin balanced appearance (bt = size/20)
1576
+ * - ratio=30: extremely thin rings (bt = size/30)
1577
+ */
1578
+ sizeToThicknessRatio = input(20, ...(ngDevMode ? [{ debugName: "sizeToThicknessRatio" }] : []));
1579
+ /**
1580
+ * Proportional multipliers for responsive thickness calculations.
1581
+ * - outer: Multiplier for outer ring thickness (default: 3)
1582
+ * - inner: Multiplier for inner ring thickness (default: 1)
1583
+ * - gap: Multiplier for gap between rings (default: 0.5)
1584
+ * Total thickness = baseThickness × (outer + inner + gap) = bt × 4.5
1585
+ * @default { outer: 3, inner: 1, gap: 0.5 }
1586
+ */
1587
+ responsiveProportions = input({ outer: 3, inner: 1, gap: 0.5 }, ...(ngDevMode ? [{ debugName: "responsiveProportions" }] : []));
1588
+ // Manual Thickness Inputs (used when responsiveMode is false)
1589
+ /**
1590
+ * Manual outer ring thickness in pixels. Ignored when responsiveMode is true.
1591
+ * @default 36
1592
+ */
1593
+ outerThickness = input(36, ...(ngDevMode ? [{ debugName: "outerThickness" }] : []));
1594
+ /**
1595
+ * Manual inner ring thickness in pixels. Ignored when responsiveMode is true.
1596
+ * @default 12
1597
+ */
1598
+ innerThickness = input(12, ...(ngDevMode ? [{ debugName: "innerThickness" }] : []));
1599
+ /**
1600
+ * Manual gap between rings in pixels. Ignored when responsiveMode is true.
1601
+ * @default 8
1602
+ */
1603
+ gap = input(8, ...(ngDevMode ? [{ debugName: "gap" }] : []));
1604
+ titleId = `rg-title-${Math.random().toString(36).slice(2)}`;
1605
+ descId = `rg-desc-${Math.random().toString(36).slice(2)}`;
1606
+ clipId = `rg-clip-${Math.random().toString(36).slice(2)}`;
1607
+ locale = inject(LOCALE_ID);
1608
+ elementRef = inject((ElementRef));
1609
+ destroyRef = inject(DestroyRef);
1610
+ nf = new Intl.NumberFormat(this.locale, {
1611
+ maximumFractionDigits: 1,
1612
+ });
1613
+ // Container Size Detection
1614
+ /**
1615
+ * Tracks the container's available size for responsive sizing.
1616
+ * Updated by ResizeObserver when fitToContainer is enabled.
1617
+ * @private
1618
+ */
1619
+ containerSize = signal(null, ...(ngDevMode ? [{ debugName: "containerSize" }] : []));
1620
+ /**
1621
+ * ResizeObserver instance for monitoring container size changes.
1622
+ * Created when fitToContainer is enabled, destroyed on component cleanup.
1623
+ * @private
1624
+ */
1625
+ resizeObserver = null;
1626
+ viewReady = toSignal(from(new Promise((resolve) => afterNextRender(resolve))).pipe(map(() => true)), { initialValue: false });
1627
+ fontsReady = toSignal(typeof document !== 'undefined' && 'fonts' in document
1628
+ ? from(document.fonts.ready).pipe(map(() => true))
1629
+ : of(true), // SSR or older browsers: treat as ready
1630
+ { initialValue: false });
1631
+ constructor() {
1632
+ this.destroyRef.onDestroy(() => {
1633
+ if (this.resizeObserver) {
1634
+ this.resizeObserver.disconnect();
1635
+ this.resizeObserver = null;
1636
+ }
1637
+ });
1638
+ }
1639
+ /**
1640
+ * Effect that manages ResizeObserver lifecycle based on fitToContainer input.
1641
+ * Automatically connects/disconnects observer when the input changes.
1642
+ * @private
1643
+ */
1644
+ containerObserverEffect = effect(() => {
1645
+ const shouldObserve = this.fitToContainer();
1646
+ if (shouldObserve && !this.resizeObserver) {
1647
+ // Create and start observing
1648
+ this.resizeObserver = new ResizeObserver((entries) => {
1649
+ const entry = entries[0];
1650
+ if (!entry)
1651
+ return;
1652
+ const { width, height } = entry.contentRect;
1653
+ const padding = this.containerPadding();
1654
+ const availW = Math.max(0, width - padding * 2);
1655
+ const availH = Math.max(0, height - padding);
1656
+ let sFromW;
1657
+ let sFromH;
1658
+ if (this.responsiveMode()) {
1659
+ // In responsive mode: outerThickness = 3 * baseThickness = 3 * size / ratio
1660
+ // Total space needed = size + outerThickness = size + 3*size/ratio = size * (1 + 3/ratio)
1661
+ const ratio = this.sizeToThicknessRatio();
1662
+ const spaceFactor = 1 + 3 / ratio; // Total space factor
1663
+ sFromW = availW / spaceFactor;
1664
+ sFromH = (2 * availH) / spaceFactor;
1665
+ }
1666
+ else {
1667
+ // Manual thickness: outer thickness is fixed
1668
+ const outerT = this.outerThickness();
1669
+ sFromW = Math.max(0, availW - outerT);
1670
+ sFromH = Math.max(0, 2 * availH - outerT);
1671
+ }
1672
+ const maxDiameter = Math.min(sFromW, sFromH);
1673
+ this.containerSize.set(Math.max(maxDiameter, 50));
1674
+ });
1675
+ this.resizeObserver.observe(this.elementRef.nativeElement);
1676
+ }
1677
+ else if (!shouldObserve && this.resizeObserver) {
1678
+ // Stop observing and cleanup
1679
+ this.resizeObserver.disconnect();
1680
+ this.resizeObserver = null;
1681
+ this.containerSize.set(null);
1682
+ }
1683
+ }, ...(ngDevMode ? [{ debugName: "containerObserverEffect" }] : []));
1684
+ // ── Build the reference string reactively ───────────────────────────────────
1685
+ referenceString = computed(() => {
1686
+ const ref = this.labelReference();
1687
+ if (typeof ref === 'string')
1688
+ return ref;
1689
+ if (typeof ref === 'number' && ref > 0) {
1690
+ const g = this.referenceGlyph() ?? '0';
1691
+ return g.repeat(ref);
1692
+ }
1693
+ return this.formattedLabel(); // measure actual label
1694
+ }, ...(ngDevMode ? [{ debugName: "referenceString" }] : []));
1695
+ // ── Core transform: center + uniform scale to fit the reserved box ──────────
1696
+ valueTransform = computed(() => {
1697
+ if (!this.showValueLabel())
1698
+ return '';
1699
+ // ensure we wait for first paint + font shaping
1700
+ this.viewReady();
1701
+ this.fontsReady();
1702
+ const cx = this.centerX();
1703
+ const cy = this.centerY();
1704
+ const r = this.legendInnerRadius();
1705
+ const pad = this.labelPadding();
1706
+ const boxWidth = Math.max(0, 2 * r - 2 * pad);
1707
+ const boxHeight = Math.max(0, r - pad);
1708
+ // If geometry is degenerate, just center.
1709
+ if (!boxWidth || !boxHeight)
1710
+ return `translate(${cx},${cy})`;
1711
+ // Measure the actual label (for height) and the reference (for width)
1712
+ const labelEl = this.valueTextEl()?.nativeElement;
1713
+ const refEl = this.refTextEl().nativeElement;
1714
+ if (!labelEl)
1715
+ return `translate(${cx},${cy})`;
1716
+ // Important: ensure text nodes are up to date before reading BBox
1717
+ // (Angular's computed/effect guarantees sync within the same microtask)
1718
+ const labelBox = this.safeBBox(labelEl);
1719
+ const refBox = this.safeBBox(refEl);
1720
+ // Use reference width and actual label height
1721
+ const widthForFit = refBox.width || labelBox.width || 1;
1722
+ const heightForFit = labelBox.height || refBox.height || 1;
1723
+ const s = Math.min(boxWidth / widthForFit, boxHeight / heightForFit) *
1724
+ this.baselineSafety();
1725
+ return `translate(${cx},${cy}) scale(${s})`;
1726
+ }, ...(ngDevMode ? [{ debugName: "valueTransform" }] : []));
1727
+ /** Guarded getBBox that avoids 0/NaN on detached or invisible nodes. */
1728
+ safeBBox(node) {
1729
+ try {
1730
+ const box = node.getBBox();
1731
+ // Firefox/Safari can occasionally return 0 when text hasn’t painted yet; fall back to a rough estimate.
1732
+ if (box && (box.width > 0 || box.height > 0))
1733
+ return box;
1734
+ }
1735
+ catch {
1736
+ /* ignore */
1737
+ }
1738
+ // Fallback guess to avoid divide-by-zero (tuned small; will get corrected next tick)
1739
+ return new DOMRect(0, 0, 1, 1);
1740
+ }
1741
+ // Responsive Size and Thickness Calculations
1742
+ /**
1743
+ * The effective gauge diameter, accounting for container sizing and manual size input.
1744
+ * Priority: containerSize (when fitToContainer=true) > manual size input
1745
+ * @returns Effective diameter in pixels
1746
+ *
1747
+ * @example
1748
+ * // Fixed size mode
1749
+ * fitToContainer=false, size=300 → effectiveSize=300
1750
+ *
1751
+ * // Container responsive mode
1752
+ * fitToContainer=true, container=400px wide → effectiveSize=380 (minus padding)
1753
+ */
1754
+ effectiveSize = computed(() => {
1755
+ const containerDiameter = this.containerSize();
1756
+ if (this.fitToContainer() && containerDiameter !== null) {
1757
+ return containerDiameter;
1758
+ }
1759
+ return this.size();
1760
+ }, ...(ngDevMode ? [{ debugName: "effectiveSize" }] : []));
1761
+ /**
1762
+ * Base thickness calculated from effective size for proportional scaling.
1763
+ * Only used when responsiveMode is enabled.
1764
+ * Formula: baseThickness = effectiveSize / sizeToThicknessRatio
1765
+ * @returns Base thickness in pixels, or 0 when responsiveMode is false
1766
+ *
1767
+ * @example
1768
+ * // effectiveSize=300, sizeToThicknessRatio=12
1769
+ * baseThickness = 300/12 = 25px
1770
+ * // Total ring thickness = 25 × 4.5 = 112.5px (37.5% of diameter)
1771
+ */
1772
+ baseThickness = computed(() => {
1773
+ if (!this.responsiveMode())
1774
+ return 0;
1775
+ return this.effectiveSize() / this.sizeToThicknessRatio();
1776
+ }, ...(ngDevMode ? [{ debugName: "baseThickness" }] : []));
1777
+ /**
1778
+ * Effective outer ring thickness, supporting both manual and responsive modes.
1779
+ * - Responsive mode: baseThickness × responsiveProportions.outer
1780
+ * - Manual mode: outerThickness input value
1781
+ * @returns Outer ring thickness in pixels
1782
+ */
1783
+ effectiveOuterThickness = computed(() => {
1784
+ if (this.responsiveMode()) {
1785
+ return this.baseThickness() * this.responsiveProportions().outer;
1786
+ }
1787
+ return this.outerThickness();
1788
+ }, ...(ngDevMode ? [{ debugName: "effectiveOuterThickness" }] : []));
1789
+ /**
1790
+ * Effective inner ring thickness, supporting both manual and responsive modes.
1791
+ * - Responsive mode: baseThickness × responsiveProportions.inner
1792
+ * - Manual mode: innerThickness input value
1793
+ * @returns Inner ring thickness in pixels
1794
+ */
1795
+ effectiveInnerThickness = computed(() => {
1796
+ if (this.responsiveMode()) {
1797
+ return this.baseThickness() * this.responsiveProportions().inner;
1798
+ }
1799
+ return this.innerThickness();
1800
+ }, ...(ngDevMode ? [{ debugName: "effectiveInnerThickness" }] : []));
1801
+ /**
1802
+ * Effective gap between rings, supporting both manual and responsive modes.
1803
+ * - Responsive mode: baseThickness × responsiveProportions.gap
1804
+ * - Manual mode: gap input value
1805
+ * @returns Gap between rings in pixels
1806
+ */
1807
+ effectiveGap = computed(() => {
1808
+ if (this.responsiveMode()) {
1809
+ return this.baseThickness() * this.responsiveProportions().gap;
1810
+ }
1811
+ return this.gap();
1812
+ }, ...(ngDevMode ? [{ debugName: "effectiveGap" }] : []));
1813
+ // SVG Layout Calculations
1814
+ svgPadding = computed(() => this.effectiveOuterThickness() / 2, ...(ngDevMode ? [{ debugName: "svgPadding" }] : []));
1815
+ svgWidth = computed(() => this.effectiveSize() + this.effectiveOuterThickness(), ...(ngDevMode ? [{ debugName: "svgWidth" }] : []));
1816
+ svgHeight = computed(() => Math.ceil(this.effectiveSize() / 2 + this.effectiveOuterThickness() / 2), ...(ngDevMode ? [{ debugName: "svgHeight" }] : []));
1817
+ centerX = computed(() => this.effectiveSize() / 2 + this.effectiveOuterThickness() / 2, ...(ngDevMode ? [{ debugName: "centerX" }] : []));
1818
+ centerY = computed(() => this.effectiveSize() / 2 + this.effectiveOuterThickness() / 2, ...(ngDevMode ? [{ debugName: "centerY" }] : []));
1819
+ /**
1820
+ * If a string is provided, we measure it and allocate space for that width.
1821
+ * If a number is provided, we build a string of that many `referenceGlyph`s.
1822
+ * If omitted, we fall back to measuring the actual label.
1823
+ */
1824
+ labelReference = input(undefined, ...(ngDevMode ? [{ debugName: "labelReference" }] : []));
1825
+ /** Glyph to repeat when labelReference is a number (defaults to '0'). */
1826
+ referenceGlyph = input('0', ...(ngDevMode ? [{ debugName: "referenceGlyph" }] : []));
1827
+ /** Extra breathing room inside the inner semicircle box (in px). */
1828
+ labelPadding = input(4, ...(ngDevMode ? [{ debugName: "labelPadding" }] : []));
1829
+ /** Safety multiplier to avoid clipping ascenders/descenders. */
1830
+ baselineSafety = input(0.95, ...(ngDevMode ? [{ debugName: "baselineSafety" }] : []));
1831
+ outerRadius = computed(() => this.effectiveSize() / 2, ...(ngDevMode ? [{ debugName: "outerRadius" }] : []));
1832
+ innerRadius = computed(() => this.outerRadius() -
1833
+ this.effectiveOuterThickness() / 2 -
1834
+ this.effectiveGap(), ...(ngDevMode ? [{ debugName: "innerRadius" }] : []));
1835
+ legendOuterRadius = computed(() => this.outerRadius() -
1836
+ this.effectiveOuterThickness() / 2 -
1837
+ this.effectiveGap() -
1838
+ this.effectiveInnerThickness() / 2, ...(ngDevMode ? [{ debugName: "legendOuterRadius" }] : []));
1839
+ legendInnerRadius = computed(() => this.legendOuterRadius() - this.effectiveInnerThickness(), ...(ngDevMode ? [{ debugName: "legendInnerRadius" }] : []));
1840
+ startAngle = -180;
1841
+ endAngle = 0;
1842
+ clampedValue = computed(() => this.clamp(this.value(), this.min(), this.max()), ...(ngDevMode ? [{ debugName: "clampedValue" }] : []));
1843
+ percentage = computed(() => {
1844
+ const range = this.max() - this.min();
1845
+ if (range === 0)
1846
+ return 0;
1847
+ return (this.clampedValue() - this.min()) / range;
1848
+ }, ...(ngDevMode ? [{ debugName: "percentage" }] : []));
1849
+ percent = computed(() => Math.round(this.percentage() * 100), ...(ngDevMode ? [{ debugName: "percent" }] : []));
1850
+ defaultSegments = computed(() => {
1851
+ const minVal = this.min();
1852
+ const maxVal = this.max();
1853
+ const range = maxVal - minVal;
1854
+ return [
1855
+ {
1856
+ from: minVal,
1857
+ to: minVal + 0.6 * range,
1858
+ color: 'var(--gauge-value-critical, #dc2626)',
1859
+ },
1860
+ {
1861
+ from: minVal + 0.6 * range,
1862
+ to: minVal + 0.8 * range,
1863
+ color: 'var(--gauge-value-warning, #f59e0b)',
1864
+ },
1865
+ {
1866
+ from: minVal + 0.8 * range,
1867
+ to: maxVal,
1868
+ color: 'var(--gauge-value-good, #10b981)',
1869
+ },
1870
+ ];
1871
+ }, ...(ngDevMode ? [{ debugName: "defaultSegments" }] : []));
1872
+ actualSegments = computed(() => this.segments() || this.defaultSegments(), ...(ngDevMode ? [{ debugName: "actualSegments" }] : []));
1873
+ formattedLabel = computed(() => this.nf.format(this.clampedValue()), ...(ngDevMode ? [{ debugName: "formattedLabel" }] : []));
1874
+ valueColor = computed(() => {
1875
+ const v = this.clampedValue();
1876
+ const segs = this.actualSegments();
1877
+ for (const s of segs) {
1878
+ if (v >= s.from && v <= s.to)
1879
+ return s.color;
1880
+ }
1881
+ return segs.at(-1)?.color ?? 'var(--mat-sys-primary)';
1882
+ }, ...(ngDevMode ? [{ debugName: "valueColor" }] : []));
1883
+ backgroundArcPath = computed(() => this.createArcPath(this.outerRadius(), this.startAngle, this.endAngle), ...(ngDevMode ? [{ debugName: "backgroundArcPath" }] : []));
1884
+ segmentPaths = computed(() => {
1885
+ const segs = this.actualSegments();
1886
+ const minVal = this.min();
1887
+ const maxVal = this.max();
1888
+ const range = maxVal - minVal;
1889
+ if (!range)
1890
+ return [];
1891
+ const r = this.legendOuterRadius();
1892
+ const gapDeg = this.gapDegreesForRadius(this.segmentGapPx(), r);
1893
+ return segs
1894
+ .map((s, i) => {
1895
+ const startPct = this.clamp((s.from - minVal) / range, 0, 1);
1896
+ const endPct = this.clamp((s.to - minVal) / range, 0, 1);
1897
+ let a0 = this.angleForPercentage(startPct);
1898
+ let a1 = this.angleForPercentage(endPct);
1899
+ if (i > 0)
1900
+ a0 += gapDeg / 2;
1901
+ if (i < segs.length - 1)
1902
+ a1 -= gapDeg / 2;
1903
+ if (a1 <= a0)
1904
+ return null;
1905
+ return { path: this.createArcPath(r, a0, a1), color: s.color };
1906
+ })
1907
+ .filter((x) => !!x);
1908
+ }, ...(ngDevMode ? [{ debugName: "segmentPaths" }] : []));
1909
+ ariaLabel = computed(() => `${this.title()}: ${this.formattedLabel()} (range ${this.min()}–${this.max()})`, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
1910
+ clamp(v, min, max) {
1911
+ return Math.min(Math.max(v, min), max);
1912
+ }
1913
+ /**
1914
+ * Converts a percentage (0-1) to an angle position on the gauge arc.
1915
+ * The gauge spans from startAngle (-180°) to endAngle (0°), creating a semicircle.
1916
+ * @param p - Percentage value between 0 and 1
1917
+ * @returns Angle in degrees for the given percentage along the gauge arc
1918
+ * @example
1919
+ * angleForPercentage(0) => -180° (start of gauge)
1920
+ * angleForPercentage(0.5) => -90° (middle of gauge)
1921
+ * angleForPercentage(1) => 0° (end of gauge)
1922
+ */
1923
+ angleForPercentage(p) {
1924
+ return this.startAngle + (this.endAngle - this.startAngle) * p;
1925
+ }
1926
+ /**
1927
+ * Converts polar coordinates (radius, angle) to Cartesian coordinates (x, y).
1928
+ * Uses standard trigonometric conversion where angle 0° points to the right (3 o'clock).
1929
+ * @param cx - Center X coordinate of the circle
1930
+ * @param cy - Center Y coordinate of the circle
1931
+ * @param r - Radius distance from center
1932
+ * @param angle - Angle in degrees (0° = right, 90° = down, 180° = left, -90° = up)
1933
+ * @returns Object with x and y Cartesian coordinates
1934
+ * @example
1935
+ * polarToCartesian(100, 100, 50, 0) => {x: 150, y: 100} // 3 o'clock
1936
+ * polarToCartesian(100, 100, 50, -90) => {x: 100, y: 50} // 12 o'clock
1937
+ */
1938
+ polarToCartesian(cx, cy, r, angle) {
1939
+ const a = (angle * Math.PI) / 180;
1940
+ return { x: cx + r * Math.cos(a), y: cy + r * Math.sin(a) };
1941
+ }
1942
+ /**
1943
+ * Creates an SVG path string for a circular arc segment.
1944
+ * Uses SVG arc path commands to draw an arc from start angle to end angle.
1945
+ * @param r - Radius of the arc
1946
+ * @param a0 - Starting angle in degrees
1947
+ * @param a1 - Ending angle in degrees
1948
+ * @returns SVG path string defining the arc
1949
+ * @example
1950
+ * createArcPath(50, -180, 0) => "M cx-50 cy A 50 50 0 1 1 cx+50 cy"
1951
+ * This creates a semicircle from left (-180°) to right (0°)
1952
+ *
1953
+ * SVG Arc Parameters:
1954
+ * - rx, ry: Radii (equal for circular arc)
1955
+ * - x-axis-rotation: 0 (no rotation for circles)
1956
+ * - large-arc-flag: 1 if arc > 180°, 0 otherwise
1957
+ * - sweep-flag: 1 for clockwise, 0 for counter-clockwise
1958
+ */
1959
+ createArcPath(r, a0, a1) {
1960
+ const cx = this.centerX(), cy = this.centerY();
1961
+ const start = this.polarToCartesian(cx, cy, r, a0);
1962
+ const end = this.polarToCartesian(cx, cy, r, a1);
1963
+ const largeArc = Math.abs(a1 - a0) > 180 ? 1 : 0;
1964
+ const sweep = a1 > a0 ? 1 : 0;
1965
+ return `M ${start.x} ${start.y} A ${r} ${r} 0 ${largeArc} ${sweep} ${end.x} ${end.y}`;
1966
+ }
1967
+ /**
1968
+ * Calculates the angular gap in degrees needed for a specific pixel gap at a given radius.
1969
+ * Used to create visual separation between legend segments.
1970
+ * @param px - Desired gap size in pixels
1971
+ * @param r - Radius at which the gap will appear
1972
+ * @returns Gap size in degrees, clamped between 0° and 180°
1973
+ * @example
1974
+ * For a 4px gap on a radius of 100px:
1975
+ * Arc length = π * 100 = 314.16px (semicircle)
1976
+ * Degrees = 180 * (4 / 314.16) ≈ 2.3°
1977
+ *
1978
+ * Mathematical basis:
1979
+ * - Semicircle arc length = π * r
1980
+ * - Ratio of gap to semicircle = px / (π * r)
1981
+ * - Convert ratio to degrees by multiplying by 180°
1982
+ */
1983
+ gapDegreesForRadius(px, r) {
1984
+ const semicircumference = Math.PI * r;
1985
+ return 180 * this.clamp(px / semicircumference, 0, 1);
1986
+ }
1987
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: RadialGaugeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1988
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: RadialGaugeComponent, isStandalone: true, selector: "ngx-radial-gauge", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, segments: { classPropertyName: "segments", publicName: "segments", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, segmentGapPx: { classPropertyName: "segmentGapPx", publicName: "segmentGapPx", isSignal: true, isRequired: false, transformFunction: null }, hasBackground: { classPropertyName: "hasBackground", publicName: "hasBackground", isSignal: true, isRequired: false, transformFunction: null }, showValueLabel: { classPropertyName: "showValueLabel", publicName: "showValueLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fitToContainer: { classPropertyName: "fitToContainer", publicName: "fitToContainer", isSignal: true, isRequired: false, transformFunction: null }, containerPadding: { classPropertyName: "containerPadding", publicName: "containerPadding", isSignal: true, isRequired: false, transformFunction: null }, responsiveMode: { classPropertyName: "responsiveMode", publicName: "responsiveMode", isSignal: true, isRequired: false, transformFunction: null }, sizeToThicknessRatio: { classPropertyName: "sizeToThicknessRatio", publicName: "sizeToThicknessRatio", isSignal: true, isRequired: false, transformFunction: null }, responsiveProportions: { classPropertyName: "responsiveProportions", publicName: "responsiveProportions", isSignal: true, isRequired: false, transformFunction: null }, outerThickness: { classPropertyName: "outerThickness", publicName: "outerThickness", isSignal: true, isRequired: false, transformFunction: null }, innerThickness: { classPropertyName: "innerThickness", publicName: "innerThickness", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null }, labelReference: { classPropertyName: "labelReference", publicName: "labelReference", isSignal: true, isRequired: false, transformFunction: null }, referenceGlyph: { classPropertyName: "referenceGlyph", publicName: "referenceGlyph", isSignal: true, isRequired: false, transformFunction: null }, labelPadding: { classPropertyName: "labelPadding", publicName: "labelPadding", isSignal: true, isRequired: false, transformFunction: null }, baselineSafety: { classPropertyName: "baselineSafety", publicName: "baselineSafety", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "meter" }, properties: { "attr.aria-label": "ariaLabel()", "attr.aria-valuemin": "min()", "attr.aria-valuemax": "max()", "attr.aria-valuenow": "clampedValue()", "attr.aria-valuetext": "formattedLabel()", "attr.aria-labelledby": "titleId", "attr.aria-describedby": "descId", "class.fit-container": "fitToContainer()", "class.has-background": "hasBackground()" } }, viewQueries: [{ propertyName: "valueTextEl", first: true, predicate: ["valueText"], descendants: true, isSignal: true }, { propertyName: "valueGroupEl", first: true, predicate: ["valueGroup"], descendants: true, isSignal: true }, { propertyName: "refTextEl", first: true, predicate: ["refText"], descendants: true, isSignal: true }], ngImport: i0, template: "@let w = svgWidth(); @let h = svgHeight(); @let cy = centerY(); @let pct =\r\npercent();\r\n\r\n<svg\r\n [attr.width]=\"fitToContainer() ? null : w\"\r\n [attr.height]=\"fitToContainer() ? null : h\"\r\n [attr.viewBox]=\"'0 0 ' + w + ' ' + h\"\r\n [class.responsive]=\"fitToContainer()\"\r\n class=\"gauge-svg\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n>\r\n <title [attr.id]=\"titleId\">{{ title() }}</title>\r\n @if (description()) {\r\n <desc [attr.id]=\"descId\">{{ description() }}</desc>\r\n }\r\n\r\n <defs>\r\n <clipPath [attr.id]=\"clipId\">\r\n <!-- Give a tiny extra room equal to half of the outer stroke to avoid anti-alias cutoff at the baseline -->\r\n <rect\r\n x=\"0\"\r\n y=\"0\"\r\n [attr.width]=\"w\"\r\n [attr.height]=\"cy + effectiveOuterThickness() / 2\"\r\n />\r\n </clipPath>\r\n </defs>\r\n\r\n <g [attr.clip-path]=\"'url(#' + clipId + ')'\">\r\n <path\r\n [attr.d]=\"backgroundArcPath()\"\r\n pathLength=\"100\"\r\n fill=\"none\"\r\n class=\"gauge-background\"\r\n [attr.stroke-width]=\"effectiveOuterThickness()\"\r\n stroke-linecap=\"butt\"\r\n />\r\n\r\n <path\r\n [attr.d]=\"backgroundArcPath()\"\r\n pathLength=\"100\"\r\n fill=\"none\"\r\n class=\"gauge-value\"\r\n [attr.stroke]=\"valueColor()\"\r\n [attr.stroke-width]=\"effectiveOuterThickness()\"\r\n stroke-linecap=\"butt\"\r\n [attr.stroke-dasharray]=\"pct + ' 100'\"\r\n />\r\n\r\n @for (segment of segmentPaths(); track segment.path) {\r\n <path\r\n [attr.d]=\"segment.path\"\r\n fill=\"none\"\r\n [attr.stroke]=\"segment.color\"\r\n [attr.stroke-width]=\"effectiveInnerThickness()\"\r\n stroke-linecap=\"butt\"\r\n class=\"gauge-segment\"\r\n />\r\n }\r\n </g>\r\n\r\n @if (showValueLabel()) {\r\n <g #valueGroup [attr.transform]=\"valueTransform()\">\r\n <text\r\n #valueText\r\n class=\"gauge-value-text\"\r\n x=\"0\"\r\n y=\"0\"\r\n text-anchor=\"middle\"\r\n alignment-baseline=\"baseline\"\r\n dy=\"-0.75\"\r\n >\r\n {{ formattedLabel() }}\r\n </text>\r\n </g>\r\n }\r\n\r\n <!-- Hidden reference text used ONLY for width measurement -->\r\n <g style=\"visibility: hidden; pointer-events: none\" aria-hidden=\"true\">\r\n <text\r\n #refText\r\n x=\"0\"\r\n y=\"0\"\r\n text-anchor=\"start\"\r\n dominant-baseline=\"alphabetic\"\r\n >\r\n {{ referenceString() }}\r\n </text>\r\n </g>\r\n</svg>\r\n", styles: [":host{display:block;--gauge-outer-bg: var(--mat-sys-surface-variant, #e0e0e0);--gauge-value-good: var(--mat-sys-tertiary, #10b981);--gauge-value-warning: var(--mat-sys-secondary, #f59e0b);--gauge-value-critical: var(--mat-sys-error, #dc2626)}:host.fit-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.gauge-svg{display:block;margin-inline:auto;max-width:100%;height:auto;shape-rendering:geometricPrecision}.gauge-svg.responsive{max-width:100%;max-height:100%;width:auto;height:auto}.gauge-background{stroke:var(--gauge-outer-bg);transition:stroke .2s ease}.gauge-value{transition:stroke-dasharray .2s ease,stroke .2s ease}.gauge-segment{transition:stroke .2s ease;opacity:.9}.gauge-segment:hover{opacity:1}@media (prefers-reduced-motion: reduce){.gauge-value,.gauge-segment{transition:none}}@media (prefers-contrast: high){.gauge-background{stroke-width:2;stroke:var(--mat-sys-outline, #000000)}.gauge-segment{opacity:1}}@media (prefers-color-scheme: dark){:host{--gauge-outer-bg: #374151}}.gauge-value-text{fill:var(--mat-sys-on-surface-variant, #6c757d);font-family:var(--mat-sys-typescale-body-large-font, \"Roboto\", sans-serif);font-weight:var(--mat-sys-typescale-body-large-weight, 400);transition:fill var(--mat-sys-motion-duration-short2, .2s) var(--mat-sys-motion-easing-standard, ease)}:host.has-background .gauge-value-text{fill:var(--mat-sys-on-surface, #1f1f1f)}:host:hover .gauge-value-text{fill:var(--mat-sys-primary, #6750a4)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1413
1989
  }
1414
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ClockWidgetComponent, decorators: [{
1990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: RadialGaugeComponent, decorators: [{
1415
1991
  type: Component,
1416
- args: [{ selector: 'ngx-dashboard-clock-widget', standalone: true, imports: [DigitalClockComponent, AnalogClockComponent], template: "@if (isDigital) {\r\n <ngx-digital-clock\r\n [timeFormat]=\"state().timeFormat || '24h'\"\r\n [showSeconds]=\"state().showSeconds ?? true\"\r\n [hasBackground]=\"state().hasBackground ?? false\"\r\n />\r\n} @else if (isAnalog) {\r\n <ngx-analog-clock\r\n [hasBackground]=\"state().hasBackground ?? false\"\r\n [showSeconds]=\"state().showSeconds ?? true\"\r\n />\r\n} @else {\r\n<div class=\"svg-wrapper\" [class.has-background]=\"state().hasBackground\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n</div>\r\n}", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.svg-wrapper,.clock-widget{display:flex;align-items:center;justify-content:center;height:100%;width:100%;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.has-background.svg-wrapper,.has-background.clock-widget{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.clock-widget{padding:var(--mat-sys-spacing-4);color:var(--mat-sys-on-surface-variant, #6c757d)}.clock-widget.has-background{color:var(--mat-sys-on-surface, #1f1f1f)}.clock-widget:hover{opacity:.8;color:var(--mat-sys-primary, #6750a4)}.analog-clock{width:min(80cqw,80cqh);aspect-ratio:1/1;position:relative}.clock-face{width:100%;height:100%;border:2px solid currentColor;border-radius:50%;position:relative}.clock-face:before,.clock-face:after{content:\"\";position:absolute;background-color:currentColor;left:50%;transform:translate(-50%)}.clock-face:before{width:2px;height:10%;top:0}.clock-face:after{width:2px;height:10%;bottom:0}.hour-hand,.minute-hand{position:absolute;background-color:currentColor;left:50%;bottom:50%;transform-origin:50% 100%;border-radius:2px}.hour-hand{width:4px;height:25%;transform:translate(-50%) rotate(30deg)}.minute-hand{width:2px;height:35%;transform:translate(-50%) rotate(90deg)}.center-dot{position:absolute;width:8px;height:8px;background-color:currentColor;border-radius:50%;top:50%;left:50%;transform:translate(-50%,-50%)}.svg-wrapper{overflow:hidden}.svg-placeholder{width:min(80cqw,80cqh);aspect-ratio:1/1;opacity:.3;transition:transform .3s ease-in-out,opacity .3s ease;transform-origin:center center}.svg-placeholder ::ng-deep svg{width:100%;height:100%;display:block}.svg-placeholder ::ng-deep svg .clock-face{stroke:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-hour-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-minute-hand{fill:var(--mat-sys-on-surface, #1d1b20)}.svg-placeholder ::ng-deep svg .clock-second-hand{fill:var(--mat-sys-primary, #6750a4)}.has-background .svg-placeholder ::ng-deep svg circle{fill:var(--mat-sys-surface, #fffbfe)}\n"] }]
1992
+ args: [{ selector: 'ngx-radial-gauge', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1993
+ role: 'meter',
1994
+ '[attr.aria-label]': 'ariaLabel()',
1995
+ '[attr.aria-valuemin]': 'min()',
1996
+ '[attr.aria-valuemax]': 'max()',
1997
+ '[attr.aria-valuenow]': 'clampedValue()',
1998
+ '[attr.aria-valuetext]': 'formattedLabel()',
1999
+ '[attr.aria-labelledby]': 'titleId',
2000
+ '[attr.aria-describedby]': 'descId',
2001
+ '[class.fit-container]': 'fitToContainer()',
2002
+ '[class.has-background]': 'hasBackground()',
2003
+ }, template: "@let w = svgWidth(); @let h = svgHeight(); @let cy = centerY(); @let pct =\r\npercent();\r\n\r\n<svg\r\n [attr.width]=\"fitToContainer() ? null : w\"\r\n [attr.height]=\"fitToContainer() ? null : h\"\r\n [attr.viewBox]=\"'0 0 ' + w + ' ' + h\"\r\n [class.responsive]=\"fitToContainer()\"\r\n class=\"gauge-svg\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n>\r\n <title [attr.id]=\"titleId\">{{ title() }}</title>\r\n @if (description()) {\r\n <desc [attr.id]=\"descId\">{{ description() }}</desc>\r\n }\r\n\r\n <defs>\r\n <clipPath [attr.id]=\"clipId\">\r\n <!-- Give a tiny extra room equal to half of the outer stroke to avoid anti-alias cutoff at the baseline -->\r\n <rect\r\n x=\"0\"\r\n y=\"0\"\r\n [attr.width]=\"w\"\r\n [attr.height]=\"cy + effectiveOuterThickness() / 2\"\r\n />\r\n </clipPath>\r\n </defs>\r\n\r\n <g [attr.clip-path]=\"'url(#' + clipId + ')'\">\r\n <path\r\n [attr.d]=\"backgroundArcPath()\"\r\n pathLength=\"100\"\r\n fill=\"none\"\r\n class=\"gauge-background\"\r\n [attr.stroke-width]=\"effectiveOuterThickness()\"\r\n stroke-linecap=\"butt\"\r\n />\r\n\r\n <path\r\n [attr.d]=\"backgroundArcPath()\"\r\n pathLength=\"100\"\r\n fill=\"none\"\r\n class=\"gauge-value\"\r\n [attr.stroke]=\"valueColor()\"\r\n [attr.stroke-width]=\"effectiveOuterThickness()\"\r\n stroke-linecap=\"butt\"\r\n [attr.stroke-dasharray]=\"pct + ' 100'\"\r\n />\r\n\r\n @for (segment of segmentPaths(); track segment.path) {\r\n <path\r\n [attr.d]=\"segment.path\"\r\n fill=\"none\"\r\n [attr.stroke]=\"segment.color\"\r\n [attr.stroke-width]=\"effectiveInnerThickness()\"\r\n stroke-linecap=\"butt\"\r\n class=\"gauge-segment\"\r\n />\r\n }\r\n </g>\r\n\r\n @if (showValueLabel()) {\r\n <g #valueGroup [attr.transform]=\"valueTransform()\">\r\n <text\r\n #valueText\r\n class=\"gauge-value-text\"\r\n x=\"0\"\r\n y=\"0\"\r\n text-anchor=\"middle\"\r\n alignment-baseline=\"baseline\"\r\n dy=\"-0.75\"\r\n >\r\n {{ formattedLabel() }}\r\n </text>\r\n </g>\r\n }\r\n\r\n <!-- Hidden reference text used ONLY for width measurement -->\r\n <g style=\"visibility: hidden; pointer-events: none\" aria-hidden=\"true\">\r\n <text\r\n #refText\r\n x=\"0\"\r\n y=\"0\"\r\n text-anchor=\"start\"\r\n dominant-baseline=\"alphabetic\"\r\n >\r\n {{ referenceString() }}\r\n </text>\r\n </g>\r\n</svg>\r\n", styles: [":host{display:block;--gauge-outer-bg: var(--mat-sys-surface-variant, #e0e0e0);--gauge-value-good: var(--mat-sys-tertiary, #10b981);--gauge-value-warning: var(--mat-sys-secondary, #f59e0b);--gauge-value-critical: var(--mat-sys-error, #dc2626)}:host.fit-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.gauge-svg{display:block;margin-inline:auto;max-width:100%;height:auto;shape-rendering:geometricPrecision}.gauge-svg.responsive{max-width:100%;max-height:100%;width:auto;height:auto}.gauge-background{stroke:var(--gauge-outer-bg);transition:stroke .2s ease}.gauge-value{transition:stroke-dasharray .2s ease,stroke .2s ease}.gauge-segment{transition:stroke .2s ease;opacity:.9}.gauge-segment:hover{opacity:1}@media (prefers-reduced-motion: reduce){.gauge-value,.gauge-segment{transition:none}}@media (prefers-contrast: high){.gauge-background{stroke-width:2;stroke:var(--mat-sys-outline, #000000)}.gauge-segment{opacity:1}}@media (prefers-color-scheme: dark){:host{--gauge-outer-bg: #374151}}.gauge-value-text{fill:var(--mat-sys-on-surface-variant, #6c757d);font-family:var(--mat-sys-typescale-body-large-font, \"Roboto\", sans-serif);font-weight:var(--mat-sys-typescale-body-large-weight, 400);transition:fill var(--mat-sys-motion-duration-short2, .2s) var(--mat-sys-motion-easing-standard, ease)}:host.has-background .gauge-value-text{fill:var(--mat-sys-on-surface, #1f1f1f)}:host:hover .gauge-value-text{fill:var(--mat-sys-primary, #6750a4)}\n"] }]
1417
2004
  }], ctorParameters: () => [] });
1418
2005
 
2006
+ // radial-gauge-widget.metadata.ts
2007
+ const svgIcon = `
2008
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 55" fill="currentColor">
2009
+ <defs>
2010
+ <clipPath id="gauge-clip"><rect x="0" y="0" width="100" height="52"/></clipPath>
2011
+
2012
+ <!-- Outer arc geometry (radius 40, stroke 8) -->
2013
+ <path id="outerArc" d="M 10 50 A 40 40 0 0 1 90 50" pathLength="100"/>
2014
+
2015
+ <!-- Inner arc geometry (radius 31) -->
2016
+ <path id="innerArc" d="M 19 50 A 31 31 0 0 1 81 50" pathLength="100"/>
2017
+ </defs>
2018
+
2019
+ <g clip-path="url(#gauge-clip)" stroke="currentColor" fill="none" stroke-linecap="butt">
2020
+ <!-- Outer background arc -->
2021
+ <use href="#outerArc" stroke-width="8" opacity="0.2"/>
2022
+
2023
+ <!-- Value arc: 65% -->
2024
+ <use href="#outerArc" stroke-width="8" stroke-dasharray="65 100"/>
2025
+
2026
+ <!-- Inner legend segments (single geometry with dash windows) -->
2027
+ <!-- 0–60% -->
2028
+ <use href="#innerArc" stroke-width="4" opacity="0.2"
2029
+ stroke-dasharray="60 100" stroke-dashoffset="0"/>
2030
+ <!-- 60–80% -->
2031
+ <use href="#innerArc" stroke-width="4" opacity="0.4"
2032
+ stroke-dasharray="20 100" stroke-dashoffset="60"/>
2033
+ <!-- 0–100% (full half-circle), same color as value arc -->
2034
+ <use href="#innerArc" stroke-width="4"
2035
+ stroke-dasharray="100 100" stroke-dashoffset="0"/>
2036
+ <!-- (Alternatively, you can omit dash attributes entirely on this one:
2037
+ <use href="#innerArc" stroke-width="4"/> ) -->
2038
+ </g>
2039
+ </svg>
2040
+ `;
2041
+
2042
+ class RadialGaugeStateDialogComponent {
2043
+ data = inject(MAT_DIALOG_DATA);
2044
+ dialogRef = inject((MatDialogRef));
2045
+ localState = {
2046
+ value: this.data.value ?? 50,
2047
+ colorProfile: this.data.colorProfile ?? 'dynamic',
2048
+ active: this.data.active ?? false,
2049
+ hasBackground: this.data.hasBackground ?? true,
2050
+ showValueLabel: this.data.showValueLabel ?? true,
2051
+ };
2052
+ onCancel() {
2053
+ this.dialogRef.close();
2054
+ }
2055
+ onSave() {
2056
+ this.dialogRef.close(this.localState);
2057
+ }
2058
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: RadialGaugeStateDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2059
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.2.1", type: RadialGaugeStateDialogComponent, isStandalone: true, selector: "lib-radial-gauge-state-dialog", ngImport: i0, template: `
2060
+ <h2 mat-dialog-title>Radial Gauge Settings</h2>
2061
+ <mat-dialog-content>
2062
+ <mat-form-field>
2063
+ <mat-label>Value (0-100)</mat-label>
2064
+ <input
2065
+ matInput
2066
+ type="number"
2067
+ [(ngModel)]="localState.value"
2068
+ min="0"
2069
+ max="100"
2070
+ />
2071
+ </mat-form-field>
2072
+
2073
+ <div class="section">
2074
+ <h4>Color Profile</h4>
2075
+ <mat-radio-group [(ngModel)]="localState.colorProfile">
2076
+ <mat-radio-button value="dynamic">Dynamic (Theme Colors)</mat-radio-button>
2077
+ <mat-radio-button value="static">Static (Performance Colors)</mat-radio-button>
2078
+ </mat-radio-group>
2079
+ </div>
2080
+
2081
+ <div class="toggle-section">
2082
+ <mat-slide-toggle [(ngModel)]="localState.active">
2083
+ Active Display
2084
+ </mat-slide-toggle>
2085
+ <p class="toggle-description">Display live gauge instead of passive icon</p>
2086
+ </div>
2087
+
2088
+ <div class="toggle-section">
2089
+ <mat-slide-toggle [(ngModel)]="localState.hasBackground">
2090
+ Background
2091
+ </mat-slide-toggle>
2092
+ <p class="toggle-description">Add a background color to the widget</p>
2093
+ </div>
2094
+
2095
+ <div class="toggle-section">
2096
+ <mat-slide-toggle [(ngModel)]="localState.showValueLabel">
2097
+ Show Value Label
2098
+ </mat-slide-toggle>
2099
+ <p class="toggle-description">Display numeric value in gauge center</p>
2100
+ </div>
2101
+ </mat-dialog-content>
2102
+
2103
+ <mat-dialog-actions align="end">
2104
+ <button mat-button (click)="onCancel()">Cancel</button>
2105
+ <button mat-flat-button (click)="onSave()">Save</button>
2106
+ </mat-dialog-actions>
2107
+ `, isInline: true, styles: ["mat-dialog-content{display:block;overflow-y:auto;overflow-x:hidden}mat-form-field{width:100%;display:block;margin-bottom:1rem}.section{margin-bottom:1.5rem}.section h4{margin:0 0 .5rem;font-size:.875rem;font-weight:500;color:var(--mat-sys-on-surface, #1f1f1f)}mat-radio-group{display:flex;flex-direction:column;gap:.5rem}.toggle-section{display:flex;align-items:center;gap:.75rem;margin-bottom:.5rem}.toggle-description{margin:0;flex:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i3$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i3$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
2108
+ }
2109
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: RadialGaugeStateDialogComponent, decorators: [{
2110
+ type: Component,
2111
+ args: [{ selector: 'lib-radial-gauge-state-dialog', standalone: true, imports: [
2112
+ CommonModule,
2113
+ MatDialogModule,
2114
+ MatButtonModule,
2115
+ MatFormFieldModule,
2116
+ MatInputModule,
2117
+ MatSlideToggleModule,
2118
+ MatRadioModule,
2119
+ FormsModule,
2120
+ ], template: `
2121
+ <h2 mat-dialog-title>Radial Gauge Settings</h2>
2122
+ <mat-dialog-content>
2123
+ <mat-form-field>
2124
+ <mat-label>Value (0-100)</mat-label>
2125
+ <input
2126
+ matInput
2127
+ type="number"
2128
+ [(ngModel)]="localState.value"
2129
+ min="0"
2130
+ max="100"
2131
+ />
2132
+ </mat-form-field>
2133
+
2134
+ <div class="section">
2135
+ <h4>Color Profile</h4>
2136
+ <mat-radio-group [(ngModel)]="localState.colorProfile">
2137
+ <mat-radio-button value="dynamic">Dynamic (Theme Colors)</mat-radio-button>
2138
+ <mat-radio-button value="static">Static (Performance Colors)</mat-radio-button>
2139
+ </mat-radio-group>
2140
+ </div>
2141
+
2142
+ <div class="toggle-section">
2143
+ <mat-slide-toggle [(ngModel)]="localState.active">
2144
+ Active Display
2145
+ </mat-slide-toggle>
2146
+ <p class="toggle-description">Display live gauge instead of passive icon</p>
2147
+ </div>
2148
+
2149
+ <div class="toggle-section">
2150
+ <mat-slide-toggle [(ngModel)]="localState.hasBackground">
2151
+ Background
2152
+ </mat-slide-toggle>
2153
+ <p class="toggle-description">Add a background color to the widget</p>
2154
+ </div>
2155
+
2156
+ <div class="toggle-section">
2157
+ <mat-slide-toggle [(ngModel)]="localState.showValueLabel">
2158
+ Show Value Label
2159
+ </mat-slide-toggle>
2160
+ <p class="toggle-description">Display numeric value in gauge center</p>
2161
+ </div>
2162
+ </mat-dialog-content>
2163
+
2164
+ <mat-dialog-actions align="end">
2165
+ <button mat-button (click)="onCancel()">Cancel</button>
2166
+ <button mat-flat-button (click)="onSave()">Save</button>
2167
+ </mat-dialog-actions>
2168
+ `, styles: ["mat-dialog-content{display:block;overflow-y:auto;overflow-x:hidden}mat-form-field{width:100%;display:block;margin-bottom:1rem}.section{margin-bottom:1.5rem}.section h4{margin:0 0 .5rem;font-size:.875rem;font-weight:500;color:var(--mat-sys-on-surface, #1f1f1f)}mat-radio-group{display:flex;flex-direction:column;gap:.5rem}.toggle-section{display:flex;align-items:center;gap:.75rem;margin-bottom:.5rem}.toggle-description{margin:0;flex:1}\n"] }]
2169
+ }] });
2170
+
2171
+ // radial-gauge-widget.component.ts
2172
+ class RadialGaugeWidgetComponent {
2173
+ static metadata = {
2174
+ widgetTypeid: '@default/radial-gauge-widget',
2175
+ name: 'Radial Gauge',
2176
+ description: 'A semi-circular gauge indicator',
2177
+ svgIcon,
2178
+ };
2179
+ #dialog = inject(MatDialog);
2180
+ #sanitizer = inject(DomSanitizer);
2181
+ safeSvgIcon = this.#sanitizer.bypassSecurityTrustHtml(svgIcon);
2182
+ state = signal({
2183
+ value: 50,
2184
+ colorProfile: 'dynamic',
2185
+ active: false,
2186
+ hasBackground: true,
2187
+ showValueLabel: true,
2188
+ }, ...(ngDevMode ? [{ debugName: "state" }] : []));
2189
+ segments = computed(() => {
2190
+ const profile = this.state().colorProfile || 'dynamic';
2191
+ if (profile === 'static') {
2192
+ // Static performance segments (like CPU usage example)
2193
+ return [
2194
+ { from: 0, to: 25, color: '#dc2626' }, // Poor - red
2195
+ { from: 25, to: 50, color: '#f59e0b' }, // Fair - orange
2196
+ { from: 50, to: 75, color: '#3b82f6' }, // Good - blue
2197
+ { from: 75, to: 100, color: '#10b981' }, // Excellent - green
2198
+ ];
2199
+ }
2200
+ else {
2201
+ // Dynamic theme-aware segments (like demo gauge preview)
2202
+ return [
2203
+ { from: 0, to: 60, color: 'var(--mat-sys-error)' },
2204
+ { from: 60, to: 80, color: 'var(--mat-sys-secondary)' },
2205
+ { from: 80, to: 100, color: 'var(--mat-sys-tertiary)' },
2206
+ ];
2207
+ }
2208
+ }, ...(ngDevMode ? [{ debugName: "segments" }] : []));
2209
+ dashboardSetState(state) {
2210
+ if (state) {
2211
+ this.state.update((current) => ({
2212
+ ...current,
2213
+ ...state,
2214
+ }));
2215
+ }
2216
+ }
2217
+ dashboardGetState() {
2218
+ return this.state();
2219
+ }
2220
+ dashboardEditState() {
2221
+ const dialogRef = this.#dialog.open(RadialGaugeStateDialogComponent, {
2222
+ data: this.state(),
2223
+ width: '400px',
2224
+ maxWidth: '90vw',
2225
+ disableClose: false,
2226
+ autoFocus: false,
2227
+ });
2228
+ dialogRef.afterClosed().subscribe((result) => {
2229
+ if (result) {
2230
+ this.state.set(result);
2231
+ }
2232
+ });
2233
+ }
2234
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: RadialGaugeWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2235
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: RadialGaugeWidgetComponent, isStandalone: true, selector: "ngx-dashboard-radial-gauge-widget", ngImport: i0, template: "<!-- radial-gauge-widget.component.html -->\r\n<div class=\"widget-container\" [class.has-background]=\"state().hasBackground\">\r\n @if (state().active) {\r\n <!-- Active mode: Show live gauge -->\r\n <div class=\"gauge-container\">\r\n <ngx-radial-gauge\r\n [value]=\"state().value || 0\"\r\n [min]=\"0\"\r\n [max]=\"100\"\r\n [fitToContainer]=\"true\"\r\n [responsiveMode]=\"true\"\r\n [segments]=\"segments()\"\r\n [outerThickness]=\"24\"\r\n [innerThickness]=\"8\"\r\n [gap]=\"4\"\r\n [segmentGapPx]=\"2\"\r\n [labelReference]=\"'00000'\"\r\n [referenceGlyph]=\"'0'\"\r\n [hasBackground]=\"state().hasBackground || false\"\r\n [showValueLabel]=\"state().showValueLabel ?? true\"\r\n />\r\n </div>\r\n } @else {\r\n <!-- Passive mode: Show static icon -->\r\n <div class=\"icon-container\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.widget-container{height:100%;width:100%;display:flex;align-items:center;justify-content:center;position:relative;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.widget-container.has-background{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.gauge-container{height:100%;width:100%;display:flex;align-items:center;justify-content:center;position:relative;box-sizing:border-box}ngx-radial-gauge{width:100%;height:100%;min-height:0;flex:1}.icon-container{height:100%;width:100%;display:flex;align-items:center;justify-content:center;position:relative;box-sizing:border-box}.svg-placeholder{width:80%;height:80%;display:flex;align-items:center;justify-content:center;color:var(--mat-sys-on-surface-variant, #6c757d);transition:color .2s ease}.svg-placeholder :deep(svg){width:100%;height:100%;max-width:100px;max-height:100px;fill:currentColor}.has-background .svg-placeholder{color:var(--mat-sys-on-surface, #1f1f1f)}.widget-container:hover .svg-placeholder{color:var(--mat-sys-primary, #6750a4)}\n"], dependencies: [{ kind: "component", type: RadialGaugeComponent, selector: "ngx-radial-gauge", inputs: ["value", "min", "max", "segments", "title", "description", "segmentGapPx", "hasBackground", "showValueLabel", "size", "fitToContainer", "containerPadding", "responsiveMode", "sizeToThicknessRatio", "responsiveProportions", "outerThickness", "innerThickness", "gap", "labelReference", "referenceGlyph", "labelPadding", "baselineSafety"] }] });
2236
+ }
2237
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: RadialGaugeWidgetComponent, decorators: [{
2238
+ type: Component,
2239
+ args: [{ selector: 'ngx-dashboard-radial-gauge-widget', imports: [RadialGaugeComponent], template: "<!-- radial-gauge-widget.component.html -->\r\n<div class=\"widget-container\" [class.has-background]=\"state().hasBackground\">\r\n @if (state().active) {\r\n <!-- Active mode: Show live gauge -->\r\n <div class=\"gauge-container\">\r\n <ngx-radial-gauge\r\n [value]=\"state().value || 0\"\r\n [min]=\"0\"\r\n [max]=\"100\"\r\n [fitToContainer]=\"true\"\r\n [responsiveMode]=\"true\"\r\n [segments]=\"segments()\"\r\n [outerThickness]=\"24\"\r\n [innerThickness]=\"8\"\r\n [gap]=\"4\"\r\n [segmentGapPx]=\"2\"\r\n [labelReference]=\"'00000'\"\r\n [referenceGlyph]=\"'0'\"\r\n [hasBackground]=\"state().hasBackground || false\"\r\n [showValueLabel]=\"state().showValueLabel ?? true\"\r\n />\r\n </div>\r\n } @else {\r\n <!-- Passive mode: Show static icon -->\r\n <div class=\"icon-container\">\r\n <div class=\"svg-placeholder\" [innerHTML]=\"safeSvgIcon\"></div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;container-type:size;width:100%;height:100%;overflow:hidden}.widget-container{height:100%;width:100%;display:flex;align-items:center;justify-content:center;position:relative;box-sizing:border-box;transition:background-color var(--mat-sys-motion-duration-medium2) var(--mat-sys-motion-easing-standard)}.widget-container.has-background{background-color:var(--mat-sys-surface-container-high);border-radius:4px}.gauge-container{height:100%;width:100%;display:flex;align-items:center;justify-content:center;position:relative;box-sizing:border-box}ngx-radial-gauge{width:100%;height:100%;min-height:0;flex:1}.icon-container{height:100%;width:100%;display:flex;align-items:center;justify-content:center;position:relative;box-sizing:border-box}.svg-placeholder{width:80%;height:80%;display:flex;align-items:center;justify-content:center;color:var(--mat-sys-on-surface-variant, #6c757d);transition:color .2s ease}.svg-placeholder :deep(svg){width:100%;height:100%;max-width:100px;max-height:100px;fill:currentColor}.has-background .svg-placeholder{color:var(--mat-sys-on-surface, #1f1f1f)}.widget-container:hover .svg-placeholder{color:var(--mat-sys-primary, #6750a4)}\n"] }]
2240
+ }] });
2241
+
1419
2242
  /*
1420
2243
  * Public API Surface of ngx-dashboard-widgets
1421
2244
  */
@@ -1424,5 +2247,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1424
2247
  * Generated bundle index. Do not edit.
1425
2248
  */
1426
2249
 
1427
- export { ArrowWidgetComponent, ClockWidgetComponent, LabelWidgetComponent, ResponsiveTextDirective };
2250
+ export { ArrowWidgetComponent, ClockWidgetComponent, LabelWidgetComponent, RadialGaugeComponent, RadialGaugeWidgetComponent, ResponsiveTextDirective };
1428
2251
  //# sourceMappingURL=dragonworks-ngx-dashboard-widgets.mjs.map