• 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

94.12
/src/input/input.component.ts
1
import { take } from 'rxjs/operators';
2

3
import { NgTemplateOutlet } from '@angular/common';
4
import {
5
    Component,
6
    ElementRef,
7
    forwardRef,
8
    NgZone,
9
    OnInit,
10
    TemplateRef,
11
    ViewEncapsulation,
12
    inject,
13
    input,
14
    effect,
15
    signal,
16
    output,
17
    contentChild,
18
    afterNextRender
19
} from '@angular/core';
20
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
21
import { ThyIcon } from 'ngx-tethys/icon';
22
import { ThyAutofocusDirective } from 'ngx-tethys/shared';
23
import { ThyInputDirective, ThyInputSize } from './input.directive';
24
import { coerceBooleanProperty } from 'ngx-tethys/util';
25

1✔
26
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
27
    provide: NG_VALUE_ACCESSOR,
28✔
28
    useExisting: forwardRef(() => ThyInput),
29
    multi: true
30
};
31

1✔
32
const noop = () => {};
33

1✔
34
const password = 'password';
35

36
/**
37
 * 内部集成输入框组件,建议 thy-input-group 和 thyInput 组合使用
38
 * @name thy-input
39
 * @order 50
40
 */
41
@Component({
42
    selector: 'thy-input',
43
    templateUrl: './input.component.html',
44
    providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],
45
    encapsulation: ViewEncapsulation.None,
46
    host: {
47
        class: 'thy-input form-control',
48
        '[class.form-control-active]': 'focused()',
49
        '[class.disabled]': 'disabled()'
50
    },
51
    imports: [NgTemplateOutlet, ThyInputDirective, ThyAutofocusDirective, FormsModule, ThyIcon]
52
})
1✔
53
export class ThyInput implements ControlValueAccessor, OnInit {
42✔
54
    private ngZone = inject(NgZone);
42✔
55
    private elementRef = inject(ElementRef);
56

57
    /**
58
     * Placeholder
59
     */
42✔
60
    readonly placeholder = input('');
61

62
    /**
63
     * 输入框大小
64
     * @type 'xs' | 'sm' | 'md' | 'default' | 'lg'
65
     * @default default
66
     */
42✔
67
    readonly thySize = input<ThyInputSize>();
68

69
    /**
70
     * 是否自动聚焦
71
     */
42✔
72
    readonly thyAutofocus = input(false, { transform: coerceBooleanProperty });
73

74
    /**
75
     * 输入框类型
76
     * @type 'number' | 'input'
77
     */
42✔
78
    readonly thyType = input<string>();
79

80
    /**
81
     * @deprecated please use thyType
82
     */
42✔
83
    readonly _type = input<string>(undefined, { alias: 'type' });
84

85
    /**
86
     * 输入 Label 文本
87
     */
42✔
88
    readonly thyLabelText = input<string>();
89

90
    /**
91
     * 是否只读
92
     */
42✔
93
    readonly readonly = input(false, { transform: coerceBooleanProperty });
94

95
    /**
96
     * focus 聚焦事件
97
     */
42✔
98
    readonly focus = output<Event>();
99

100
    /**
101
     * blur 失焦事件
102
     */
42✔
103
    readonly blur = output<Event>();
104

105
    /**
106
     * 后置模板
107
     */
42✔
108
    readonly appendTemplate = contentChild<TemplateRef<any>>('append');
109

110
    /**
111
     * 前置模板
112
     */
42✔
113
    readonly prependTemplate = contentChild<TemplateRef<any>>('prepend');
114

42✔
115
    public type = signal<string | undefined>(undefined);
116

42✔
117
    public value = signal('');
118

42✔
119
    public showLabel = signal(false);
120

42✔
121
    public focused = signal(false);
122

42✔
123
    public disabled = signal(false);
124

42✔
125
    private onTouchedCallback: () => void = noop;
126

42✔
127
    private onChangeCallback: (_: any) => void = noop;
128

42✔
129
    public isPasswordType = signal(false);
130

131
    constructor() {
42✔
132
        effect(() => {
43✔
133
            this.type.set(this.thyType() || this._type());
134
        });
135

136
        afterNextRender(() => {
137
            this.isPasswordType.set(this.isPassword(this.type()));
42✔
138
        });
42✔
139
    }
140

141
    ngOnInit() {}
142

143
    writeValue(value: any): void {
56✔
144
        this.value.set(value);
145
    }
146

147
    registerOnChange(fn: any): void {
28✔
148
        this.onChangeCallback = fn;
149
    }
150

151
    registerOnTouched(fn: any): void {
28✔
152
        this.onTouchedCallback = fn;
153
    }
154

155
    setDisabledState?(isDisabled: boolean): void {
29✔
156
        this.disabled.set(isDisabled);
157
    }
158

159
    onModelChange() {
×
160
        this.onChangeCallback(this.value());
161
    }
162

163
    onInputFocus(event: Event) {
1✔
164
        this.focused.set(true);
1✔
165
        this.showLabel.set(true);
1✔
166
        this.focus.emit(event);
167
    }
168

169
    onInputBlur(event: Event) {
1✔
170
        this.onTouchedCallback();
1!
171
        if (this.elementRef.nativeElement.onblur) {
×
172
            this.elementRef.nativeElement.onblur(event);
173
        }
1✔
174
        this.focused.set(false);
1✔
175
        this.showLabel.set(false);
1✔
176
        this.blur.emit(event);
177
    }
178

179
    isPassword(value?: string) {
68✔
180
        return value === password;
181
    }
182

183
    togglePasswordType() {
2✔
184
        this.type.set(this.isPassword(this.type()) ? 'text' : 'password');
185
    }
186
}
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