import * as i0 from '@angular/core';
import { InjectionToken, signal, inject, ElementRef, computed, TemplateRef, Component, Injector, Injectable, input, booleanAttribute, PLATFORM_ID, Directive, NgModule } from '@angular/core';
import { NgTemplateOutlet, NgComponentOutlet, isPlatformBrowser } from '@angular/common';
import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { calculateOverlayArrowPosition, getPositionStrategy, getOverlay } from '@siemens/element-ng/common';
import { SiTranslatePipe } from '@siemens/element-translate-ng/translate';

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

class TooltipComponent {
    tooltipPositionClass = signal('', ...(ngDevMode ? [{ debugName: "tooltipPositionClass" }] : []));
    arrowPos = signal(undefined, ...(ngDevMode ? [{ debugName: "arrowPos" }] : []));
    config = inject(SI_TOOLTIP_CONFIG);
    elementRef = inject(ElementRef);
    tooltipText = computed(() => {
        const tooltip = this.config.tooltip();
        return typeof tooltip === 'string' ? tooltip : null;
    }, ...(ngDevMode ? [{ debugName: "tooltipText" }] : []));
    tooltipTemplate = computed(() => {
        const tooltip = this.config.tooltip();
        return tooltip instanceof TemplateRef ? tooltip : null;
    }, ...(ngDevMode ? [{ debugName: "tooltipTemplate" }] : []));
    tooltipComponent = computed(() => {
        const tooltip = this.config.tooltip();
        return !(tooltip instanceof TemplateRef) && typeof tooltip !== 'string' ? tooltip : null;
    }, ...(ngDevMode ? [{ debugName: "tooltipComponent" }] : []));
    /** @internal */
    updateTooltipPosition(change, anchor) {
        const arrowClassTooltip = `tooltip-${change.connectionPair.overlayX}-${change.connectionPair.overlayY}`;
        // need two updates as class changes affect the position
        if (arrowClassTooltip !== this.tooltipPositionClass()) {
            this.tooltipPositionClass.set(arrowClassTooltip);
        }
        const arrowPos = calculateOverlayArrowPosition(change, this.elementRef, anchor);
        this.arrowPos.set(arrowPos);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: TooltipComponent, isStandalone: true, selector: "si-tooltip", host: { attributes: { "animate.leave": "tooltip-leave" } }, ngImport: i0, template: "<div\n  class=\"tooltip show position-relative\"\n  role=\"tooltip\"\n  [id]=\"config.id\"\n  [class]=\"tooltipPositionClass()\"\n>\n  <div\n    class=\"tooltip-arrow\"\n    [style.left.px]=\"arrowPos()?.left\"\n    [style.right.px]=\"arrowPos()?.right\"\n  ></div>\n  <div class=\"tooltip-inner\">\n    @if (tooltipText()) {\n      <div class=\"si-body\">{{ tooltipText() | translate }}</div>\n    } @else if (tooltipTemplate()) {\n      <ng-template\n        [ngTemplateOutlet]=\"tooltipTemplate()\"\n        [ngTemplateOutletContext]=\"config.tooltipContext()\"\n      />\n    } @else if (tooltipComponent()) {\n      <ng-container [ngComponentOutlet]=\"tooltipComponent()!\" />\n    }\n  </div>\n</div>\n", styles: [":host .tooltip,:host{transition:opacity calc(.15s * var(--element-animations-enabled, 1)) ease-out,transform calc(.15s * var(--element-animations-enabled, 1)) ease-out}:host{opacity:1;transform:scale(1)}:host.tooltip-leave{opacity:0;transform:scale(.8)}@starting-style{:host .tooltip{opacity:0;transform:scale(.8)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TooltipComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-tooltip', imports: [NgTemplateOutlet, SiTranslatePipe, NgComponentOutlet], host: {
                        'animate.leave': 'tooltip-leave'
                    }, template: "<div\n  class=\"tooltip show position-relative\"\n  role=\"tooltip\"\n  [id]=\"config.id\"\n  [class]=\"tooltipPositionClass()\"\n>\n  <div\n    class=\"tooltip-arrow\"\n    [style.left.px]=\"arrowPos()?.left\"\n    [style.right.px]=\"arrowPos()?.right\"\n  ></div>\n  <div class=\"tooltip-inner\">\n    @if (tooltipText()) {\n      <div class=\"si-body\">{{ tooltipText() | translate }}</div>\n    } @else if (tooltipTemplate()) {\n      <ng-template\n        [ngTemplateOutlet]=\"tooltipTemplate()\"\n        [ngTemplateOutletContext]=\"config.tooltipContext()\"\n      />\n    } @else if (tooltipComponent()) {\n      <ng-container [ngComponentOutlet]=\"tooltipComponent()!\" />\n    }\n  </div>\n</div>\n", styles: [":host .tooltip,:host{transition:opacity calc(.15s * var(--element-animations-enabled, 1)) ease-out,transform calc(.15s * var(--element-animations-enabled, 1)) ease-out}:host{opacity:1;transform:scale(1)}:host.tooltip-leave{opacity:0;transform:scale(.8)}@starting-style{:host .tooltip{opacity:0;transform:scale(.8)}}\n"] }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * TooltipRef is attached to a specific element.
 * Use it to show or hide a tooltip for that element.
 *
 * @internal
 */
class TooltipRef {
    overlayRef;
    element;
    injector;
    constructor(overlayRef, element, injector) {
        this.overlayRef = overlayRef;
        this.element = element;
        this.injector = injector;
    }
    subscription;
    show() {
        if (this.overlayRef.hasAttached()) {
            return;
        }
        const toolTipPortal = new ComponentPortal(TooltipComponent, undefined, this.injector);
        const tooltipRef = this.overlayRef.attach(toolTipPortal);
        const positionStrategy = getPositionStrategy(this.overlayRef);
        this.subscription?.unsubscribe();
        this.subscription = positionStrategy?.positionChanges.subscribe(change => tooltipRef.instance.updateTooltipPosition(change, this.element));
    }
    hide() {
        this.overlayRef.detach();
        this.subscription?.unsubscribe();
    }
    destroy() {
        this.overlayRef.dispose();
        this.subscription?.unsubscribe();
    }
}
/**
 * A service to create tooltips for specific elements.
 * Use this if the tooltip directive is not suitable.
 * Must not be used outside element-ng.
 *
 * @internal
 */
// We cannot provide this in root, as people may override the cdk overlay creation.
class SiTooltipService {
    overlay = inject(Overlay);
    createTooltip(config) {
        const injector = Injector.create({
            parent: config.injector,
            providers: [
                {
                    provide: SI_TOOLTIP_CONFIG,
                    useValue: {
                        id: config.describedBy,
                        tooltip: config.tooltip,
                        tooltipContext: config.tooltipContext
                    }
                }
            ]
        });
        return new TooltipRef(getOverlay(config.element, this.overlay, false, config.placement), config.element, injector);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipService, decorators: [{
            type: Injectable
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiTooltipDirective {
    static idCounter = 0;
    /**
     * The tooltip text to be displayed
     *
     * @defaultValue ''
     */
    siTooltip = input('', ...(ngDevMode ? [{ debugName: "siTooltip" }] : []));
    /**
     * The placement of the tooltip. One of 'top', 'start', end', 'bottom'
     *
     * @defaultValue 'auto'
     */
    placement = input('auto', ...(ngDevMode ? [{ debugName: "placement" }] : []));
    /**
     * Allows the tooltip to be disabled
     *
     * @defaultValue false
     */
    isDisabled = input(false, { ...(ngDevMode ? { debugName: "isDisabled" } : {}), transform: booleanAttribute });
    /**
     * The context for the attached template
     */
    tooltipContext = input(...(ngDevMode ? [undefined, { debugName: "tooltipContext" }] : []));
    describedBy = `__tooltip_${SiTooltipDirective.idCounter++}`;
    tooltipRef;
    showTimeout;
    tooltipService = inject(SiTooltipService);
    elementRef = inject(ElementRef);
    isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
    ngOnDestroy() {
        this.clearShowTimeout();
        this.tooltipRef?.destroy();
    }
    clearShowTimeout() {
        if (this.showTimeout) {
            clearTimeout(this.showTimeout);
            this.showTimeout = undefined;
        }
    }
    showTooltip(immediate = false) {
        const siTooltip = this.siTooltip();
        if (this.isDisabled() || !siTooltip) {
            return;
        }
        this.clearShowTimeout();
        const delay = immediate ? 0 : 500;
        this.showTimeout = setTimeout(() => {
            this.tooltipRef ??= this.tooltipService.createTooltip({
                describedBy: this.describedBy,
                element: this.elementRef,
                placement: this.placement(),
                tooltip: this.siTooltip,
                tooltipContext: this.tooltipContext
            });
            this.tooltipRef.show();
        }, delay);
    }
    focusIn(event) {
        if (this.isBrowser && event.target.matches(':focus-visible')) {
            this.showTooltip(true);
        }
    }
    show() {
        this.showTooltip(false);
    }
    hide() {
        this.clearShowTimeout();
        this.tooltipRef?.hide();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.8", type: SiTooltipDirective, isStandalone: true, selector: "[siTooltip]", inputs: { siTooltip: { classPropertyName: "siTooltip", publicName: "siTooltip", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, tooltipContext: { classPropertyName: "tooltipContext", publicName: "tooltipContext", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "focus": "focusIn($event)", "mouseenter": "show()", "touchstart": "hide()", "focusout": "hide()", "mouseleave": "hide()" }, properties: { "attr.aria-describedby": "describedBy" } }, providers: [SiTooltipService], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siTooltip]',
                    providers: [SiTooltipService],
                    host: {
                        '[attr.aria-describedby]': 'describedBy',
                        '(focus)': 'focusIn($event)',
                        '(mouseenter)': 'show()',
                        '(touchstart)': 'hide()',
                        '(focusout)': 'hide()',
                        '(mouseleave)': 'hide()'
                    }
                }]
        }], propDecorators: { siTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "siTooltip", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], tooltipContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipContext", required: false }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiTooltipModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipModule, imports: [SiTooltipDirective], exports: [SiTooltipDirective] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiTooltipModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [SiTooltipDirective],
                    exports: [SiTooltipDirective]
                }]
        }] });

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

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

export { SiTooltipDirective, SiTooltipModule, SiTooltipService };
//# sourceMappingURL=siemens-element-ng-tooltip.mjs.map
