import { Component, Input, Output, Renderer2, ViewChild, ViewChildren, QueryList, ElementRef, AfterViewInit, } from '@angular/core'; import { EventEmitter } from '@angular/core'; import { NgClass } from '@angular/common'; // Pipes import { ToolbarTabsClassPipe } from './pipes/toolbar-tabs-class-pipe'; // Enums import { eToolbarVariant } from './enums'; // Interfaces import { IToolbarTabs } from './interfaces'; // Types import { ToolbarVariantType } from './types'; @Component({ selector: 'ca-toolbar-tab-switch', templateUrl: './ca-toolbar-tab-switch.component.html', styleUrl: './ca-toolbar-tab-switch.component.scss', imports: [NgClass, ToolbarTabsClassPipe], }) export class CaToolbarTabSwitchComponent implements AfterViewInit { @ViewChild('tabSwitchIndicator') indicator!: ElementRef; @ViewChildren('tabSwitchItems') tabItems!: QueryList< ElementRef >; @Input() set selectedTab(value: string | undefined) { this._selectedTab = value; if (this.indicator && this.tabItems) { this.animateIndicatorTransition(); } } @Input() set data(value: IToolbarTabs[] | undefined) { this._data = value; if (this.indicator && this.tabItems) { requestAnimationFrame(() => this.updateIndicatorPosition()); } } @Input() variant: ToolbarVariantType = eToolbarVariant.Large; @Output() tabSelected = new EventEmitter(); get data(): IToolbarTabs[] | undefined { return this._data; } get selectedTab(): string | undefined { return this._selectedTab; } private _selectedTab?: string; private _data?: IToolbarTabs[]; public isAnimating: boolean = false; public toolbarVariant = eToolbarVariant; constructor(private renderer: Renderer2) {} ngAfterViewInit() { if (this._selectedTab) { requestAnimationFrame(() => this.updateIndicatorPosition()); } } private updateIndicatorPosition() { if (!this.indicator || !this.tabItems || !this._selectedTab) { return; } const isLargeLayout = this.variant === this.toolbarVariant.Large; const tabItemsArray = this.tabItems.toArray(); tabItemsArray.forEach((tabItem) => { this.renderer.removeClass(tabItem.nativeElement, 'active'); }); const activeTabIndex = this.data?.findIndex((item) => { return isLargeLayout ? item.title === this._selectedTab : item.name === this._selectedTab; }); if (activeTabIndex === undefined) { return; } if (activeTabIndex === -1 || !tabItemsArray[activeTabIndex]) { return; } const activeTabElement = tabItemsArray[activeTabIndex].nativeElement; const left = activeTabElement.offsetLeft; const width = activeTabElement.offsetWidth; this.renderer.addClass(activeTabElement, 'active'); this.renderer.setStyle( this.indicator.nativeElement, 'left', `${left}px` ); this.renderer.setStyle( this.indicator.nativeElement, 'width', `${width}px` ); } private animateIndicatorTransition(): void { this.renderer.addClass( this.indicator.nativeElement, 'transition-left-width' ); requestAnimationFrame(() => { this.updateIndicatorPosition(); const indicatorElement = this.indicator.nativeElement; const handleTransitionEnd = () => { this.renderer.removeClass( indicatorElement, 'transition-left-width' ); indicatorElement.removeEventListener( 'transitionend', handleTransitionEnd ); }; indicatorElement.addEventListener( 'transitionend', handleTransitionEnd ); }); } public onTabClick(event: MouseEvent, tabName: string) { event.stopPropagation(); if (tabName !== this.selectedTab) { this.tabSelected.emit(tabName); } } }