Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | 1x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 9x 11x 6x 10x 10x 10x 10x 10x 6x 9x 9x 6x 6x 6x 6x 6x 7x 2x 2x 2x 2x 5x 7x 2x 2x 7x | /** * Copyright (c) Siemens 2016 - 2025 * SPDX-License-Identifier: MIT */ import { NgClass } from '@angular/common'; import { booleanAttribute, ChangeDetectionStrategy, Component, computed, ElementRef, inject, input, OnChanges, OnDestroy, signal, SimpleChanges, viewChild } from '@angular/core'; import { BlinkService, EntityStatusType, StatusIcon } from '@siemens/element-ng/common'; import { addIcons, elementRight4, SiIconComponent, STATUS_ICON_CONFIG } from '@siemens/element-ng/icon'; import { SiTranslatePipe, TranslatableString } from '@siemens/element-translate-ng/translate'; import { Observable, Subscription } from 'rxjs'; @Component({ selector: 'si-circle-status', imports: [NgClass, SiIconComponent, SiTranslatePipe], templateUrl: './si-circle-status.component.html', styleUrl: './si-circle-status.component.scss', changeDetection: ChangeDetectionStrategy.OnPush }) export class SiCircleStatusComponent implements OnChanges, OnDestroy { private readonly statusIcons = inject(STATUS_ICON_CONFIG); /** * The status (success, info, warning, danger) to be visualized. */ readonly status = input<EntityStatusType>(); /* DO NOT REMOVE: Even though the input is marked as deprecated, the core-team decided not to remove the input. The possibility to have custom color is often requested by projects, so we keep it. however in order to discourage it's use, we keep it marked deprecated. */ /** * A custom color (e.g. `#fefefe`) for exceptional cases. * @deprecated use the semantic `status` input instead. */ readonly color = input<string>(); /** * Set a domain type icon (e.g. `element-door`) for which the status shall be shown. * Leave undefined for visualizing the status without an icon. */ readonly icon = input<string>(); /** * Set the size using either regular or small only works when used together with `icon` * * @defaultValue 'regular' */ readonly size = input<'regular' | 'small'>('regular'); /** * event direction is out * * @defaultValue false */ readonly eventOut = input(false, { transform: booleanAttribute }); /** * Custom icon class for event out */ readonly eventIcon = input<string>(); /** * Whether the status should appear with a pulsing circle around the badge. * * @defaultValue false */ readonly blink = input(false, { transform: booleanAttribute }); /** * Blink pulse generator for synchronized blinking with other components */ readonly blinkPulse = input<Observable<boolean>>(); /** * Aria label for icon and status combo. Needed for a11y */ readonly ariaLabel = input<TranslatableString>(); protected readonly backgroundClass = computed(() => this.statusIcon()?.background ?? ''); protected readonly theAriaLabel = computed(() => this.ariaLabel() ?? this.autoLabel()); protected readonly autoLabel = computed(() => { const status = this.status(); const statusName = status && this.statusIcons[status] ? status : 'none'; const direction = this.eventOut() ? ' out' : ''; const iconName = this.icon()?.replace(/^element-{0,1}(.+)/, '$1 ') ?? ''; return `${iconName.toLocaleLowerCase()}${ this.status() && this.icon() ? 'in ' : '' }status ${statusName}${direction}`; }); protected readonly statusIcon = computed<StatusIcon | undefined>(() => { const status = this.status(); return status ? this.statusIcons[status] : undefined; }); protected readonly blinkOn = signal(false); protected readonly contrastFix = signal(false); protected readonly icons = addIcons({ elementRight4 }); private blinkSubs?: Subscription; private readonly bg = viewChild.required<ElementRef>('bg'); private blinkService = inject(BlinkService); ngOnChanges(changes: SimpleChanges): void { if (this.blinkService && changes.blink) { this.blinkSubs?.unsubscribe(); if (this.blink()) { const pulse = this.blinkPulse() ?? this.blinkService.pulse$; this.blinkSubs = pulse.subscribe(onOff => { this.blinkOn.set(onOff); }); } else E{ this.blinkOn.set(false); } } if (changes.color || changes.blink) { queueMicrotask(() => { this.contrastFix.set(!!this.color() && this.blink() && this.calculateContrastFix()); }); } } ngOnDestroy(): void { this.blinkSubs?.unsubscribe(); } private calculateContrastFix(): boolean { // see https://www.w3.org/TR/AERT/#color-contrast const rgb = getComputedStyle(this.bg().nativeElement) .backgroundColor?.match(/\d+/g) ?.map(v => +v); return !!rgb && Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000) <= 128; } } |