import { FocusKeyManager } from '@angular/cdk/a11y';
import { CdkMenuTrigger } from '@angular/cdk/menu';
import { DomPortal, CdkPortalOutlet } from '@angular/cdk/portal';
import { NgTemplateOutlet } from '@angular/common';
import * as i0 from '@angular/core';
import { input, ChangeDetectionStrategy, Component, InjectionToken, booleanAttribute, output, inject, ElementRef, viewChild, TemplateRef, computed, effect, untracked, Directive, contentChildren, INJECTOR, signal, model } from '@angular/core';
import * as i1 from '@angular/router';
import { Router, RouterLink, RouterLinkActive } from '@angular/router';
import { elementCancel, elementOptions } from '@siemens/element-icons';
import { isRTL } from '@siemens/element-ng/common';
import { addIcons, SiIconComponent } from '@siemens/element-ng/icon';
import { SiMenuDirective, SiMenuItemComponent } from '@siemens/element-ng/menu';
import * as i1$1 from '@siemens/element-ng/resize-observer';
import { SiResizeObserverModule } from '@siemens/element-ng/resize-observer';
import { SiTranslatePipe } from '@siemens/element-translate-ng/translate';
import { toSignal } from '@angular/core/rxjs-interop';
import { startWith } from 'rxjs/operators';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiTabBadgeComponent {
    badgeContent = input(...(ngDevMode ? [undefined, { debugName: "badgeContent" }] : []));
    badgeColor = input(...(ngDevMode ? [undefined, { debugName: "badgeColor" }] : []));
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiTabBadgeComponent, isStandalone: true, selector: "si-tab-badge", inputs: { badgeContent: { classPropertyName: "badgeContent", publicName: "badgeContent", isSignal: true, isRequired: false, transformFunction: null }, badgeColor: { classPropertyName: "badgeColor", publicName: "badgeColor", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "d-contents" }, ngImport: i0, template: "@let badgeContent = this.badgeContent();\n@if (badgeContent === true) {\n  <span class=\"badge-dot\"></span>\n} @else if (badgeContent && badgeColor()) {\n  <span class=\"badge\" [class]=\"`bg-${badgeColor() || 'default'}`\">\n    {{ badgeContent ?? '' | translate }}\n  </span>\n} @else if (badgeContent && !badgeColor()) {\n  <span class=\"badge-text\"> {{ badgeContent ?? '' | translate }}</span>\n}\n", styles: [".badge-dot{inset-block-end:100%;inset-inline-start:12px;margin-inline-end:12px}.badge-text{inset-block-end:calc(100% - 7px);inset-inline-start:2px}:host-context(.cdk-menu-item) .badge-dot{inset-block-end:4px;min-inline-size:12px}:host-context(.cdk-menu-item) .badge-text{inset-inline-start:0}:host-context(.cdk-menu-item) .badge{margin-inline:-6px}\n"], dependencies: [{ kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabBadgeComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-tab-badge', imports: [SiTranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, host: {
                        'class': 'd-contents'
                    }, template: "@let badgeContent = this.badgeContent();\n@if (badgeContent === true) {\n  <span class=\"badge-dot\"></span>\n} @else if (badgeContent && badgeColor()) {\n  <span class=\"badge\" [class]=\"`bg-${badgeColor() || 'default'}`\">\n    {{ badgeContent ?? '' | translate }}\n  </span>\n} @else if (badgeContent && !badgeColor()) {\n  <span class=\"badge-text\"> {{ badgeContent ?? '' | translate }}</span>\n}\n", styles: [".badge-dot{inset-block-end:100%;inset-inline-start:12px;margin-inline-end:12px}.badge-text{inset-block-end:calc(100% - 7px);inset-inline-start:2px}:host-context(.cdk-menu-item) .badge-dot{inset-block-end:4px;min-inline-size:12px}:host-context(.cdk-menu-item) .badge-text{inset-inline-start:0}:host-context(.cdk-menu-item) .badge{margin-inline:-6px}\n"] }]
        }], propDecorators: { badgeContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeContent", required: false }] }], badgeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeColor", required: false }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
const SI_TABSET = new InjectionToken('SiTabsetComponent');

class SiTabBaseDirective {
    /** Title of the tab item. */
    heading = input.required(...(ngDevMode ? [{ debugName: "heading" }] : []));
    /**
     * Icon of the tab item.
     * If provided, heading text will be ignored and only icon will be displayed.
     */
    icon = input(...(ngDevMode ? [undefined, { debugName: "icon" }] : []));
    /**
     * Additional badge content. A value of
     * - `true` will render a red dot
     * - any string without a `badgeColor` will render a red dot with text
     * - any string with a `badgeColor` will render a normal badge
     */
    badgeContent = input(...(ngDevMode ? [undefined, { debugName: "badgeContent" }] : []));
    /**
     * Background color of the badge.
     * If no color is provided a red dot badge will be rendered.
     */
    badgeColor = input(...(ngDevMode ? [undefined, { debugName: "badgeColor" }] : []));
    /**
     * Disables the tab.
     *
     * @defaultValue false
     */
    disabledTab = input(false, { ...(ngDevMode ? { debugName: "disabledTab" } : {}), transform: booleanAttribute,
        // eslint-disable-next-line @angular-eslint/no-input-rename
        alias: 'disabled' });
    /**
     * Close the current tab.
     *
     * @defaultValue false
     */
    closable = input(false, { ...(ngDevMode ? { debugName: "closable" } : {}), transform: booleanAttribute });
    /** Event emitter to notify when a tab is closed. */
    closeTriggered = output();
    /** @internal */
    tabButton = inject(ElementRef);
    /** @internal */
    tabContent = viewChild('tabContent', { ...(ngDevMode ? { debugName: "tabContent" } : {}), read: TemplateRef });
    static tabCounter = 0;
    indexBeforeClose = -1;
    /** @internal */
    tabId = `${SiTabBaseDirective.tabCounter++}`;
    icons = addIcons({ elementCancel });
    tabset = inject(SI_TABSET);
    index = computed(() => this.tabset.tabPanels().indexOf(this), ...(ngDevMode ? [{ debugName: "index" }] : []));
    constructor() {
        // Update the focusKeyManager if a tab is added that is active or if the tab is set active by the app.
        // This effect should not run, if active was already applied to the focusKeyManager.
        effect(() => {
            const active = this.active(); // We only want to subscribe to the active signal.
            untracked(() => {
                // !!! focusKeyManger.activeItem has signal reads internally. Do not move this outside of untracked.
                if (active && this.tabset.focusKeyManager.activeItem !== this) {
                    this.tabset.focusKeyManager.updateActiveItem(this.index());
                }
            });
        });
    }
    ngOnDestroy() {
        if (this.indexBeforeClose >= 0) {
            this.tabset.removedTabByUser(this.indexBeforeClose, this.active());
        }
    }
    closeTab(event) {
        if (this.closable() && !this.disabledTab()) {
            event.stopPropagation();
            const index = this.index();
            this.closeTriggered.emit();
            this.indexBeforeClose = index;
        }
    }
    /** @internal */
    focus() {
        this.tabButton.nativeElement.focus({ preventScroll: true });
        // The element is not fully scrolled into view when focused. So we prevent and scroll it manually.
        this.scrollTabIntoView();
    }
    /** @internal */
    get disabled() {
        return this.disabledTab();
    }
    /**
     * Programmatically selects the current tab.
     */
    selectTab(retainFocus) {
        this.tabset.focusKeyManager.updateActiveItem(this.index());
        if (retainFocus) {
            // We need the timeout to wait for cdkMenu to restore the focus before we move it again.
            setTimeout(() => this.focus());
        }
    }
    /** @internal */
    deSelectTab() {
        // Empty be default, can be overridden in derived classes.
    }
    /** @internal */
    scrollTabIntoView() {
        this.tabButton.nativeElement.scrollIntoView({
            inline: 'nearest',
            block: 'nearest',
            behavior: 'instant'
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabBaseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.0.8", type: SiTabBaseDirective, isStandalone: true, selector: "[siTabNextBase]", inputs: { heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, badgeContent: { classPropertyName: "badgeContent", publicName: "badgeContent", isSignal: true, isRequired: false, transformFunction: null }, badgeColor: { classPropertyName: "badgeColor", publicName: "badgeColor", isSignal: true, isRequired: false, transformFunction: null }, disabledTab: { classPropertyName: "disabledTab", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeTriggered: "closeTriggered" }, host: { attributes: { "role": "tab" }, listeners: { "keydown.delete": "closeTab($event)" }, properties: { "class.disabled": "disabledTab()", "class.icon-only": "!!icon()", "class.pe-3": "closable()", "class.active": "active()", "attr.id": "'tab-' + tabId", "attr.aria-selected": "active()", "attr.aria-disabled": "disabledTab()", "attr.tabindex": "tabset.focusKeyManager.activeItem === this && !disabledTab() ? 0 : -1", "attr.aria-controls": "'content-' + tabId" }, classAttribute: "nav-link focus-inside px-5 si-h4" }, viewQueries: [{ propertyName: "tabContent", first: true, predicate: ["tabContent"], descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabBaseDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siTabNextBase]',
                    host: {
                        class: 'nav-link focus-inside px-5 si-h4',
                        role: 'tab',
                        '[class.disabled]': 'disabledTab()',
                        '[class.icon-only]': '!!icon()',
                        '[class.pe-3]': 'closable()',
                        '[class.active]': 'active()',
                        '[attr.id]': "'tab-' + tabId",
                        '[attr.aria-selected]': 'active()',
                        '[attr.aria-disabled]': 'disabledTab()',
                        '[attr.tabindex]': 'tabset.focusKeyManager.activeItem === this && !disabledTab() ? 0 : -1',
                        '[attr.aria-controls]': "'content-' + tabId",
                        '(keydown.delete)': 'closeTab($event)'
                    }
                }]
        }], ctorParameters: () => [], propDecorators: { heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: true }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], badgeContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeContent", required: false }] }], badgeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeColor", required: false }] }], disabledTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], closeTriggered: [{ type: i0.Output, args: ["closeTriggered"] }], tabContent: [{ type: i0.ViewChild, args: ['tabContent', { ...{ read: TemplateRef }, isSignal: true }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * Creates a tab that uses the Angular router.
 *
 * @example
 * ```html
 * <si-tabset>
 *   <a si-tab routerLink="/home" heading="Home"></a>
 *
 *   <router-outlet />
 * </si-tabset>
 * ```
 */
class SiTabLinkComponent extends SiTabBaseDirective {
    router = inject(Router);
    /** @internal */
    routerLink = inject(RouterLink, { self: true });
    routerLinkActive = inject(RouterLinkActive, { self: true });
    /** @defaultValue false */
    active = toSignal(this.routerLinkActive.isActiveChange.pipe(startWith(this.routerLinkActive.isActive)));
    /** {@inheritDoc} */
    selectTab(retainFocus) {
        if (this.routerLink.urlTree) {
            this.router.navigateByUrl(this.routerLink.urlTree, {
                skipLocationChange: this.routerLink.skipLocationChange,
                replaceUrl: this.routerLink.replaceUrl,
                info: this.routerLink.info,
                state: this.routerLink.state
            });
        }
        super.selectTab(retainFocus);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabLinkComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiTabLinkComponent, isStandalone: true, selector: "a[si-tab][routerLink]", providers: [{ provide: SiTabBaseDirective, useExisting: SiTabLinkComponent }], usesInheritance: true, hostDirectives: [{ directive: i1.RouterLinkActive }], ngImport: i0, template: "@let icon = this.icon();\n@if (icon) {\n  <si-icon class=\"tab-icon\" [icon]=\"icon\" [attr.title]=\"heading() | translate\" />\n} @else {\n  <span class=\"text-truncate\">{{ heading() | translate }}</span>\n}\n<si-tab-badge [badgeColor]=\"badgeColor()\" [badgeContent]=\"badgeContent()\" />\n@if (closable() && !disabledTab()) {\n  <si-icon\n    class=\"ms-2 btn btn-circle btn-sm btn-ghost close\"\n    [icon]=\"icons.elementCancel\"\n    (click)=\"closeTab($event)\"\n  />\n}\n\n<ng-template #tabContent>\n  <ng-content />\n</ng-template>\n", styles: [":host.nav-link{flex-shrink:0;transform:translate(0)}:host.nav-link.icon-only{min-inline-size:auto}.tab-icon{font-size:24px}\n"], dependencies: [{ kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "component", type: SiTabBadgeComponent, selector: "si-tab-badge", inputs: ["badgeContent", "badgeColor"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabLinkComponent, decorators: [{
            type: Component,
            args: [{ selector: 'a[si-tab][routerLink]', imports: [SiIconComponent, SiTranslatePipe, SiTabBadgeComponent], providers: [{ provide: SiTabBaseDirective, useExisting: SiTabLinkComponent }], changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [
                        {
                            directive: RouterLinkActive
                        }
                    ], template: "@let icon = this.icon();\n@if (icon) {\n  <si-icon class=\"tab-icon\" [icon]=\"icon\" [attr.title]=\"heading() | translate\" />\n} @else {\n  <span class=\"text-truncate\">{{ heading() | translate }}</span>\n}\n<si-tab-badge [badgeColor]=\"badgeColor()\" [badgeContent]=\"badgeContent()\" />\n@if (closable() && !disabledTab()) {\n  <si-icon\n    class=\"ms-2 btn btn-circle btn-sm btn-ghost close\"\n    [icon]=\"icons.elementCancel\"\n    (click)=\"closeTab($event)\"\n  />\n}\n\n<ng-template #tabContent>\n  <ng-content />\n</ng-template>\n", styles: [":host.nav-link{flex-shrink:0;transform:translate(0)}:host.nav-link.icon-only{min-inline-size:auto}.tab-icon{font-size:24px}\n"] }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * A component to group multiple tabs together.
 * Can either be used with {@link SiTabLinkComponent} or {@link SiTabComponent} components.
 */
class SiTabsetComponent {
    /**
     * When set, the overflowing content inside the tab will automatically scroll
     * @defaultValue false
     **/
    contentOverflowAuto = input(false, { ...(ngDevMode ? { debugName: "contentOverflowAuto" } : {}), transform: booleanAttribute });
    icons = addIcons({ elementOptions });
    contentNode = viewChild.required('contentNode');
    /**
     * A `DomPortal` wrapping the tab panel container. Used by {@link SiTabPortalComponent}
     * to render the active tab's content at a remote location in the DOM.
     *
     * @internal
     */
    contentPortal = computed(() => new DomPortal(this.contentNode()), ...(ngDevMode ? [{ debugName: "contentPortal" }] : []));
    /** @internal */
    activeTab = computed(() => this.tabPanels().find(tab => tab.active()), ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
    /** @internal */
    tabPanels = contentChildren(SiTabBaseDirective, ...(ngDevMode ? [{ debugName: "tabPanels" }] : []));
    /** @internal */
    focusKeyManager = new FocusKeyManager(this.tabPanels, inject(INJECTOR))
        .withHorizontalOrientation(isRTL() ? 'rtl' : 'ltr')
        .withWrap(true);
    /** @internal */
    showMenuButton = signal(false, ...(ngDevMode ? [{ debugName: "showMenuButton" }] : []));
    tabIsLink(tab) {
        return tab instanceof SiTabLinkComponent;
    }
    constructor() {
        effect(() => {
            if (this.showMenuButton() && this.activeTab()) {
                // wait for menu button to render on DOM
                setTimeout(() => {
                    this.activeTab()?.scrollTabIntoView();
                });
            }
        });
    }
    /** @internal */
    removedTabByUser(index, active) {
        // The tab was already removed from the tabPanels list when this function is called.
        // We need to:
        // - focus another tab if the closed one was focused
        // - activate another tab if the closed one was active
        // If the closed tab was not focussed, there is no need to restore the focus as it could only be closed by mouse.
        for (let i = 0; i < this.tabPanels().length; i++) {
            // Get the actual index using modulo to wrap around
            const checkIndex = (index + i) % this.tabPanels().length;
            const checkTab = this.tabPanels()[checkIndex];
            if (!checkTab.disabledTab()) {
                if (this.focusKeyManager.activeItemIndex === index) {
                    this.focusKeyManager.setActiveItem(checkIndex);
                }
                if (active) {
                    checkTab.selectTab(true);
                }
                return;
            }
        }
    }
    resizeContainer(width, scrollWidth) {
        // 48px is the width of the menu button.
        this.showMenuButton.set(scrollWidth > width + (this.showMenuButton() ? 48 : 0));
    }
    keydown(event) {
        this.focusKeyManager.onKeydown(event);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiTabsetComponent, isStandalone: true, selector: "si-tabset", inputs: { contentOverflowAuto: { classPropertyName: "contentOverflowAuto", publicName: "contentOverflowAuto", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
            {
                provide: SI_TABSET,
                useExisting: SiTabsetComponent
            }
        ], queries: [{ propertyName: "tabPanels", predicate: SiTabBaseDirective, isSignal: true }], viewQueries: [{ propertyName: "contentNode", first: true, predicate: ["contentNode"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tabs-container\">\n  <div class=\"tab-container-buttonbar-list nav nav-tabs\">\n    <div\n      #tabScrollContainer\n      role=\"tablist\"\n      tabindex=\"-1\"\n      class=\"d-flex tabs-wrapper\"\n      (siResizeObserver)=\"\n        resizeContainer(tabScrollContainer.clientWidth, tabScrollContainer.scrollWidth)\n      \"\n      (keydown)=\"keydown($event)\"\n    >\n      <ng-content />\n    </div>\n\n    @if (showMenuButton()) {\n      <button\n        type=\"button\"\n        class=\"dropdown btn btn-tertiary focus-inside\"\n        tabindex=\"-1\"\n        aria-hidden=\"true\"\n        [cdkMenuTriggerFor]=\"tabsMenu\"\n      >\n        <si-icon class=\"icon m-0\" [icon]=\"icons.elementOptions\" />\n      </button>\n    }\n  </div>\n  @let tabContent = this.activeTab()?.tabContent();\n  @let activeTab = this.activeTab();\n\n  <div #contentNode class=\"d-contents\">\n    @if (activeTab) {\n      <div\n        class=\"tab-content focus-inside\"\n        role=\"tabpanel\"\n        [id]=\"`content-${activeTab.tabId}`\"\n        [class.tab-scroll]=\"contentOverflowAuto()\"\n        [tabIndex]=\"contentOverflowAuto() ? '0' : null\"\n        [attr.aria-labelledby]=\"`tab-${activeTab.tabId}`\"\n      >\n        @if (tabContent) {\n          <ng-container [ngTemplateOutlet]=\"tabContent\" />\n        }\n\n        <ng-content select=\"router-outlet\" />\n      </div>\n    }\n  </div>\n</div>\n\n<ng-template #tabsMenu>\n  <si-menu>\n    @for (tab of tabPanels(); track tab) {\n      @if (tabIsLink(tab)) {\n        <a\n          si-menu-item\n          [disabled]=\"tab.disabledTab()\"\n          [icon]=\"tab.icon()\"\n          [routerLink]=\"tab.routerLink.urlTree\"\n          (triggered)=\"tab.selectTab(true)\"\n        >\n          <ng-container [ngTemplateOutlet]=\"badgeTemplate\" [ngTemplateOutletContext]=\"{ tab }\" />\n        </a>\n      } @else {\n        <button\n          type=\"button\"\n          si-menu-item\n          [disabled]=\"tab.disabledTab()\"\n          [icon]=\"tab.icon()\"\n          (triggered)=\"tab.selectTab(true)\"\n        >\n          <ng-container [ngTemplateOutlet]=\"badgeTemplate\" [ngTemplateOutletContext]=\"{ tab }\" />\n        </button>\n      }\n    }\n  </si-menu>\n</ng-template>\n\n<ng-template #badgeTemplate let-tab=\"tab\">\n  <div class=\"d-flex align-items-center space-between flex-no-wrap justify-content-between\">\n    {{ tab.heading() }}\n    <si-tab-badge [badgeContent]=\"tab.badgeContent()\" [badgeColor]=\"tab.badgeColor()\" />\n  </div>\n</ng-template>\n", styles: [":host{display:block;flex-direction:column}.tabs-container{display:flex;flex-direction:column;overflow:hidden;block-size:100%;min-block-size:40px}.tabs-container:before{inset-block-start:38px;inset-block-end:auto}.btn.dropdown{color:var(--element-text-primary);min-inline-size:0;border-block-end:2px solid var(--element-ui-4);block-size:40px;padding-inline:12px;flex-shrink:0}.btn.dropdown:hover{border-color:var(--element-ui-4);color:var(--element-action-secondary-text-hover)}.tab-content{flex-grow:1}.tab-scroll{flex-basis:0;overflow:auto}.tabs-wrapper{overflow-y:hidden;overflow-x:auto;scroll-behavior:smooth;scrollbar-width:none}\n"], dependencies: [{ kind: "directive", type: SiMenuDirective, selector: "si-menu" }, { kind: "component", type: SiMenuItemComponent, selector: "si-menu-item, a[si-menu-item], button[si-menu-item]" }, { kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData", "cdkMenuTriggerTransformOriginOn"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: SiResizeObserverModule }, { kind: "directive", type: i1$1.SiResizeObserverDirective, selector: "[siResizeObserver]", inputs: ["resizeThrottle", "emitInitial"], outputs: ["siResizeObserver"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: SiTabBadgeComponent, selector: "si-tab-badge", inputs: ["badgeContent", "badgeColor"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabsetComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-tabset', imports: [
                        SiMenuDirective,
                        SiMenuItemComponent,
                        CdkMenuTrigger,
                        NgTemplateOutlet,
                        SiResizeObserverModule,
                        RouterLink,
                        SiTabBadgeComponent,
                        SiIconComponent
                    ], providers: [
                        {
                            provide: SI_TABSET,
                            useExisting: SiTabsetComponent
                        }
                    ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tabs-container\">\n  <div class=\"tab-container-buttonbar-list nav nav-tabs\">\n    <div\n      #tabScrollContainer\n      role=\"tablist\"\n      tabindex=\"-1\"\n      class=\"d-flex tabs-wrapper\"\n      (siResizeObserver)=\"\n        resizeContainer(tabScrollContainer.clientWidth, tabScrollContainer.scrollWidth)\n      \"\n      (keydown)=\"keydown($event)\"\n    >\n      <ng-content />\n    </div>\n\n    @if (showMenuButton()) {\n      <button\n        type=\"button\"\n        class=\"dropdown btn btn-tertiary focus-inside\"\n        tabindex=\"-1\"\n        aria-hidden=\"true\"\n        [cdkMenuTriggerFor]=\"tabsMenu\"\n      >\n        <si-icon class=\"icon m-0\" [icon]=\"icons.elementOptions\" />\n      </button>\n    }\n  </div>\n  @let tabContent = this.activeTab()?.tabContent();\n  @let activeTab = this.activeTab();\n\n  <div #contentNode class=\"d-contents\">\n    @if (activeTab) {\n      <div\n        class=\"tab-content focus-inside\"\n        role=\"tabpanel\"\n        [id]=\"`content-${activeTab.tabId}`\"\n        [class.tab-scroll]=\"contentOverflowAuto()\"\n        [tabIndex]=\"contentOverflowAuto() ? '0' : null\"\n        [attr.aria-labelledby]=\"`tab-${activeTab.tabId}`\"\n      >\n        @if (tabContent) {\n          <ng-container [ngTemplateOutlet]=\"tabContent\" />\n        }\n\n        <ng-content select=\"router-outlet\" />\n      </div>\n    }\n  </div>\n</div>\n\n<ng-template #tabsMenu>\n  <si-menu>\n    @for (tab of tabPanels(); track tab) {\n      @if (tabIsLink(tab)) {\n        <a\n          si-menu-item\n          [disabled]=\"tab.disabledTab()\"\n          [icon]=\"tab.icon()\"\n          [routerLink]=\"tab.routerLink.urlTree\"\n          (triggered)=\"tab.selectTab(true)\"\n        >\n          <ng-container [ngTemplateOutlet]=\"badgeTemplate\" [ngTemplateOutletContext]=\"{ tab }\" />\n        </a>\n      } @else {\n        <button\n          type=\"button\"\n          si-menu-item\n          [disabled]=\"tab.disabledTab()\"\n          [icon]=\"tab.icon()\"\n          (triggered)=\"tab.selectTab(true)\"\n        >\n          <ng-container [ngTemplateOutlet]=\"badgeTemplate\" [ngTemplateOutletContext]=\"{ tab }\" />\n        </button>\n      }\n    }\n  </si-menu>\n</ng-template>\n\n<ng-template #badgeTemplate let-tab=\"tab\">\n  <div class=\"d-flex align-items-center space-between flex-no-wrap justify-content-between\">\n    {{ tab.heading() }}\n    <si-tab-badge [badgeContent]=\"tab.badgeContent()\" [badgeColor]=\"tab.badgeColor()\" />\n  </div>\n</ng-template>\n", styles: [":host{display:block;flex-direction:column}.tabs-container{display:flex;flex-direction:column;overflow:hidden;block-size:100%;min-block-size:40px}.tabs-container:before{inset-block-start:38px;inset-block-end:auto}.btn.dropdown{color:var(--element-text-primary);min-inline-size:0;border-block-end:2px solid var(--element-ui-4);block-size:40px;padding-inline:12px;flex-shrink:0}.btn.dropdown:hover{border-color:var(--element-ui-4);color:var(--element-action-secondary-text-hover)}.tab-content{flex-grow:1}.tab-scroll{flex-basis:0;overflow:auto}.tabs-wrapper{overflow-y:hidden;overflow-x:auto;scroll-behavior:smooth;scrollbar-width:none}\n"] }]
        }], ctorParameters: () => [], propDecorators: { contentOverflowAuto: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentOverflowAuto", required: false }] }], contentNode: [{ type: i0.ViewChild, args: ['contentNode', { isSignal: true }] }], tabPanels: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SiTabBaseDirective), { isSignal: true }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * Creates a normal tab that can contain any content.
 *
 * @example
 * ```html
 * <si-tabset>
 *   <si-tab heading="Tab 1">
 *     <p>Content of Tab 1</p>
 *   </si-tab>
 * </si-tabset>
 * ```
 */
class SiTabComponent extends SiTabBaseDirective {
    /**
     * Whether the tab is active or not.
     * If set to `true`, the tab will be selected and its content will be displayed.
     * @defaultValue false
     * */
    active = model(false, ...(ngDevMode ? [{ debugName: "active" }] : []));
    /**
     * Guard to check if the tab can be activated.
     * If not provided, the tab can always be activated.
     */
    canActivate = input(...(ngDevMode ? [undefined, { debugName: "canActivate" }] : []));
    /**
     * Guard to check if the tab can be deactivated.
     * If not provided, the tab can always be deactivated.
     */
    canDeactivate = input(...(ngDevMode ? [undefined, { debugName: "canDeactivate" }] : []));
    selectTabByUser() {
        const canActivate = this.canActivate();
        if (!this.active() && (canActivate ? canActivate() : true)) {
            this.selectTab();
        }
    }
    /** {@inheritDoc} */
    selectTab(retainFocus) {
        const activeTab = this.tabset.activeTab();
        if (activeTab instanceof SiTabComponent) {
            const canDeactivate = activeTab?.canDeactivate();
            if (canDeactivate ? !canDeactivate() : false) {
                return;
            }
        }
        this.tabset.activeTab()?.deSelectTab();
        this.active.set(true);
        super.selectTab(retainFocus);
    }
    /** @internal */
    deSelectTab() {
        this.active.set(false);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiTabComponent, isStandalone: true, selector: "si-tab", inputs: { active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, canActivate: { classPropertyName: "canActivate", publicName: "canActivate", isSignal: true, isRequired: false, transformFunction: null }, canDeactivate: { classPropertyName: "canDeactivate", publicName: "canDeactivate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { active: "activeChange" }, host: { listeners: { "click": "selectTabByUser()", "keydown.enter": "selectTabByUser()" } }, providers: [{ provide: SiTabBaseDirective, useExisting: SiTabComponent }], usesInheritance: true, ngImport: i0, template: "@let icon = this.icon();\n@if (icon) {\n  <si-icon class=\"tab-icon\" [icon]=\"icon\" [attr.title]=\"heading() | translate\" />\n} @else {\n  <span class=\"text-truncate\">{{ heading() | translate }}</span>\n}\n<si-tab-badge [badgeColor]=\"badgeColor()\" [badgeContent]=\"badgeContent()\" />\n@if (closable() && !disabledTab()) {\n  <si-icon\n    class=\"ms-2 btn btn-circle btn-sm btn-ghost close\"\n    [icon]=\"icons.elementCancel\"\n    (click)=\"closeTab($event)\"\n  />\n}\n\n<ng-template #tabContent>\n  <ng-content />\n</ng-template>\n", styles: [":host.nav-link{flex-shrink:0;transform:translate(0)}:host.nav-link.icon-only{min-inline-size:auto}.tab-icon{font-size:24px}\n"], dependencies: [{ kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "component", type: SiTabBadgeComponent, selector: "si-tab-badge", inputs: ["badgeContent", "badgeColor"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-tab', imports: [SiIconComponent, SiTranslatePipe, SiTabBadgeComponent], providers: [{ provide: SiTabBaseDirective, useExisting: SiTabComponent }], changeDetection: ChangeDetectionStrategy.OnPush, host: {
                        '(click)': 'selectTabByUser()',
                        '(keydown.enter)': 'selectTabByUser()'
                    }, template: "@let icon = this.icon();\n@if (icon) {\n  <si-icon class=\"tab-icon\" [icon]=\"icon\" [attr.title]=\"heading() | translate\" />\n} @else {\n  <span class=\"text-truncate\">{{ heading() | translate }}</span>\n}\n<si-tab-badge [badgeColor]=\"badgeColor()\" [badgeContent]=\"badgeContent()\" />\n@if (closable() && !disabledTab()) {\n  <si-icon\n    class=\"ms-2 btn btn-circle btn-sm btn-ghost close\"\n    [icon]=\"icons.elementCancel\"\n    (click)=\"closeTab($event)\"\n  />\n}\n\n<ng-template #tabContent>\n  <ng-content />\n</ng-template>\n", styles: [":host.nav-link{flex-shrink:0;transform:translate(0)}:host.nav-link.icon-only{min-inline-size:auto}.tab-icon{font-size:24px}\n"] }]
        }], propDecorators: { active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }, { type: i0.Output, args: ["activeChange"] }], canActivate: [{ type: i0.Input, args: [{ isSignal: true, alias: "canActivate", required: false }] }], canDeactivate: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDeactivate", required: false }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * A component that renders the active tab's content at a remote
 * location in the DOM using an Angular CDK `DomPortal`.
 *
 * This component **automatically** renders the content of the currently
 * active `si-tab`, including the `role="tabpanel"` container with proper
 * ARIA attributes linked to the active tab.
 *
 * @example
 * ```html
 * <si-tabset #tabset>
 *   <si-tab heading="Overview" [active]="true">
 *     overview content
 *   </si-tab>
 *   <si-tab heading="History">
 *     history content
 *   </si-tab>
 * </si-tabset>
 *
 * <si-tab-portal [tabset]="tabset" />
 * ```
 */
class SiTabPortalComponent {
    /**
     * Reference to the {@link SiTabsetComponent} whose active tab content
     * this component renders via a `DomPortal`.
     *
     * The tabset's tab panel container, including the `role="tabpanel"` element
     * with proper ARIA attributes, is transported to this component's location.
     */
    tabset = input.required(...(ngDevMode ? [{ debugName: "tabset" }] : []));
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabPortalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.8", type: SiTabPortalComponent, isStandalone: true, selector: "si-tab-portal", inputs: { tabset: { classPropertyName: "tabset", publicName: "tabset", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: ` <ng-template [cdkPortalOutlet]="tabset().contentPortal()" /> `, isInline: true, dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTabPortalComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'si-tab-portal',
                    imports: [CdkPortalOutlet],
                    template: ` <ng-template [cdkPortalOutlet]="tabset().contentPortal()" /> `,
                    changeDetection: ChangeDetectionStrategy.OnPush
                }]
        }], propDecorators: { tabset: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabset", required: true }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * Generated bundle index. Do not edit.
 */

export { SiTabComponent, SiTabLinkComponent, SiTabPortalComponent, SiTabsetComponent };
//# sourceMappingURL=siemens-element-ng-tabs.mjs.map
