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

atinc / ngx-tethys / cd64db52-e563-41a3-85f3-a0adb87ce135

30 Oct 2024 08:03AM UTC coverage: 90.402% (-0.04%) from 90.438%
cd64db52-e563-41a3-85f3-a0adb87ce135

push

circleci

web-flow
refactor: refactor constructor to the inject function (#3222)

5503 of 6730 branches covered (81.77%)

Branch coverage included in aggregate %.

422 of 429 new or added lines in 170 files covered. (98.37%)

344 existing lines in 81 files now uncovered.

13184 of 13941 relevant lines covered (94.57%)

997.19 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)));
10!
UNCOV
52

×
53
/**
54
 * 搜索输入框
10✔
55
 * @name thy-input-search
8✔
56
 * @order 30
3✔
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',
10✔
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
    standalone: true,
73
    imports: [ThyIcon, ThyInputDirective, ThyAutofocusDirective, FormsModule]
74
})
34✔
75
export class ThyInputSearch extends _MixinBase implements ControlValueAccessor, OnInit, OnDestroy {
34✔
76
    private cdr = inject(ChangeDetectorRef);
77
    private elementRef = inject(ElementRef);
78

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

81
    private hostRenderer = useHostRenderer();
1✔
82

83
    private hostFocusControl = useHostFocusControl();
84

2✔
85
    public disabled = false;
2✔
86

2✔
87
    public autoFocus = false;
2!
UNCOV
88

×
89
    public iconPosition: ThyInputSearchIconPosition = 'before';
90

2✔
91
    searchText: string;
2✔
92

2✔
93
    focused = false;
2✔
94

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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