import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import * as i0 from '@angular/core';
import { input, viewChild, signal, computed, TemplateRef, inject, Injector, ElementRef, DOCUMENT, Component, output, HostListener, Directive } from '@angular/core';
import { calculateOverlayArrowPosition, getOverlay, getPositionStrategy } from '@siemens/element-ng/common';
import { Subject, takeUntil } from 'rxjs';
import { ConfigurableFocusTrapFactory } from '@angular/cdk/a11y';
import { NgTemplateOutlet } from '@angular/common';
import { SiIconComponent } from '@siemens/element-ng/icon';
import { SiTranslatePipe } from '@siemens/element-translate-ng/translate';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class PopoverComponent {
    popoverDirective = input.required(...(ngDevMode ? [{ debugName: "popoverDirective" }] : []));
    popoverWrapper = viewChild.required('popoverWrapper');
    /** @internal */
    labelledBy;
    /** @internal */
    describedBy;
    positionClass = signal('', ...(ngDevMode ? [{ debugName: "positionClass" }] : []));
    arrowPos = signal(undefined, ...(ngDevMode ? [{ debugName: "arrowPos" }] : []));
    description = computed(() => {
        const description = this.popoverDirective().siPopover();
        return !(description instanceof TemplateRef) ? description : undefined;
    }, ...(ngDevMode ? [{ debugName: "description" }] : []));
    popoverTemplate = null;
    injector = inject(Injector);
    elementRef = inject(ElementRef);
    focusTrapFactory = inject(ConfigurableFocusTrapFactory);
    focusTrap;
    previouslyActiveElement = inject(DOCUMENT).activeElement;
    ngOnInit() {
        const popoverDirective = this.popoverDirective();
        const popover = popoverDirective.siPopover();
        if (popover instanceof TemplateRef) {
            this.popoverTemplate = popover;
        }
        this.labelledBy = `__popover-title_${popoverDirective.popoverCounter}`;
        this.describedBy = `__popover-body_${popoverDirective.popoverCounter}`;
        this.applyFocus();
    }
    ngOnDestroy() {
        this.focusTrap?.destroy();
        if (this.previouslyActiveElement &&
            'focus' in this.previouslyActiveElement &&
            typeof this.previouslyActiveElement.focus === 'function') {
            this.previouslyActiveElement.focus();
        }
    }
    /** @internal */
    updateArrow(change, anchor) {
        const positionClass = `popover-${change.connectionPair.overlayX}-${change.connectionPair.overlayY}`;
        // need two updates as class changes affect the position
        this.positionClass.set(positionClass);
        const arrowPos = calculateOverlayArrowPosition(change, this.elementRef, anchor);
        this.arrowPos.set(arrowPos);
    }
    hide() {
        this.popoverDirective().hide();
    }
    applyFocus() {
        // Using setTimeout ensures that SR first read `expanded` before we move the focus.
        setTimeout(async () => {
            const popoverWrapperEl = this.popoverWrapper().nativeElement;
            this.focusTrap = this.focusTrapFactory.create(this.popoverWrapper().nativeElement);
            const moved = await this.focusTrap.focusFirstTabbableElementWhenReady();
            if (!moved) {
                popoverWrapperEl.tabIndex = 0;
                popoverWrapperEl.focus();
            }
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: PopoverComponent, isStandalone: true, selector: "si-popover", inputs: { popoverDirective: { classPropertyName: "popoverDirective", publicName: "popoverDirective", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "id": "this.popoverDirective().popoverId" } }, viewQueries: [{ propertyName: "popoverWrapper", first: true, predicate: ["popoverWrapper"], descendants: true, isSignal: true }], ngImport: i0, template: "@let popover = popoverDirective();\n<div\n  #popoverWrapper\n  role=\"dialog\"\n  [class]=\"[\n    'popover',\n    'position-relative',\n    'focus-inside',\n    positionClass(),\n    popover.containerClass()\n  ]\"\n  [attr.aria-labelledby]=\"labelledBy\"\n  [attr.aria-describedby]=\"describedBy\"\n  (keydown.escape)=\"hide()\"\n>\n  <div\n    class=\"popover-arrow\"\n    [style.left.px]=\"arrowPos()?.left\"\n    [style.right.px]=\"arrowPos()?.right\"\n  ></div>\n  @if (popover.title()) {\n    <div class=\"popover-header\">\n      @let iconValue = popover.icon();\n      @if (iconValue) {\n        <si-icon class=\"icon me-1\" [icon]=\"iconValue\" />\n      }\n      <span class=\"si-h5\" [id]=\"labelledBy\">{{ popover.title() | translate }}</span>\n    </div>\n  }\n  @if (!popoverTemplate) {\n    <div class=\"popover-body\">\n      <div class=\"si-body\" [id]=\"describedBy\">{{ description() | translate }}</div>\n    </div>\n  } @else {\n    <!-- If title is already provided, we wrap the template with the `popover-body` class\n    since the template may not be in the popover body directive. Also used by SiHelpButtonComponent -->\n    @if (popover.title()) {\n      <div class=\"popover-body\">\n        <ng-template\n          [ngTemplateOutlet]=\"popoverTemplate\"\n          [ngTemplateOutletContext]=\"popover.context()\"\n          [ngTemplateOutletInjector]=\"injector\"\n        />\n      </div>\n    } @else {\n      <ng-template\n        [ngTemplateOutlet]=\"popoverTemplate\"\n        [ngTemplateOutletContext]=\"popover.context()\"\n        [ngTemplateOutletInjector]=\"injector\"\n      />\n    }\n  }\n</div>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: PopoverComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-popover', imports: [NgTemplateOutlet, SiIconComponent, SiTranslatePipe], host: {
                        '[id]': 'this.popoverDirective().popoverId'
                    }, template: "@let popover = popoverDirective();\n<div\n  #popoverWrapper\n  role=\"dialog\"\n  [class]=\"[\n    'popover',\n    'position-relative',\n    'focus-inside',\n    positionClass(),\n    popover.containerClass()\n  ]\"\n  [attr.aria-labelledby]=\"labelledBy\"\n  [attr.aria-describedby]=\"describedBy\"\n  (keydown.escape)=\"hide()\"\n>\n  <div\n    class=\"popover-arrow\"\n    [style.left.px]=\"arrowPos()?.left\"\n    [style.right.px]=\"arrowPos()?.right\"\n  ></div>\n  @if (popover.title()) {\n    <div class=\"popover-header\">\n      @let iconValue = popover.icon();\n      @if (iconValue) {\n        <si-icon class=\"icon me-1\" [icon]=\"iconValue\" />\n      }\n      <span class=\"si-h5\" [id]=\"labelledBy\">{{ popover.title() | translate }}</span>\n    </div>\n  }\n  @if (!popoverTemplate) {\n    <div class=\"popover-body\">\n      <div class=\"si-body\" [id]=\"describedBy\">{{ description() | translate }}</div>\n    </div>\n  } @else {\n    <!-- If title is already provided, we wrap the template with the `popover-body` class\n    since the template may not be in the popover body directive. Also used by SiHelpButtonComponent -->\n    @if (popover.title()) {\n      <div class=\"popover-body\">\n        <ng-template\n          [ngTemplateOutlet]=\"popoverTemplate\"\n          [ngTemplateOutletContext]=\"popover.context()\"\n          [ngTemplateOutletInjector]=\"injector\"\n        />\n      </div>\n    } @else {\n      <ng-template\n        [ngTemplateOutlet]=\"popoverTemplate\"\n        [ngTemplateOutletContext]=\"popover.context()\"\n        [ngTemplateOutletInjector]=\"injector\"\n      />\n    }\n  }\n</div>\n" }]
        }], propDecorators: { popoverDirective: [{ type: i0.Input, args: [{ isSignal: true, alias: "popoverDirective", required: true }] }], popoverWrapper: [{ type: i0.ViewChild, args: ['popoverWrapper', { isSignal: true }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiPopoverDirective {
    static idCounter = 0;
    /**
     * The popover text to be displayed
     */
    siPopover = input(...(ngDevMode ? [undefined, { debugName: "siPopover" }] : []));
    /**
     * The placement of the popover. One of 'top', 'start', end', 'bottom'
     *
     * @defaultValue 'auto'
     */
    placement = input('auto', { ...(ngDevMode ? { debugName: "placement" } : {}), alias: 'siPopoverPlacement' });
    placementInternal = computed(() => {
        if (this.placement() !== 'top' &&
            this.placement() !== 'bottom' &&
            this.placement() !== 'start' &&
            this.placement() !== 'end') {
            return 'auto';
        }
        else {
            return this.placement();
        }
    }, ...(ngDevMode ? [{ debugName: "placementInternal" }] : []));
    /**
     * The title to be displayed on top for the popover
     *
     * @defaultValue undefined
     */
    title = input(undefined, { ...(ngDevMode ? { debugName: "title" } : {}), alias: 'siPopoverTitle' });
    /**
     * The class that will be applied to container of the popover
     *
     * @defaultValue ''
     */
    containerClass = input('', { ...(ngDevMode ? { debugName: "containerClass" } : {}), alias: 'siPopoverContainerClass' });
    /**
     * The icon to be displayed besides popover title
     *
     * @defaultValue undefined
     */
    icon = input(undefined, { ...(ngDevMode ? { debugName: "icon" } : {}), alias: 'siPopoverIcon' });
    /**
     * The context for the attached template
     *
     * @defaultValue undefined
     */
    context = input(undefined, { ...(ngDevMode ? { debugName: "context" } : {}), alias: 'siPopoverContext' });
    /**
     * Emits an event when the popover is shown/hidden
     */
    visibilityChange = output({ alias: 'siPopoverVisibilityChange' });
    /** @internal */
    popoverCounter = SiPopoverDirective.idCounter++;
    /** @internal */
    popoverId = `__popover_${this.popoverCounter}`;
    /** @internal */
    isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
    overlayref;
    overlay = inject(Overlay);
    elementRef = inject(ElementRef);
    destroyer = new Subject();
    ngOnDestroy() {
        this.overlayref?.dispose();
        this.destroyer.next();
        this.destroyer.complete();
    }
    /**
     * Displays popover and emits 'shown' event.
     */
    show() {
        if (this.overlayref?.hasAttached()) {
            return;
        }
        this.overlayref = getOverlay(this.elementRef, this.overlay, false, this.placementInternal());
        this.overlayref
            .outsidePointerEvents()
            .pipe(takeUntil(this.destroyer))
            .subscribe(({ target }) => {
            if (target !== this.elementRef.nativeElement) {
                this.hide();
            }
        });
        const popoverPortal = new ComponentPortal(PopoverComponent);
        const popoverRef = this.overlayref.attach(popoverPortal);
        popoverRef.setInput('popoverDirective', this);
        const positionStrategy = getPositionStrategy(this.overlayref);
        positionStrategy?.positionChanges
            .pipe(takeUntil(this.destroyer))
            .subscribe(change => popoverRef.instance.updateArrow(change, this.elementRef));
        this.isOpen.set(true);
        this.visibilityChange.emit();
    }
    /**
     * Hides the popover and emits 'hidden' event.
     */
    hide() {
        if (this.overlayref?.hasAttached()) {
            this.overlayref?.detach();
            this.isOpen.set(false);
            this.visibilityChange.emit();
            this.destroyer.next();
        }
    }
    /**
     * Updates the position of the popover based on the position strategy.
     */
    updatePosition() {
        this.overlayref?.updatePosition();
    }
    onClick() {
        if (this.overlayref?.hasAttached()) {
            this.hide();
        }
        else {
            this.show();
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiPopoverDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.8", type: SiPopoverDirective, isStandalone: true, selector: "[siPopover]", inputs: { siPopover: { classPropertyName: "siPopover", publicName: "siPopover", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "siPopoverPlacement", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "siPopoverTitle", isSignal: true, isRequired: false, transformFunction: null }, containerClass: { classPropertyName: "containerClass", publicName: "siPopoverContainerClass", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "siPopoverIcon", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "siPopoverContext", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visibilityChange: "siPopoverVisibilityChange" }, host: { listeners: { "click": "onClick()" }, properties: { "attr.aria-expanded": "isOpen()", "attr.aria-controls": "popoverId" } }, exportAs: ["si-popover"], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiPopoverDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siPopover]',
                    host: {
                        '[attr.aria-expanded]': 'isOpen()',
                        '[attr.aria-controls]': 'popoverId'
                    },
                    exportAs: 'si-popover'
                }]
        }], propDecorators: { siPopover: [{ type: i0.Input, args: [{ isSignal: true, alias: "siPopover", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "siPopoverPlacement", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "siPopoverTitle", required: false }] }], containerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "siPopoverContainerClass", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "siPopoverIcon", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "siPopoverContext", required: false }] }], visibilityChange: [{ type: i0.Output, args: ["siPopoverVisibilityChange"] }], onClick: [{
                type: HostListener,
                args: ['click']
            }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiPopoverTitleDirective {
    popover = inject(PopoverComponent);
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiPopoverTitleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.8", type: SiPopoverTitleDirective, isStandalone: true, selector: "si-popover-title", host: { properties: { "id": "this.popover.labelledBy" }, classAttribute: "popover-header" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiPopoverTitleDirective, decorators: [{
            type: Directive,
            args: [{
                    // eslint-disable-next-line @angular-eslint/directive-selector
                    selector: 'si-popover-title',
                    host: {
                        '[id]': 'this.popover.labelledBy',
                        'class': 'popover-header'
                    }
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiPopoverBodyDirective {
    popover = inject(PopoverComponent);
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiPopoverBodyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.8", type: SiPopoverBodyDirective, isStandalone: true, selector: "si-popover-body", host: { properties: { "id": "this.popover.describedBy" }, classAttribute: "popover-body d-block" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiPopoverBodyDirective, decorators: [{
            type: Directive,
            args: [{
                    // eslint-disable-next-line @angular-eslint/directive-selector
                    selector: 'si-popover-body',
                    host: {
                        '[id]': 'this.popover.describedBy',
                        'class': 'popover-body d-block'
                    }
                }]
        }] });

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

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

export { SiPopoverBodyDirective, SiPopoverDirective, SiPopoverTitleDirective };
//# sourceMappingURL=siemens-element-ng-popover.mjs.map
