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

atinc / ngx-tethys / ebc321d8-d8ed-4ed1-9e59-a5945729a8da

24 Aug 2023 02:49AM UTC coverage: 90.055% (-0.1%) from 90.181%
ebc321d8-d8ed-4ed1-9e59-a5945729a8da

Pull #2771

circleci

web-flow
feat(dropdown): update thyImmediateRender template remove div #INFR-9359 (#2794)

* feat(dropdown): update thyImmediateRender template remove div #INFR-9359

* feat(dropdown): update test

* feat(dropdown): update test

* build: code review

* build: code review
Pull Request #2771: feat: bump angular to 16.x

5104 of 6321 branches covered (80.75%)

Branch coverage included in aggregate %.

144 of 144 new or added lines in 15 files covered. (100.0%)

12897 of 13668 relevant lines covered (94.36%)

977.88 hits per line

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

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

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

16✔
35
import { FocusOrigin } from '@angular/cdk/a11y';
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(() => ThyInputSearchComponent),
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!
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: [NgIf, ThyIconComponent, ThyInputDirective, ThyAutofocusDirective, FormsModule]
74
})
34✔
75
export class ThyInputSearchComponent extends _MixinBase implements ControlValueAccessor, OnInit, OnDestroy {
34✔
76
    @ViewChild('input', { static: true }) inputElement: ElementRef<any>;
77

78
    private hostRenderer = useHostRenderer();
17✔
79

80
    private hostFocusControl = useHostFocusControl();
81

1✔
82
    public disabled = false;
83

84
    public autoFocus = false;
2✔
85

2✔
86
    public iconPosition: ThyInputSearchIconPosition = 'before';
2✔
87

2!
88
    searchText: string;
×
89

90
    focused = false;
2✔
91

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

16✔
97
    /**
98
     * 搜索框 Placeholder
1✔
99
     */
100
    @Input() placeholder = '';
101

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

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

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

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

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

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

145
    constructor(private cdr: ChangeDetectorRef, private elementRef: ElementRef) {
146
        super();
147
    }
148

149
    ngOnInit(): void {
150
        super.ngOnInit();
151
        this.updateClasses(true);
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 = false;
165
                    this.onTouchedFn();
166
                }
167
            }
168
            this.cdr.markForCheck();
169
        };
170
    }
171

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

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

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

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

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

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