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

atinc / ngx-tethys / 68ef226c-f83e-44c1-b8ed-e420a83c5d84

28 May 2025 10:31AM UTC coverage: 10.352% (-80.0%) from 90.316%
68ef226c-f83e-44c1-b8ed-e420a83c5d84

Pull #3460

circleci

pubuzhixing8
chore: xxx
Pull Request #3460: refactor(icon): migrate signal input #TINFR-1476

132 of 6823 branches covered (1.93%)

Branch coverage included in aggregate %.

10 of 14 new or added lines in 1 file covered. (71.43%)

11648 existing lines in 344 files now uncovered.

2078 of 14525 relevant lines covered (14.31%)

6.69 hits per line

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

10.77
/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';
12

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

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

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

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

×
UNCOV
46
const noop = () => {};
×
47

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

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

×
77
    readonly inputElement = viewChild<ElementRef<any>>('input');
78

UNCOV
79
    private hostRenderer = useHostRenderer();
×
80

81
    private hostFocusControl = useHostFocusControl();
UNCOV
82

×
UNCOV
83
    public disabled = signal(false);
×
UNCOV
84

×
UNCOV
85
    searchText = signal<string>('');
×
86

×
87
    focused = signal(false);
UNCOV
88

×
UNCOV
89
    /**
×
UNCOV
90
     * 搜索框 name 属性
×
UNCOV
91
     */
×
92
    readonly name = input('');
93

UNCOV
94
    /**
×
95
     * 搜索框 Placeholder
96
     */
1✔
97
    readonly placeholder = input('');
1✔
98

99
    /**
100
     * 搜索框风格
101
     * @type 'default' | 'ellipse' | 'transparent'
102
     * @default default
103
     */
104
    readonly thyTheme = input<ThyInputSearchTheme>();
105

106
    /**
107
     * 是否自动聚焦
108
     * @default false
109
     */
1✔
110
    readonly autoFocus = input(false, { alias: 'thySearchFocus', transform: coerceBooleanProperty });
111

112
    /**
113
     * 搜索图标位置,当传入 after 时,搜索图标在输入框后方显示,有内容时显示为关闭按钮
114
     * @type ThyInputSearchIconPosition
115
     */
116
    readonly iconPosition = input('before', {
117
        alias: 'thyIconPosition',
118
        transform: (value: ThyInputSearchIconPosition) => value || 'before'
119
    });
120

121
    /**
122
     * 输入框大小
123
     * @type 'xs' | 'sm' | 'md' | 'default' | 'lg'
124
     */
125
    readonly thySize = input<ThyInputSize>();
126

127
    /**
128
     * @deprecated please use thyClear
129
     */
130
    readonly clear = output<Event>();
131

132
    /**
133
     * 清除搜索事件
134
     */
135
    readonly thyClear = output<Event>();
136

137
    constructor() {
138
        super();
139

140
        effect(() => {
141
            this.focused.set(this.autoFocus());
142
        });
143

144
        effect(() => {
145
            const iconPosition = this.iconPosition();
146
            this.hostRenderer.updateClass([`thy-input-search-${iconPosition}`]);
147
        });
148
    }
149

150
    ngOnInit(): void {
151
        super.ngOnInit();
152

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

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

171
    writeValue(value: any): void {
172
        this.searchText.set(value);
173
    }
174

175
    setDisabledState?(isDisabled: boolean): void {
176
        this.disabled.set(isDisabled);
177
    }
178

179
    searchModelChange() {
180
        this.onChangeFn(this.searchText());
181
    }
182

183
    clearSearchText(event: Event) {
184
        const element = this.elementRef.nativeElement.querySelector('.input-search-control');
185
        element.focus();
186
        event.stopPropagation();
187
        if (this.disabled()) {
188
            return;
189
        }
190
        this.searchText.set('');
191
        this.onChangeFn(this.searchText());
192
        this.clear.emit(event);
193
        this.thyClear.emit(event);
194
    }
195

196
    ngOnDestroy(): void {
197
        this.hostFocusControl.destroy();
198
    }
199
}
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

© 2025 Coveralls, Inc