import {
Component,
Input,
Output,
EventEmitter,
ContentChildren,
QueryList,
AfterContentInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
OnDestroy,
inject,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
let nextId = 0;
@Component({
selector: 'mv-tab',
standalone: true,
template: `
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TabComponent {
@Input() label: string = '';
@Input() id: string = `tab-${nextId++}`;
@Input() disabled: boolean = false;
active: boolean = false;
public cdr = inject(ChangeDetectorRef);
}
@Component({
selector: 'mv-tabs',
standalone: true,
imports: [CommonModule],
template: `
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TabsComponent implements AfterContentInit, OnDestroy {
@Input() activeId?: string;
@Input() hostClass = '';
@Output() activeIdChange = new EventEmitter();
@ContentChildren(TabComponent) tabs!: QueryList;
private destroy$ = new Subject();
private cdr = inject(ChangeDetectorRef);
ngAfterContentInit(): void {
this.tabs.changes.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.updateActiveTab();
});
this.updateActiveTab();
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
ngOnChanges(): void {
if (this.tabs) {
this.updateActiveTab();
}
}
selectTab(tab: TabComponent): void {
if (tab.disabled || tab.active) {
return;
}
this.tabs.toArray().forEach((t) => {
t.active = false;
t.cdr.markForCheck();
});
tab.active = true;
tab.cdr.markForCheck();
this.activeIdChange.emit(tab.id);
}
private updateActiveTab(): void {
const tabsArray = this.tabs.toArray();
if (!tabsArray.length) return;
let tabToActivate = tabsArray.find((t) => t.id === this.activeId);
// If no activeId is provided or found, activate the first non-disabled tab
if (!tabToActivate) {
const activeTab = tabsArray.find((t) => t.active);
if (activeTab) {
tabToActivate = activeTab;
} else {
tabToActivate = tabsArray.find((t) => !t.disabled);
}
}
if (tabToActivate) {
this.selectTab(tabToActivate);
}
}
}