-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathtab-group.component.ts
More file actions
115 lines (101 loc) · 2.91 KB
/
tab-group.component.ts
File metadata and controls
115 lines (101 loc) · 2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { CommonModule } from '@angular/common';
import {
AfterContentInit,
AfterViewInit,
ChangeDetectionStrategy,
Component,
contentChildren,
effect,
ElementRef,
HostListener,
signal,
viewChildren
} from '@angular/core';
import { CodeTabComponent } from '../tab.component';
@Component({
selector: 'code-tab-group',
imports: [CommonModule],
templateUrl: './tab-group.component.html',
styleUrl: './tab-group.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CodeTabGroupComponent implements AfterViewInit, AfterContentInit {
@HostListener('window:resize')
onResize(): void {
const tab = this.activeTab();
if (!tab) {
return;
}
this.setSelectorStyle();
}
/**
* The CodeTabComponents supplied into the CodeTabGroupComponent.
*/
protected tabComponents = contentChildren(CodeTabComponent);
/**
* The tab buttons that allow you to choose which tab to open.
*/
protected tabLabelEls = viewChildren<ElementRef<HTMLDivElement>>('tab');
/**
* The tab that has its content currently displayed.
*/
protected activeTab = signal<CodeTabComponent | null>(null);
/**
* A record that is used to update the CSS styles of the selector.
*/
protected selectorStyles = signal<Record<string, string>>({});
constructor() {
// Handles the active tab changing.
effect(() => {
const activeTab = this.activeTab();
if (!activeTab) {
return;
}
for (const tab of this.tabComponents()) {
if (activeTab === tab) {
tab.isActive.set(true);
const selectedTabEl = this.tabLabelEls()[tab.tabIndex()];
this.selectorStyles.set({
left: `${selectedTabEl.nativeElement.offsetLeft}px`,
width: `${selectedTabEl.nativeElement.offsetWidth}px`
});
this.setSelectorStyle();
continue;
}
if (tab.isActive()) {
tab.isActive.set(false);
}
}
});
}
ngAfterContentInit(): void {
if (!this.tabComponents().length) {
throw new Error('No tab components found.');
}
for (const [index, tab] of this.tabComponents().entries()) {
tab.tabIndex.set(index);
}
// Set the first tab child as the active one.
this.tabComponents()[0].isActive.set(true);
}
ngAfterViewInit(): void {
if (!this.tabLabelEls().length) {
throw new Error('No tab labels found.');
}
this.activeTab.set(this.tabComponents()[0]);
}
/**
* Changes the style of the tab selector, which makes it move to the currently active tab.
*/
private setSelectorStyle(): void {
const activeTab = this.activeTab();
if (!activeTab) {
return;
}
const selectedTabEl = this.tabLabelEls()[activeTab.tabIndex()];
this.selectorStyles.set({
left: `${selectedTabEl.nativeElement.offsetLeft}px`,
width: `${selectedTabEl.nativeElement.offsetWidth}px`
});
}
}