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

atinc / ngx-tethys / edbc1d43-1648-411a-a6bc-f24c9aa3f654

27 Mar 2025 06:13AM UTC coverage: 90.236% (+0.06%) from 90.179%
edbc1d43-1648-411a-a6bc-f24c9aa3f654

push

circleci

web-flow
Merge pull request #3282 from atinc/v19.0.0-next

5598 of 6865 branches covered (81.54%)

Branch coverage included in aggregate %.

8 of 8 new or added lines in 7 files covered. (100.0%)

157 existing lines in 46 files now uncovered.

13357 of 14141 relevant lines covered (94.46%)

992.51 hits per line

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

92.86
/src/input/input-search.component.ts
1
import {
2
    AbstractControlValueAccessor,
3
    Constructor,
4
    mixinDisabled,
5
    mixinInitialized,
6
    mixinTabIndex,
7
    ThyCanDisable,
8
    ThyHasTabIndex,
9
    ThyInitialized,
10
    useHostFocusControl
11
} from 'ngx-tethys/core';
1✔
12

13
import {
16✔
14
    ChangeDetectionStrategy,
15
    ChangeDetectorRef,
16
    Component,
1✔
17
    ElementRef,
1✔
18
    EventEmitter,
19
    forwardRef,
20
    Input,
21
    OnDestroy,
22
    OnInit,
23
    Output,
1✔
24
    ViewChild,
25
    ViewEncapsulation,
13✔
26
    inject
13✔
27
} from '@angular/core';
28
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
29
import { useHostRenderer } from '@tethys/cdk/dom';
13✔
30
import { ThyIcon } from 'ngx-tethys/icon';
13✔
31
import { ThyAutofocusDirective } from 'ngx-tethys/shared';
32
import { ThyInputDirective, ThyInputSize } from './input.directive';
33

16✔
34
import { FocusOrigin } from '@angular/cdk/a11y';
16✔
35
import { coerceBooleanProperty } from 'ngx-tethys/util';
16✔
36

16✔
37
export type ThyInputSearchTheme = 'default' | 'ellipse' | 'transparent' | '';
16✔
38
export type ThyInputSearchIconPosition = 'before' | 'after';
16✔
39

16✔
40
export const CUSTOM_INPUT_SEARCH_CONTROL_VALUE_ACCESSOR: any = {
16✔
41
    provide: NG_VALUE_ACCESSOR,
16✔
42
    useExisting: forwardRef(() => ThyInputSearch),
16✔
43
    multi: true
16✔
44
};
16✔
45

16✔
46
const noop = () => {};
47

48
const _MixinBase: Constructor<ThyHasTabIndex> &
16✔
49
    Constructor<ThyInitialized> &
16✔
50
    Constructor<ThyCanDisable> &
16✔
51
    typeof AbstractControlValueAccessor = mixinInitialized(mixinTabIndex(mixinDisabled(AbstractControlValueAccessor)));
16!
52

×
53
/**
54
 * 搜索输入框
16✔
55
 * @name thy-input-search
14✔
56
 * @order 30
6✔
57
 */
58
@Component({
59
    selector: 'thy-input-search',
60
    templateUrl: './input-search.component.html',
2!
61
    providers: [CUSTOM_INPUT_SEARCH_CONTROL_VALUE_ACCESSOR],
2✔
62
    encapsulation: ViewEncapsulation.None,
2✔
63
    changeDetection: ChangeDetectionStrategy.OnPush,
64
    host: {
65
        class: 'thy-input form-control thy-input-search',
16✔
66
        '[class.thy-input-search-ellipse]': 'thyTheme === "ellipse"',
67
        '[class.thy-input-search-transparent]': 'thyTheme === "transparent"',
68
        '[class.thy-input-search-before-with-clear]': 'searchText && iconPosition === "before"',
13✔
69
        '[class.form-control-active]': 'focused',
29✔
70
        '[attr.tabindex]': 'tabIndex'
16✔
71
    },
72
    imports: [ThyIcon, ThyInputDirective, ThyAutofocusDirective, FormsModule]
73
})
74
export class ThyInputSearch extends _MixinBase implements ControlValueAccessor, OnInit, OnDestroy {
34✔
75
    private cdr = inject(ChangeDetectorRef);
34✔
76
    private elementRef = inject(ElementRef);
77

78
    @ViewChild('input', { static: true }) inputElement: ElementRef<any>;
17✔
79

80
    private hostRenderer = useHostRenderer();
81

1✔
82
    private hostFocusControl = useHostFocusControl();
83

84
    public disabled = false;
2✔
85

2✔
86
    public autoFocus = false;
2✔
87

2!
UNCOV
88
    public iconPosition: ThyInputSearchIconPosition = 'before';
×
89

90
    searchText: string;
2✔
91

2✔
92
    focused = false;
2✔
93

2✔
94
    /**
95
     * 搜索框 name 属性
96
     */
16✔
97
    @Input() name = '';
98

1✔
99
    /**
1✔
100
     * 搜索框 Placeholder
101
     */
102
    @Input() placeholder = '';
103

104
    /**
105
     * 搜索框风格
106
     * @type 'default' | 'ellipse' | 'transparent'
107
     * @default default
108
     */
109
    @Input() thyTheme: ThyInputSearchTheme;
110

111
    /**
1✔
112
     * 是否自动聚焦
113
     * @default false
114
     */
115
    @Input({ transform: coerceBooleanProperty })
116
    set thySearchFocus(value: boolean) {
117
        this.autoFocus = value;
118
        this.focused = value;
119
    }
120

121
    /**
122
     * 搜索图标位置,当传入 after 时,搜索图标在输入框后方显示,有内容时显示为关闭按钮
123
     * @type
124
     */
125
    @Input() set thyIconPosition(value: ThyInputSearchIconPosition) {
126
        this.iconPosition = value || 'before';
127
        this.updateClasses();
128
    }
129

130
    /**
131
     * 输入框大小
132
     * @type 'xs' | 'sm' | 'md' | 'default' | 'lg'
133
     */
134
    @Input() thySize: ThyInputSize;
135

136
    /**
137
     * @deprecated please use thyClear
138
     */
139
    @Output() clear: EventEmitter<Event> = new EventEmitter<Event>();
140

141
    /**
142
     * 清除搜索事件
143
     */
144
    @Output() thyClear: EventEmitter<Event> = new EventEmitter<Event>();
145

146
    constructor() {
147
        super();
148
    }
149

150
    ngOnInit(): void {
151
        super.ngOnInit();
152
        this.updateClasses(true);
153

154
        this.hostFocusControl.focusChanged = (origin: FocusOrigin) => {
155
            if (this.disabled) {
156
                return;
157
            }
158

159
            if (origin) {
160
                if (!this.focused) {
161
                    this.inputElement.nativeElement.focus();
162
                }
163
            } else {
164
                if (this.focused) {
165
                    this.focused = false;
166
                    this.onTouchedFn();
167
                }
168
            }
169
            this.cdr.markForCheck();
170
        };
171
    }
172

173
    updateClasses(forceUpdate = false) {
174
        if (this.initialized || forceUpdate) {
175
            this.hostRenderer.updateClass([`thy-input-search-${this.iconPosition}`]);
176
        }
177
    }
178

179
    writeValue(value: any): void {
180
        this.searchText = value;
181
        this.cdr.markForCheck();
182
    }
183

184
    setDisabledState?(isDisabled: boolean): void {
185
        this.disabled = isDisabled;
186
    }
187

188
    searchModelChange() {
189
        this.onChangeFn(this.searchText);
190
    }
191

192
    clearSearchText(event: Event) {
193
        const element = this.elementRef.nativeElement.querySelector('.input-search-control');
194
        element.focus();
195
        event.stopPropagation();
196
        if (this.disabled) {
197
            return;
198
        }
199
        this.searchText = '';
200
        this.onChangeFn(this.searchText);
201
        this.clear.emit(event);
202
        this.thyClear.emit(event);
203
    }
204

205
    ngOnDestroy(): void {
206
        this.hostFocusControl.destroy();
207
    }
208
}
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