• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atinc / ngx-tethys / 5883ea4a-4016-490e-aa92-276202e661fd

21 May 2025 03:22AM UTC coverage: 90.254% (+0.002%) from 90.252%
5883ea4a-4016-490e-aa92-276202e661fd

push

circleci

web-flow
refactor(switch): migrate to signal for switch #TINFR-1776 (#3409)

5560 of 6831 branches covered (81.39%)

Branch coverage included in aggregate %.

25 of 26 new or added lines in 1 file covered. (96.15%)

1 existing line in 1 file now uncovered.

13702 of 14511 relevant lines covered (94.42%)

900.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.12
/src/switch/switch.component.ts
1
import { NgClass } from '@angular/common';
2
import {
3
    ChangeDetectionStrategy,
4
    ChangeDetectorRef,
5
    Component,
6
    ElementRef,
7
    forwardRef,
8
    inject,
9
    viewChild,
1✔
10
    input,
1✔
11
    computed,
12
    signal,
13
    output,
14
    effect
15
} from '@angular/core';
16
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
1✔
17
import { TabIndexDisabledControlValueAccessorMixin } from 'ngx-tethys/core';
18
import { coerceBooleanProperty } from 'ngx-tethys/util';
383✔
19

20
const supportedTypes: string[] = ['primary', 'info', 'warning', 'danger'];
21

327✔
22
const supportedSizes: string[] = ['', 'sm', 'xs'];
327✔
23

327✔
24
/**
327✔
25
 * 开关组件
327✔
26
 * @name thy-switch
327✔
27
 * @order 10
327✔
28
 */
327✔
29
@Component({
327✔
30
    selector: 'thy-switch',
326✔
31
    templateUrl: './switch.component.html',
4✔
32
    changeDetection: ChangeDetectionStrategy.OnPush,
33
    providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ThySwitch), multi: true }],
34
    imports: [NgClass],
322✔
35
    host: { class: 'thy-switch', '[class.thy-switch-xs]': 'size() === "xs"', '[class.thy-switch-sm]': 'size() === "sm"' }
36
})
37
export class ThySwitch extends TabIndexDisabledControlValueAccessorMixin implements ControlValueAccessor {
327✔
38
    /**
324!
UNCOV
39
     * 类型,目前分为: 'primary' |'info' | 'warning' | 'danger'
×
40
     */
41
    readonly thyType = input<string>('primary');
42

324✔
43
    /**
44
     * 大小
45
     * @type xs | sm | md
327✔
46
     * @default md
331✔
47
     */
331✔
48
    readonly thySize = input<string>('');
2✔
49

50
    /**
331✔
51
     * 是否属于禁用状态
3✔
52
     */
3!
NEW
53
    readonly inputDisabled = input(false, { transform: coerceBooleanProperty, alias: `thyDisabled` });
×
54

55
    /**
56
     * 是否加载中
331✔
57
     */
58
    readonly thyLoading = input(false, { transform: coerceBooleanProperty });
327✔
59

1✔
60
    /**
1✔
61
     * 数据变化的回调事件,即将被弃用,请使用 ngModelChange
1✔
62
     * @deprecated
1✔
63
     */
1✔
64
    thyChange = output<Event>();
65

66
    model = signal<boolean>(false);
67

68
    disabled = signal(false);
69

70
    get thyDisabled() {
71
        return this.disabled() as boolean;
327✔
72
    }
327✔
73

327✔
74
    readonly type = computed(() => {
327✔
75
        if (!supportedTypes.includes(this.thyType())) {
327✔
76
            return 'primary';
325✔
77
        } else {
78
            return this.thyType();
79
        }
80
    });
646✔
81

646✔
82
    readonly size = computed(() => {
83
        if (!supportedSizes.includes(this.thySize())) {
84
            return '';
323✔
85
        } else {
86
            return this.thySize();
87
        }
323✔
88
    });
89

90
    readonly classNames = computed(() => {
328✔
91
        const classList = [`thy-switch-${this.type()}`];
92
        if (this.size()) {
93
            classList.push(`thy-switch-${this.size()}`);
1✔
94
        }
1✔
95
        if (this.disabled() || this.thyLoading()) {
1✔
96
            classList.push(`thy-switch-disabled`);
1✔
97
            if (this.model()) {
98
                classList.push(`thy-switch-disabled-true`);
1✔
99
            }
1✔
100
        }
101
        return classList;
102
    });
103

104
    readonly loadingCircle = computed(() => {
105
        const svgSize: Record<string, number> = { xs: 12, sm: 16 };
106
        const circleSize = svgSize[this.size()] ?? 20;
107
        const centerPoint = circleSize / 2;
108
        const r = circleSize / 4;
1✔
109
        return {
110
            viewBox: `0 0 ${circleSize} ${circleSize}`,
111
            cx: centerPoint,
112
            cy: centerPoint,
113
            r: r,
327✔
114
            dasharray: `${2 * Math.PI * r * 0.75} ${2 * Math.PI * r * 0.25}`
115
        };
116
    });
117

118
    onModelChange: Function = () => {};
119

120
    onModelTouched: Function = () => {};
121

122
    readonly switchElementRef = viewChild<string, ElementRef<HTMLElement>>('switch', { read: ElementRef<HTMLElement> });
123

124
    private cdr = inject(ChangeDetectorRef);
125

126
    constructor() {
127
        super();
128

129
        effect(() => {
130
            this.disabled.set(this.inputDisabled());
131
        });
132
    }
133

134
    writeValue(value: boolean) {
135
        this.model.set(value);
136
        this.cdr.markForCheck();
137
    }
138

139
    registerOnChange(fn: Function): void {
140
        this.onModelChange = fn;
141
    }
142

143
    registerOnTouched(fn: Function): void {
144
        this.onModelTouched = fn;
145
    }
146

147
    setDisabledState(isDisabled: boolean): void {
148
        this.disabled.set(isDisabled);
149
    }
150

151
    toggle(event: Event) {
152
        this.model.set(!this.model());
153
        this.onModelChange(this.model());
154
        this.onModelTouched();
155
        this.thyChange?.emit(event);
156
    }
157
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc