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); } } }