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

atinc / ngx-tethys / #102

26 May 2026 08:11AM UTC coverage: 91.111% (+0.7%) from 90.407%
#102

push

web-flow
build: bump docgeni to 2.8.0-next.5 (#3809)

4571 of 5491 branches covered (83.25%)

Branch coverage included in aggregate %.

13141 of 13949 relevant lines covered (94.21%)

966.75 hits per line

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

93.55
/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,
10
    input,
11
    computed,
12
    signal,
13
    output,
14
    effect
15
} from '@angular/core';
16
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
17
import { TabIndexDisabledControlValueAccessorMixin } from 'ngx-tethys/core';
18
import { coerceBooleanProperty } from 'ngx-tethys/util';
19

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

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

24
/**
25
 * 开关组件
26
 * @name thy-switch
27
 * @order 10
28
 */
29
@Component({
30
    selector: 'thy-switch',
31
    templateUrl: './switch.component.html',
32
    changeDetection: ChangeDetectionStrategy.OnPush,
33
    providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ThySwitch), multi: true }],
327✔
34
    imports: [NgClass],
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 {
1✔
38
    /**
39
     * 类型,目前分为: 'primary' |'info' | 'warning' | 'danger'
40
     */
41
    readonly thyType = input<string>('primary');
327✔
42

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

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

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

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

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

68
    disabled = signal(false);
327✔
69

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

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

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

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

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

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

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

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

124
    private cdr = inject(ChangeDetectorRef);
327✔
125

126
    constructor() {
127
        super();
327✔
128

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

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

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

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

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

151
    toggle(event: Event) {
152
        this.model.set(!this.model());
1✔
153
        this.onModelChange(this.model());
1✔
154
        this.onModelTouched();
1✔
155
        this.thyChange?.emit(event);
1✔
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