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

atinc / ngx-tethys / d9ae709b-3c27-4b69-b125-b8b80b54f90b

pending completion
d9ae709b-3c27-4b69-b125-b8b80b54f90b

Pull #2757

circleci

mengshuicmq
fix: fix code review
Pull Request #2757: feat(color-picker): color-picker support disabled (#INFR-8645)

98 of 6315 branches covered (1.55%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

2392 of 13661 relevant lines covered (17.51%)

83.12 hits per line

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

6.45
/src/button/button.component.ts
1
import {
2
    ChangeDetectionStrategy,
3
    Component,
4
    ElementRef,
5
    HostBinding,
6
    Input,
7
    OnInit,
8
    Renderer2,
9
    ViewEncapsulation,
1✔
10
    AfterViewInit
11
} from '@angular/core';
12

13
import { InputBoolean } from 'ngx-tethys/core';
14
import { assertIconOnly } from 'ngx-tethys/util';
15
import { useHostRenderer } from '@tethys/cdk/dom';
16
import { ThyIconComponent } from 'ngx-tethys/icon';
17
import { NgIf, NgClass } from '@angular/common';
18

19
export type ThyButtonType =
20
    | 'primary'
21
    | 'secondary'
22
    | 'info'
23
    | 'outline-primary'
24
    | 'outline-default'
1✔
25
    | 'danger'
26
    | 'link'
27
    | 'link-secondary'
28
    | 'warning'
29
    | 'outline-warning'
30
    | 'success'
1✔
31
    | 'outline-success'
32
    | 'outline-info'
×
33
    | 'outline-danger'
34
    | 'link-danger-weak'
35
    | 'link-danger'
×
36
    | 'link-success';
37

38
const btnTypeClassesMap = {
×
39
    primary: ['btn-primary'],
40
    secondary: ['btn-primary', 'btn-md'],
41
    info: ['btn-info'],
×
42
    warning: ['btn-warning'],
×
43
    danger: ['btn-danger'],
×
44
    'outline-primary': ['btn-outline-primary'],
×
45
    'outline-default': ['btn-outline-default'],
×
46
    link: ['btn-link'], // 链接按钮
47
    'link-info': ['btn-link', 'btn-link-info'], // 幽灵链接按钮
48
    'link-secondary': ['btn-link', 'btn-link-primary-weak'], // 幽灵链接按钮
×
49
    'link-danger-weak': ['btn-link', 'btn-link-danger-weak'], // 幽灵危险按钮
×
50
    'link-danger': ['btn-link', 'btn-link-danger'], // 危险按钮
51
    'link-success': ['btn-link', 'btn-link-success'] // 成功按钮
52
};
53

×
54
const iconOnlyClass = 'thy-btn-icon-only';
×
55

×
56
/**
×
57
 * 操作按钮,支持组件`thy-button`和`thyButton`指令两种形式
58
 * @name thy-button,[thy-button],[thyButton]
59
 * @order 10
60
 */
61
@Component({
×
62
    selector: 'thy-button,[thy-button],[thyButton]',
×
63
    templateUrl: './button.component.html',
×
64
    encapsulation: ViewEncapsulation.None,
65
    changeDetection: ChangeDetectionStrategy.OnPush,
66
    host: {
67
        class: 'thy-btn btn'
×
68
    },
×
69
    standalone: true,
×
70
    imports: [NgIf, ThyIconComponent, NgClass]
×
71
})
×
72
export class ThyButtonComponent implements OnInit, AfterViewInit {
×
73
    private _initialized = false;
74

×
75
    private _originalText: string;
×
76

77
    private _type: string;
78

×
79
    private _size: string;
80

81
    private _icon: string;
82

×
83
    private _loading: boolean;
×
84

85
    private _loadingText: string;
86

87
    // 圆角方形
×
88
    _isRadiusSquare = false;
×
89

×
90
    iconClass: string[];
×
91

92
    svgIconName: string;
93

×
94
    private get nativeElement(): HTMLElement {
95
        return this.elementRef.nativeElement;
×
96
    }
×
97

98
    private hostRenderer = useHostRenderer();
99

100
    /**
101
     * 按钮类型,支持添加前缀`outline-`实现线框按钮,支持添加前缀`link-`实现按钮链接
×
102
     * @type primary | info | warning | danger | success
×
103
     * @default primary
×
104
     */
105
    @Input()
106
    set thyButton(value: ThyButtonType) {
107
        this.setBtnType(value);
×
108
    }
×
109

×
110
    /**
×
111
     * 和`thyButton`参数一样,一般使用`thyButton`,为了减少参数输入, 当通过`thy-button`使用时,只能使用该参数控制类型
112
     * @default primary
113
     */
114
    @Input()
×
115
    set thyType(value: ThyButtonType) {
×
116
        this.setBtnType(value);
×
117
    }
118

119
    /**
×
120
     * 加载状态
×
121
     * @default false
122
     */
123
    @Input()
×
124
    @InputBoolean()
×
125
    set thyLoading(value: boolean) {
126
        if (!this._loading && value) {
×
127
            this._loading = value;
×
128
            const textElement = this.nativeElement.querySelector('span');
129
            this._originalText = textElement ? textElement.innerText : '';
×
130
            this.setLoadingStatus();
×
131
        } else {
132
            this._loading = value;
×
133
            this.setLoadingStatus();
134
        }
135
    }
×
136

×
137
    /**
×
138
     * 加载状态时显示的文案
139
     */
×
140
    @Input()
×
141
    set thyLoadingText(value: string) {
142
        if (this._loadingText !== value) {
143
            this._loadingText = value;
×
144
            if (this._loading) {
×
145
                this.setLoadingText(this._loadingText);
146
            }
147
        }
×
148
    }
×
149

150
    /**
151
     * 按钮大小
×
152
     * @type xs | sm | md | default | lg
153
     * @default default
×
154
     */
155
    @Input()
156
    set thySize(size: string) {
×
157
        this._size = size;
×
158
        if (this._initialized) {
×
159
            this.updateClasses();
×
160
        }
×
161
    }
×
162

×
163
    /**
164
     * 按钮中显示的图标,支持SVG图标名称,比如`angle-left`,也支持传之前的 wtf 字体,比如: wtf-plus
165
     */
166
    @Input()
1✔
167
    set thyIcon(icon: string) {
168
        this._icon = icon;
169
        if (this._icon) {
170
            if (icon.includes('wtf')) {
1✔
171
                const classes = this._icon.split(' ');
172
                if (classes.length === 1) {
173
                    classes.unshift('wtf');
174
                }
175
                this.iconClass = classes;
176
                this.svgIconName = null;
177
            } else {
178
                this.svgIconName = icon;
179
            }
180
        } else {
1✔
181
            this.iconClass = null;
182
            this.svgIconName = null;
183
        }
184
    }
185

1✔
186
    /**
187
     * 按钮整块展示
188
     * @default false
189
     */
1✔
190
    @HostBinding(`class.btn-block`)
191
    @Input()
192
    @InputBoolean()
193
    thyBlock: boolean;
194

195
    private setBtnType(value: ThyButtonType) {
196
        if (value) {
197
            if (value.includes('-square')) {
198
                this._type = value.replace('-square', '');
199
                this._isRadiusSquare = true;
200
            } else {
201
                this._type = value;
202
            }
203

204
            if (this._initialized) {
205
                this.updateClasses();
206
            }
207
        }
208
    }
209

210
    private setLoadingText(text: string) {
211
        const spanElement = this.nativeElement.querySelector('span');
212
        if (spanElement) {
213
            this.renderer.setProperty(spanElement, 'innerText', text);
214
        }
215
    }
216

217
    private setLoadingStatus() {
218
        const innerText = this._loading ? this._loadingText : this._originalText;
219
        this.updateClasses();
220
        if (innerText) {
221
            this.setLoadingText(innerText);
222
        }
223
    }
224

225
    private updateClasses() {
226
        let classNames: string[] = [];
227
        if (btnTypeClassesMap[this._type]) {
228
            classNames = [...btnTypeClassesMap[this._type]];
229
        } else {
230
            if (this._type) {
231
                classNames.push(`btn-${this._type}`);
232
            }
233
        }
234
        if (this._size) {
235
            classNames.push(`btn-${this._size}`);
236
        }
237
        if (this._isRadiusSquare) {
238
            classNames.push('btn-square');
239
        }
240
        if (this._loading) {
241
            classNames.push('loading');
242
        }
243
        this.hostRenderer.updateClass(classNames);
244
    }
245

246
    constructor(private elementRef: ElementRef, private renderer: Renderer2) {}
247

248
    ngOnInit() {
249
        this.updateClasses();
250
        this._initialized = true;
251
    }
252

253
    ngAfterViewInit() {
254
        if (assertIconOnly(this.nativeElement)) {
255
            this.hostRenderer.addClass(iconOnlyClass);
256
        } else {
257
            this.hostRenderer.removeClass(iconOnlyClass);
258
        }
259
        this.wrapSpanForText(this.nativeElement.childNodes);
260
    }
261

262
    private wrapSpanForText(nodes: NodeList): void {
263
        nodes.forEach(node => {
264
            if (node.nodeName === '#text') {
265
                const span = this.renderer.createElement('span');
266
                const parent = this.renderer.parentNode(node);
267
                this.renderer.addClass(span, 'thy-btn-wrap-span');
268
                this.renderer.insertBefore(parent, span, node);
269
                this.renderer.appendChild(span, node);
270
            }
271
        });
272
    }
273
}
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