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

atinc / ngx-tethys / #101

13 Aug 2025 01:01PM UTC coverage: 90.43% (+0.02%) from 90.407%
#101

push

web-flow
Merge b7d320098 into 254bab68c

5524 of 6796 branches covered (81.28%)

Branch coverage included in aggregate %.

149 of 166 new or added lines in 15 files covered. (89.76%)

12 existing lines in 7 files now uncovered.

14018 of 14814 relevant lines covered (94.63%)

906.76 hits per line

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

89.36
/src/shared/option/option.component.ts
1
import {
2
    Component,
3
    TemplateRef,
4
    ChangeDetectionStrategy,
5
    HostBinding,
6
    HostListener,
7
    ElementRef,
8
    ChangeDetectorRef,
9
    OnDestroy,
10
    inject,
×
11
    input,
117✔
12
    viewChild,
117✔
13
    WritableSignal,
14
    signal,
15
    output,
16
    Input
17
} from '@angular/core';
18
import { Highlightable } from '@angular/cdk/a11y';
19
import { SelectOptionBase } from './select-option-base';
20
import { ENTER, SPACE, coerceBooleanProperty, hasModifierKey } from 'ngx-tethys/util';
21
import { THY_OPTION_PARENT_COMPONENT } from './option.token';
1✔
22

23
import { ThyIcon } from 'ngx-tethys/icon';
24
import { SafeAny } from '../../types';
5,003✔
25

26
export class ThyOptionSelectionChangeEvent {
27
    constructor(
4,753✔
28
        public option: ThyOption,
29
        public isUserInput = false
30
    ) {}
965✔
31
}
965✔
32

965✔
33
export class ThyOptionVisibleChangeEvent {
965✔
34
    option: ThyOption;
965✔
35
}
965✔
36

965✔
37
/**
965✔
38
 * @private
965✔
39
 * @order 20
965✔
40
 */
965✔
41
@Component({
965✔
42
    selector: 'thy-option',
43
    templateUrl: './option.component.html',
44
    changeDetection: ChangeDetectionStrategy.OnPush,
168✔
45
    imports: [ThyIcon],
46
    host: {
47
        class: 'thy-option-item',
28✔
48
        '[class.disabled]': 'thyDisabled()',
49
        '[class.hidden]': 'hidden()',
NEW
50
        '[attr.tabindex]': `tabIndex`,
×
NEW
51
        '[class.active]': 'selected()'
×
NEW
52
    }
×
53
})
54
export class ThyOption extends SelectOptionBase implements OnDestroy, Highlightable {
55
    element = inject<ElementRef<HTMLElement>>(ElementRef);
56
    parent = inject(THY_OPTION_PARENT_COMPONENT, { optional: true })!;
37✔
57
    private cdr = inject(ChangeDetectorRef);
36✔
58

36✔
59
    // 继承至 SelectOptionBase,无法修改为 Signal
36✔
60
    @Input() thyValue: any;
36✔
61

62
    @Input() thyRawValue: any;
63

64
    @Input() thyLabelText: string;
92✔
65

90✔
66
    readonly thyShowOptionCustom = input<boolean>();
48✔
67

48✔
68
    readonly thySearchKey = input<string>();
48✔
69

70
    readonly template = viewChild(TemplateRef);
71

72
    readonly thyDisabled = input(false, { transform: coerceBooleanProperty });
73

35✔
74
    readonly hidden: WritableSignal<boolean> = signal(false);
30✔
75

30✔
76
    // 继承至 Highlightable,无法修改为 Signal
30✔
77
    get disabled(): boolean {
78
        return this.hidden() || this.thyDisabled();
79
    }
80

40✔
81
    get tabIndex(): string {
37✔
82
        return this.disabled ? '-1' : '0';
37✔
83
    }
37✔
84

85
    readonly selected: WritableSignal<boolean> = signal(false);
86

87
    readonly selectionChange = output<ThyOptionSelectionChangeEvent>();
16✔
88

10✔
89
    readonly visibleChange = output<ThyOptionVisibleChangeEvent>();
10✔
90

10✔
91
    constructor() {
92
        super();
93
    }
94

56✔
95
    getHostElement(): HTMLElement {
56✔
96
        return this.element.nativeElement;
12✔
97
    }
5✔
98

99
    @HostListener('click', ['$event'])
100
    onClick(event: Event) {
7✔
101
        this.selectViaInteraction();
102
    }
103

104
    @HostListener('keydown', ['$event'])
44✔
105
    handleKeydown(event: KeyboardEvent): void {
11✔
106
        if ((event.keyCode === ENTER || event.keyCode === SPACE) && !hasModifierKey(event)) {
107
            this.selectViaInteraction();
108
            event.preventDefault();
33✔
109
        }
110
    }
111

112
    selectViaInteraction(): void {
113
        if (!this.disabled) {
119✔
114
            const selected = this.parent.isMultiple ? !this.selected() : true;
119✔
115
            this.selected.set(selected);
116
            this.cdr.markForCheck();
117
            this.emitSelectionChangeEvent(true);
49✔
118
        }
49✔
119
    }
120

UNCOV
121
    select(event?: Event): void {
×
122
        if (!this.disabled) {
123
            if (!this.selected()) {
78✔
124
                this.selected.set(true);
114✔
125
                this.emitSelectionChangeEvent();
126
                this.cdr.markForCheck();
127
            }
1✔
128
        }
1✔
129
    }
130

131
    deselect(): void {
132
        if (this.selected() || this.disabled) {
133
            this.selected.set(false);
134
            this.emitSelectionChangeEvent();
135
            this.cdr.markForCheck();
136
        }
137
    }
138

139
    hideOption() {
140
        if (!this.hidden()) {
141
            this.hidden.set(true);
142
            this.visibleChange.emit({ option: this });
1✔
143
            this.cdr.markForCheck();
144
        }
145
    }
146

147
    showOption() {
148
        if (this.hidden()) {
149
            this.hidden.set(false);
150
            this.visibleChange.emit({ option: this });
151
            this.cdr.markForCheck();
152
        }
153
    }
154

155
    matchSearchText(searchText: string): boolean {
156
        const thySearchKey = this.thySearchKey();
157
        if (thySearchKey) {
158
            if (thySearchKey.toLowerCase().indexOf(searchText.toLowerCase()) >= 0) {
159
                return true;
160
            } else {
161
                return false;
162
            }
163
        } else {
164
            if (this.thyLabelText.toLowerCase().indexOf(searchText.toLowerCase()) >= 0) {
165
                return true;
166
            } else {
167
                return false;
168
            }
169
        }
170
    }
171

172
    setActiveStyles(): void {
173
        this.getHostElement().classList.add('hover');
174
        this.cdr.markForCheck();
175
    }
176

177
    setInactiveStyles(): void {
178
        this.getHostElement().classList.remove('hover');
179
        this.cdr.markForCheck();
180
    }
181

182
    getLabel(): string {
183
        return '';
184
    }
185

186
    private emitSelectionChangeEvent(isUserInput = false): void {
187
        this.selectionChange.emit(new ThyOptionSelectionChangeEvent(this, isUserInput));
188
    }
189

190
    ngOnDestroy() {}
191
}
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