/// /// Copyright 2015-2026 Micro Focus or one of its affiliates. /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// import { NgClass, NgTemplateOutlet, AsyncPipe } from '@angular/common'; import { Component, ElementRef, HostBinding, inject, Input, ViewChild } from '@angular/core'; import { ResizeDimensions } from '../../../directives/resize'; import { ResizeDirective } from '../../../directives/resize/resize.directive'; import { IconComponent } from '../../icon/icon.component'; import { CardTabComponent } from '../card-tab/card-tab.component'; import { CardTabsService } from '../card-tabs.service'; @Component({ selector: 'ux-card-tabset', templateUrl: './card-tabset.component.html', providers: [CardTabsService], imports: [IconComponent, ResizeDirective, NgClass, NgTemplateOutlet, AsyncPipe], }) export class CardTabsetComponent { tabService = inject(CardTabsService); @HostBinding('class') @Input() set position(direction: string) { this.tabService.setPosition(direction); } get position(): string { return this.tabService.position$.getValue(); } @ViewChild('tablist', { static: true }) tablist: ElementRef; offset: number = 0; bounds: CardTabsBounds = { lower: 0, upper: 0 }; private _width: number; private _innerWidth: number; select(tab: CardTabComponent, element: HTMLElement): void { // select the tab this.tabService.select(tab); // ensure the tab is moved into view if required this.moveIntoView(element); } resize(dimensions: ResizeDimensions): void { this._width = dimensions.width; this._innerWidth = this.tablist.nativeElement.scrollWidth; this.bounds.lower = 0; this.bounds.upper = -(this._innerWidth - this._width); } previous(): void { this.offset += this._width; // ensure it remains within the allowed bounds this.offset = Math.min(this.offset, this.bounds.lower); } next(): void { this.offset -= this._width; // ensure it remains within the allowed bounds this.offset = Math.max(this.offset, this.bounds.upper); } private moveIntoView(element: HTMLElement): void { // if we dont have the dimensions we cant check if (!this._width || !this._innerWidth) { return; } // get the current element bounds const { offsetLeft, offsetWidth } = element; const { marginLeft, marginRight } = getComputedStyle(element); // calculate the visible area const viewportStart = Math.abs(this.offset); const viewportEnd = viewportStart + this._width; const cardWidth = parseFloat(marginLeft) + offsetWidth + parseFloat(marginRight); // if we need to move to the left - figure out how much if (offsetLeft < viewportStart) { this.offset -= offsetLeft - parseFloat(marginLeft) - viewportStart; } // if we need to move to the right - figure out how much if (offsetLeft + cardWidth > viewportEnd) { this.offset -= offsetLeft + cardWidth - viewportEnd; } } } export interface CardTabsBounds { lower: number; upper: number; }