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

atinc / ngx-tethys / 0bbb2cec-209e-4d8a-b1b3-6bc54e05daa6

04 Sep 2023 08:40AM UTC coverage: 15.616% (-74.6%) from 90.2%
0bbb2cec-209e-4d8a-b1b3-6bc54e05daa6

Pull #2829

circleci

cmm-va
fix: add test
Pull Request #2829: fix: add tabIndex

300 of 6386 branches covered (0.0%)

Branch coverage included in aggregate %.

78 of 78 new or added lines in 26 files covered. (100.0%)

2849 of 13779 relevant lines covered (20.68%)

83.41 hits per line

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

8.33
/src/tabs/tabs.component.ts
1
import {
2
    AfterContentInit,
3
    ChangeDetectionStrategy,
4
    ChangeDetectorRef,
5
    Component,
6
    ContentChildren,
7
    ElementRef,
8
    EventEmitter,
9
    Input,
10
    OnChanges,
11
    OnInit,
12
    Output,
13
    QueryList,
14
    SimpleChanges,
15
    TemplateRef
16
} from '@angular/core';
1✔
17
import { InputBoolean, UnsubscribeMixin } from 'ngx-tethys/core';
18
import { isString } from 'ngx-tethys/util';
×
19
import { fromEvent } from 'rxjs';
×
20
import { takeUntil } from 'rxjs/operators';
×
21
import { ThyTabComponent } from './tab.component';
22
import { ThyActiveTabInfo, ThyTabActiveEvent } from './types';
23
import { ThyTabContentComponent } from './tab-content.component';
×
24
import { NgFor, NgIf, NgTemplateOutlet } from '@angular/common';
×
25
import { ThyNavComponent, ThyNavItemDirective } from 'ngx-tethys/nav';
26

27
export type ThyTabsSize = 'lg' | 'md' | 'sm';
28

×
29
export type ThyTabsType = 'pulled' | 'tabs' | 'pills' | 'lite';
×
30

×
31
export type ThyTabsPosition = 'top' | 'left';
×
32

×
33
/**
×
34
 * 选项卡切换组件
×
35
 * @name thy-tabs
×
36
 */
×
37
@Component({
×
38
    selector: 'thy-tabs',
×
39
    templateUrl: './tabs.component.html',
×
40
    changeDetection: ChangeDetectionStrategy.OnPush,
41
    host: {
42
        class: 'thy-tabs',
×
43
        '[class.thy-tabs-top]': `thyPosition === 'top'`,
×
44
        '[class.thy-tabs-left]': `thyPosition === 'left'`,
45
        '[style.overflow]': `transitionStarted ? "hidden" : null`
46
    },
×
47
    standalone: true,
×
48
    imports: [ThyNavComponent, NgFor, ThyNavItemDirective, NgIf, NgTemplateOutlet, ThyTabContentComponent]
49
})
50
export class ThyTabsComponent extends UnsubscribeMixin implements OnInit, OnChanges, AfterContentInit {
51
    @ContentChildren(ThyTabComponent, { descendants: true }) tabs = new QueryList<ThyTabComponent>();
×
52

×
53
    /**
×
54
     * 标签类型
×
55
     * @type 'pulled' | 'tabs' | 'pills' | 'lite'
×
56
     */
57
    @Input() thyType: ThyTabsType = 'tabs';
58

59
    /**
×
60
     * 选项卡的大小
×
61
     * @type 'lg' | 'md' | 'sm'
×
62
     */
63
    @Input() thySize: ThyTabsSize = 'md';
64

65
    /**
×
66
     * 激活的项
67
     */
68
    @Input()
×
69
    set thyActiveTab(value: ThyActiveTabInfo) {
×
70
        if (isString(value)) {
71
            this.activeTabId = value;
×
72
            this.activeTabIndex = undefined;
73
        } else {
74
            this.activeTabIndex = value;
×
75
            this.activeTabId = undefined;
×
76
        }
77
    }
×
78

×
79
    /**
×
80
     * 附加操作
×
81
     */
×
82
    @Input() thyExtra: TemplateRef<unknown>;
83

84
    /**
×
85
     * 选项卡的位置
86
     * @type 'top' | 'left'
1✔
87
     */
88
    @Input() thyPosition: ThyTabsPosition = 'top';
89

90
    /**
1✔
91
     * 是否使用动画切换 Tabs
92
     */
93
    @Input() @InputBoolean() thyAnimated: boolean = false;
94

95
    /**
96
     * 响应式,自动计算宽度存放 thyNavItem,并添加更多弹框
97
     */
98
    @Input() @InputBoolean() thyResponsive: boolean = false;
99

100
    /**
101
     * 激活的项发生改变时的回调
102
     */
1✔
103
    @Output() thyActiveTabChange: EventEmitter<ThyTabActiveEvent> = new EventEmitter<ThyTabActiveEvent>();
104

105
    activeTabIndex: number = 0;
106

1✔
107
    activeTabId: string;
108

109
    transitionStarted: boolean = false;
110

1✔
111
    constructor(private cd: ChangeDetectorRef, private el: ElementRef) {
112
        super();
113
    }
114

115
    ngOnInit(): void {
116
        const tabsContent = this.el.nativeElement.querySelector('.thy-tabs-content');
117
        fromEvent(tabsContent, 'transitionend')
118
            .pipe(takeUntil(this.ngUnsubscribe$))
119
            .subscribe(() => {
120
                this.transitionStarted = false;
121
                this.cd.markForCheck();
122
            });
123
    }
124

125
    ngOnChanges(changes: SimpleChanges): void {
126
        const { thyActiveTab } = changes;
127
        if (thyActiveTab && !thyActiveTab.firstChange && this.thyAnimated) {
128
            const index = thyActiveTab?.currentValue?.index || Array.from(this.tabs).findIndex(k => k.id === thyActiveTab?.currentValue.id);
129
            this.transitionStarted = this.activeTabIndex !== index;
130
            this.activeTabIndex = index;
131
        }
132
    }
133

134
    ngAfterContentInit() {
135
        this.tabs.changes.pipe(takeUntil(this.ngUnsubscribe$)).subscribe(data => {
136
            this.thyAnimated && (this.transitionStarted = true);
137
            this.activeTabIndex = data.length - 1;
138
        });
139
    }
140

141
    get tabPaneAnimated(): boolean {
142
        return this.thyPosition === 'top' && this.thyAnimated;
143
    }
144

145
    getTabContentMarginLeft(): string {
146
        if (this.tabPaneAnimated) {
147
            return `${-(this.activeTabIndex || 0) * 100}%`;
148
        }
149
        return '';
150
    }
151

152
    activeTab(tab: ThyTabComponent, index: number) {
153
        if (tab.thyDisabled) {
154
            return;
155
        }
156
        this.activeTabId = tab.id || null;
157
        this.thyAnimated && (this.transitionStarted = this.activeTabIndex !== index);
158
        this.activeTabIndex = index;
159
        const activeTab = tab.id ? tab.id : index;
160
        this.thyActiveTabChange.emit(activeTab);
161
    }
162

163
    tabTrackBy(index: number, item: ThyTabComponent) {
164
        return index;
165
    }
166
}
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