• 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

11.11
/src/action/action.component.ts
1
import {
2
    ChangeDetectionStrategy,
3
    Component,
4
    Input,
5
    OnInit,
6
    AfterViewInit,
7
    OnChanges,
8
    ElementRef,
9
    Renderer2,
1✔
10
    SimpleChanges,
11
    ChangeDetectorRef,
12
    OnDestroy
13
} from '@angular/core';
14
import { InputBoolean } from 'ngx-tethys/core';
15
import { useHostRenderer } from '@tethys/cdk/dom';
16
import { ThyIconComponent } from 'ngx-tethys/icon';
17
import { NgIf } from '@angular/common';
18
import { Subscription, timer } from 'rxjs';
19

20
export type ThyActionType = 'primary' | 'success' | 'danger' | 'warning';
21

22
export type ThyActionFeedback = 'success' | 'error';
23

24
export interface ThyActionFeedbackOptions {
25
    icon?: string;
1✔
26
    class?: string;
27
    duration?: number;
×
28
}
29

30
const defaultFeedbackOptions: Record<ThyActionFeedback, ThyActionFeedbackOptions> = {
×
31
    success: {
32
        icon: 'check-circle-fill',
33
        class: 'text-success',
×
34
        duration: 3000
35
    },
36
    error: {
×
37
        icon: 'close-circle-fill',
38
        class: 'text-danger',
39
        duration: 3000
×
40
    }
41
};
42
/**
×
43
 * 立即操作组件
×
44
 * @name thy-action,[thyAction]
×
45
 */
×
46
@Component({
×
47
    selector: 'thy-action, [thyAction]',
×
48
    templateUrl: './action.component.html',
×
49
    changeDetection: ChangeDetectionStrategy.OnPush,
×
50
    host: {
51
        class: 'thy-action',
52
        '[class.active]': 'active',
×
53
        '[class.thy-action-hover-icon]': 'thyHoverIcon',
54
        '[class.thy-action-has-feedback]': '!!feedback',
55
        '[class.disabled]': 'thyDisabled'
×
56
    },
57
    standalone: true,
58
    imports: [NgIf, ThyIconComponent]
×
59
})
×
60
export class ThyActionComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy {
61
    icon: string;
62

63
    feedback: ThyActionFeedback = null;
×
64

65
    feedbackOptions: ThyActionFeedbackOptions;
66

67
    active = false;
68

69
    private type: string = 'primary';
×
70

71
    private hostRenderer = useHostRenderer();
72

73
    private feedbackTimer: Subscription;
74

75
    /**
×
76
     * 操作图标的类型
77
     * @type primary | success | danger | warning
78
     * @default primary
×
79
     */
×
80
    @Input()
81
    set thyType(value: ThyActionType) {
×
82
        this.setActionType(value || 'primary');
×
83
    }
×
84

×
85
    /**
×
86
     * 操作图标,支持传参同时也支持在投影中写 thy-icon 组件
×
87
     */
×
88
    @Input()
89
    set thyIcon(icon: string) {
×
90
        this.icon = icon;
×
91
    }
×
92

×
93
    /**
94
     * 操作图标,当 thyIcon 和其他指令参数名有冲突时使用 thyActionIcon
95
     */
96
    @Input()
97
    set thyActionIcon(icon: string) {
×
98
        this.icon = icon;
×
99
    }
×
100

×
101
    /**
102
     * 操作的图标 Active 状态,设置为 true 时会在 Item 上添加 active class
×
103
     * @default false
×
104
     */
105
    @Input()
106
    @InputBoolean()
107
    set thyActive(value: boolean) {
108
        this.active = value;
×
109
    }
110

111
    /**
×
112
     * 操作的图标 Active 状态,当 thyActive 和其他指令参数名有冲突时使用 thyActionActive
×
113
     * @default false
×
114
     */
×
115
    @Input()
116
    @InputBoolean()
×
117
    set thyActionActive(value: boolean) {
118
        this.active = value;
119
    }
×
120

121
    /**
1✔
122
     * 操作图标的主题
123
     * @type fill(背景色填充) | lite(简单文本颜色变化)
124
     */
125
    @Input() thyTheme: 'fill' | 'lite' = 'fill';
126

1✔
127
    /**
128
     * Hover 展示的图标
129
     */
130
    @Input() thyHoverIcon: string;
131

132
    /**
133
     * 是否处于禁用状态
134
     * @default false
135
     */
136
    @Input()
137
    @InputBoolean()
1✔
138
    thyDisabled: boolean;
139

140
    constructor(private elementRef: ElementRef<HTMLElement>, private renderer: Renderer2, private cdr: ChangeDetectorRef) {}
141

142
    ngOnInit(): void {
1✔
143
        this.updateClasses();
144
    }
145

146
    ngAfterViewInit() {
147
        this.wrapSpanForText(this.elementRef.nativeElement.childNodes);
1✔
148
    }
149

150
    ngOnChanges(changes: SimpleChanges): void {
151
        if ((changes.thyType && !changes.thyType.firstChange) || (changes.thyTheme && !changes.thyTheme.firstChange)) {
1✔
152
            this.updateClasses();
153
        }
154
    }
155

156
    setMarginRight(marginRight: string) {
157
        this.elementRef.nativeElement.style.marginRight = marginRight;
158
    }
159

160
    /**
161
     * 触发成功反馈操作
162
     */
163
    success(options?: ThyActionFeedbackOptions) {
164
        this.setFeedback('success', options);
165
    }
166

167
    /**
168
     * 触发失败反馈操作
169
     */
170
    error(options?: ThyActionFeedbackOptions) {
171
        this.setFeedback('error', options);
172
    }
173

174
    private setFeedback(feedback: ThyActionFeedback, options: ThyActionFeedbackOptions) {
175
        if (this.thyDisabled) {
176
            return;
177
        }
178
        options = Object.assign({}, defaultFeedbackOptions[feedback], options);
179
        this.feedback = feedback;
180
        this.feedbackOptions = options;
181
        this.cdr.markForCheck();
182
        if (options.duration) {
183
            if (this.feedbackTimer) {
184
                this.feedbackTimer.unsubscribe();
185
            }
186
            this.feedbackTimer = timer(options.duration).subscribe(() => {
187
                this.feedback = null;
188
                this.feedbackOptions = null;
189
                this.cdr.markForCheck();
190
            });
191
        }
192
    }
193

194
    private wrapSpanForText(nodes: NodeList): void {
195
        nodes.forEach(node => {
196
            if (node.nodeName === '#text') {
197
                const span = this.renderer.createElement('span');
198
                const parent = this.renderer.parentNode(node);
199
                // this.renderer.addClass(span, 'thy-action-wrap-span');
200
                this.renderer.insertBefore(parent, span, node);
201
                this.renderer.appendChild(span, node);
202
            }
203
        });
204
    }
205

206
    private setActionType(value: ThyActionType) {
207
        this.type = value;
208
    }
209

210
    private updateClasses() {
211
        let classNames: string[] = [];
212
        classNames.push(`action-${this.type}`);
213
        if (this.thyTheme === 'lite') {
214
            classNames.push('thy-action-lite');
215
        }
216
        this.hostRenderer.updateClass(classNames);
217
    }
218

219
    ngOnDestroy(): void {
220
        this.feedbackTimer?.unsubscribe();
221
    }
222
}
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