import * as i0 from '@angular/core';
import { input, output, signal, TemplateRef, Component, inject, DestroyRef, NgZone, EnvironmentInjector, computed, Injectable, ElementRef, effect, Directive } from '@angular/core';
import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { combineLatest, fromEvent, debounceTime, Subject } from 'rxjs';
import * as i1 from '@angular/common';
import { CommonModule, NgStyle } from '@angular/common';
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FocusTrapFactory } from '@angular/cdk/a11y';
import * as i3 from '@ngx-translate/core';
import { TranslateModule } from '@ngx-translate/core';
import * as i2 from '@seniorsistemas/angular-components/button';
import { ButtonModule } from '@seniorsistemas/angular-components/button';
import { CheckboxComponent } from '@seniorsistemas/angular-components/checkbox';

/**
 * Componente de popover do Spotlight.
 *
 * Exibe o card de destaque com título, mensagem, seta direcional, contador de passos,
 * botões de navegação e, em modo simples (passo único), o checkbox "não mostrar novamente".
 *
 * Este componente é instanciado programaticamente pelo `SpotlightOverlayComponent`
 * via CDK Overlay. Normalmente não é usado diretamente no template.
 */
class SpotlightComponent {
    /** Título do popover. Aceita string ou `TemplateRef` para conteúdo dinâmico. */
    title = input('');
    /** Mensagem principal do popover. Aceita string ou `TemplateRef` para conteúdo dinâmico. */
    message = input();
    /** Template opcional para área de mídia/conteúdo customizado acima da mensagem. */
    content = input(null);
    /** Posição do popover em relação ao elemento alvo. @default 'bottom-center' */
    position = input('bottom-center');
    /** Número do passo atual (1-based) exibido no contador. @default 1 */
    currentStep = input(1);
    /** Total de passos do tour, usado no contador e para controle de botões. @default 1 */
    totalSteps = input(1);
    /**
     * Exibe o checkbox "não mostrar novamente" (apenas em passo único).
     * Passe `false` para suprimir o checkbox quando não for necessário persistir a preferência.
     * @default true
     */
    showDoNotShowAgain = input(true);
    /** Lista de botões de ação adicionais exibidos na área de rodapé. */
    actions = input([]);
    /**
     * Deslocamento em pixels para posicionar a seta manualmente no eixo principal.
     * Quando `null`, o alinhamento é controlado pela `position`. @default null
     */
    arrowOffsetPx = input(null);
    /** Emitido ao clicar no botão de fechar (X). */
    closed = output();
    /** Emitido ao clicar em "Próximo". */
    next = output();
    /** Emitido ao clicar em "Voltar". */
    previous = output();
    /** Emitido ao clicar em "Entendido" (modo simples, passo único). */
    understand = output();
    /** Estado atual do checkbox "não mostrar novamente". */
    isDoNotShowAgainChecked = signal(false);
    static instanceCount = 0;
    /** @internal */
    instanceId = `spotlight-${++SpotlightComponent.instanceCount}`;
    /** @internal */
    titleId = `${this.instanceId}-title`;
    /** @internal */
    descId = `${this.instanceId}-desc`;
    get titleTemplate() {
        const v = this.title();
        return v instanceof TemplateRef ? v : null;
    }
    get titleString() {
        const v = this.title();
        return v instanceof TemplateRef ? '' : (v ?? '');
    }
    get messageTemplate() {
        const v = this.message();
        return v instanceof TemplateRef ? v : null;
    }
    get messageString() {
        const v = this.message();
        return v instanceof TemplateRef ? '' : (v ?? '');
    }
    get arrowPosition() {
        const [direction] = this.position().split('-');
        const [, alignment] = this.position().split('-');
        const oppositeDirection = this.getOppositeDirection(direction);
        return `${oppositeDirection}-${alignment}`;
    }
    get isArrowTop() {
        return this.arrowPosition.startsWith('top-');
    }
    get isArrowBottom() {
        return this.arrowPosition.startsWith('bottom-');
    }
    get isArrowLeft() {
        return this.arrowPosition.startsWith('left-');
    }
    get isArrowRight() {
        return this.arrowPosition.startsWith('right-');
    }
    get arrowRotation() {
        const direction = this.arrowPosition.split('-')[0];
        switch (direction) {
            case 'top':
                return '';
            case 'bottom':
                return 'rotate-180';
            case 'left':
                return '-rotate-90';
            case 'right':
                return 'rotate-90';
            default:
                return '';
        }
    }
    get arrowAlignmentClass() {
        const offset = this.arrowOffsetPx();
        if (offset !== null) {
            return 'justify-start';
        }
        const alignment = this.arrowPosition.split('-')[1];
        if (this.isArrowTop || this.isArrowBottom) {
            switch (alignment) {
                case 'start':
                    return 'justify-start';
                case 'center':
                    return 'justify-center';
                case 'end':
                    return 'justify-end';
                default:
                    return '';
            }
        }
        else {
            switch (alignment) {
                case 'start':
                    return 'items-start justify-start';
                case 'center':
                    return 'items-center justify-center';
                case 'end':
                    return 'items-end justify-end';
                default:
                    return '';
            }
        }
    }
    get arrowPaddingStyle() {
        const offset = this.arrowOffsetPx();
        if (offset === null) {
            return {};
        }
        if (this.isArrowTop || this.isArrowBottom) {
            return { 'padding-left': `${offset}px`, 'padding-right': '0' };
        }
        return { 'padding-top': `${offset}px`, 'padding-bottom': '0' };
    }
    /** Emite o evento `closed`. Chamado pelo botão de fechar no template. */
    onClose() {
        this.closed.emit();
    }
    /** Emite o evento `next`. Chamado pelo botão "Próximo" no template. */
    onNext() {
        this.next.emit();
    }
    /** Emite o evento `previous`. Chamado pelo botão "Voltar" no template. */
    onPrevious() {
        this.previous.emit();
    }
    /** Emite o evento `understand`. Chamado pelo botão "Entendido" no template. */
    onUnderstand() {
        this.understand.emit();
    }
    /** Alterna o estado de `isDoNotShowAgainChecked`. */
    toggleDoNotShowAgain() {
        this.isDoNotShowAgainChecked.update((v) => !v);
    }
    getOppositeDirection(direction) {
        switch (direction) {
            case 'top':
                return 'bottom';
            case 'bottom':
                return 'top';
            case 'left':
                return 'right';
            case 'right':
                return 'left';
            default:
                return direction;
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SpotlightComponent, isStandalone: true, selector: "s-spotlight", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, currentStep: { classPropertyName: "currentStep", publicName: "currentStep", isSignal: true, isRequired: false, transformFunction: null }, totalSteps: { classPropertyName: "totalSteps", publicName: "totalSteps", isSignal: true, isRequired: false, transformFunction: null }, showDoNotShowAgain: { classPropertyName: "showDoNotShowAgain", publicName: "showDoNotShowAgain", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, arrowOffsetPx: { classPropertyName: "arrowOffsetPx", publicName: "arrowOffsetPx", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", next: "next", previous: "previous", understand: "understand" }, ngImport: i0, template: "<div\n    [attr.role]=\"totalSteps() > 1 ? 'dialog' : 'tooltip'\"\n    [attr.aria-modal]=\"totalSteps() > 1 ? 'true' : null\"\n    [attr.aria-labelledby]=\"titleId\"\n    [attr.aria-describedby]=\"descId\"\n    class=\"flex max-w-[342px]\"\n    [ngClass]=\"isArrowLeft || isArrowRight ? 'flex-row' : 'flex-col'\"\n>\n    @if (isArrowTop) {\n        <ng-container *ngTemplateOutlet=\"arrowTopTemplate\"></ng-container>\n    }\n\n    @if (isArrowLeft) {\n        <ng-container *ngTemplateOutlet=\"arrowLeftTemplate\"></ng-container>\n    }\n\n    <div\n        class=\"relative flex w-full flex-col overflow-hidden rounded-[4px] bg-grayscale-0\"\n        style=\"\n            box-shadow:\n                0 3px 5px rgba(0, 0, 0, 0.2),\n                0 1px 18px rgba(0, 0, 0, 0.12),\n                0 6px 10px rgba(0, 0, 0, 0.14);\n        \"\n    >\n        <!-- Regi\u00E3o aria-live para anuncia\u00E7\u00E3o de mudan\u00E7a de passo para leitores de tela -->\n        <span\n            class=\"sr-only\"\n            aria-live=\"polite\"\n            aria-atomic=\"true\"\n        >\n            @if (totalSteps() > 1) {\n                {{\n                    'platform.angular_components.step_progress'\n                        | translate: { current: currentStep(), total: totalSteps() }\n                }}\n            }\n        </span>\n        <div class=\"flex h-[40px] w-full items-center justify-between p-[12px]\">\n            <div class=\"flex min-w-0 flex-1 items-center gap-[8px]\">\n                <h2\n                    [id]=\"titleId\"\n                    class=\"flex-1 overflow-hidden overflow-ellipsis whitespace-nowrap font-open-sans text-[14px] font-bold leading-[1.5] text-grayscale-90\"\n                >\n                    @if (titleTemplate) {\n                        <ng-container *ngTemplateOutlet=\"titleTemplate\"></ng-container>\n                    } @else {\n                        {{ titleString }}\n                    }\n                </h2>\n            </div>\n            <button\n                (click)=\"onClose()\"\n                class=\"flex h-[16px] w-[16px] flex-none items-center justify-center text-grayscale-90 transition-colors hover:text-grayscale-100\"\n                [attr.aria-label]=\"'platform.angular_components.close' | translate\"\n            >\n                <i class=\"fas fa-times\"></i>\n            </button>\n        </div>\n\n        @if (content()) {\n            <ng-container *ngTemplateOutlet=\"content()\"></ng-container>\n        }\n\n        <div class=\"flex w-full flex-col items-start gap-[20px] bg-grayscale-0 p-[12px]\">\n            <div\n                [id]=\"descId\"\n                class=\"w-full whitespace-pre-wrap font-open-sans text-[14px] font-normal leading-[1.5] text-grayscale-90\"\n            >\n                @if (messageTemplate) {\n                    <ng-container *ngTemplateOutlet=\"messageTemplate\"></ng-container>\n                } @else {\n                    {{ messageString }}\n                }\n            </div>\n\n            <div class=\"flex w-full flex-wrap gap-3\">\n                @if (totalSteps() > 1) {\n                    <p class=\"font-open-sans text-[14px] font-normal leading-[1.5] text-grayscale-90\">\n                        {{\n                            'platform.angular_components.step_counter'\n                                | translate: { current: currentStep(), total: totalSteps() }\n                        }}\n                    </p>\n                }\n\n                @if (totalSteps() === 1 && showDoNotShowAgain()) {\n                    <s-checkbox\n                        [checked]=\"isDoNotShowAgainChecked()\"\n                        (checkedChange)=\"toggleDoNotShowAgain()\"\n                        [label]=\"'platform.angular_components.dont_show_again' | translate\"\n                    ></s-checkbox>\n                }\n\n                <div\n                    class=\"flex flex-wrap items-start justify-end gap-[8px]\"\n                    [ngClass]=\"totalSteps() > 1 ? 'w-full' : ''\"\n                >\n                    @for (action of actions(); track action.label) {\n                        <s-button\n                            [label]=\"action.label\"\n                            (clicked)=\"action.handler()\"\n                            priority=\"default\"\n                            size=\"small\"\n                            class=\"flex-none\"\n                        ></s-button>\n                    }\n\n                    @if (totalSteps() > 1 && currentStep() > 1) {\n                        <s-button\n                            [label]=\"'platform.angular_components.back' | translate\"\n                            (clicked)=\"onPrevious()\"\n                            priority=\"default\"\n                            size=\"small\"\n                            class=\"flex-none\"\n                        ></s-button>\n                    }\n\n                    <s-button\n                        [label]=\"\n                            totalSteps() <= 1\n                                ? ('platform.angular_components.understood' | translate)\n                                : currentStep() < totalSteps()\n                                  ? ('platform.angular_components.next' | translate)\n                                  : ('platform.angular_components.complete' | translate)\n                        \"\n                        (clicked)=\"totalSteps() > 1 ? onNext() : onUnderstand()\"\n                        priority=\"secondary\"\n                        size=\"small\"\n                        class=\"flex-none\"\n                    ></s-button>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    @if (isArrowBottom) {\n        <ng-container *ngTemplateOutlet=\"arrowBottomTemplate\"></ng-container>\n    }\n\n    @if (isArrowRight) {\n        <ng-container *ngTemplateOutlet=\"arrowRightTemplate\"></ng-container>\n    }\n</div>\n\n<!-- Arrow Templates -->\n<ng-template #arrowTopTemplate>\n    <div\n        class=\"relative z-10 flex h-[8px] w-full px-[12px] py-0\"\n        [ngClass]=\"arrowAlignmentClass\"\n        [ngStyle]=\"arrowPaddingStyle\"\n    >\n        <svg\n            width=\"16\"\n            height=\"8\"\n            viewBox=\"0 0 16 8\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            class=\"text-grayscale-0\"\n            [ngClass]=\"arrowRotation\"\n        >\n            <path\n                d=\"M0 8L8 0L16 8\"\n                fill=\"currentColor\"\n            />\n        </svg>\n    </div>\n</ng-template>\n\n<ng-template #arrowBottomTemplate>\n    <div\n        class=\"relative z-10 flex h-[8px] w-full px-[12px] py-0\"\n        [ngClass]=\"arrowAlignmentClass\"\n        [ngStyle]=\"arrowPaddingStyle\"\n    >\n        <svg\n            width=\"16\"\n            height=\"8\"\n            viewBox=\"0 0 16 8\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            class=\"text-grayscale-0\"\n            [ngClass]=\"arrowRotation\"\n        >\n            <path\n                d=\"M0 8L8 0L16 8\"\n                fill=\"currentColor\"\n            />\n        </svg>\n    </div>\n</ng-template>\n\n<ng-template #arrowLeftTemplate>\n    <div\n        class=\"relative z-10 flex w-[8px] flex-col items-center self-stretch px-0\"\n        [ngClass]=\"arrowAlignmentClass\"\n        [ngStyle]=\"arrowPaddingStyle\"\n    >\n        <svg\n            width=\"16\"\n            height=\"8\"\n            viewBox=\"0 0 16 8\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            class=\"text-grayscale-0\"\n            [ngClass]=\"arrowRotation\"\n        >\n            <path\n                d=\"M0 8L8 0L16 8\"\n                fill=\"currentColor\"\n            />\n        </svg>\n    </div>\n</ng-template>\n\n<ng-template #arrowRightTemplate>\n    <div\n        class=\"relative z-10 flex w-[8px] flex-col items-center self-stretch px-0\"\n        [ngClass]=\"arrowAlignmentClass\"\n        [ngStyle]=\"arrowPaddingStyle\"\n    >\n        <svg\n            width=\"16\"\n            height=\"8\"\n            viewBox=\"0 0 16 8\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            class=\"text-grayscale-0\"\n            [ngClass]=\"arrowRotation\"\n        >\n            <path\n                d=\"M0 8L8 0L16 8\"\n                fill=\"currentColor\"\n            />\n        </svg>\n    </div>\n</ng-template>\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "s-button", inputs: ["id", "label", "tooltip", "tooltipPosition", "iconClass", "rightIconClass", "caret", "styleClass", "baseZIndex", "disabled", "auxiliary", "type", "priority", "menuOptions", "size", "slide", "animation", "badge", "iconColor", "menuAriaLabel", "ariaLabel"], outputs: ["clicked"] }, { kind: "component", type: CheckboxComponent, selector: "s-checkbox", inputs: ["disabled", "checked", "indeterminate", "label", "ariaLabel", "ariaLabelledBy"], outputs: ["disabledChange", "checkedChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightComponent, decorators: [{
            type: Component,
            args: [{ selector: 's-spotlight', standalone: true, imports: [CommonModule, ButtonModule, CheckboxComponent, TranslateModule], template: "<div\n    [attr.role]=\"totalSteps() > 1 ? 'dialog' : 'tooltip'\"\n    [attr.aria-modal]=\"totalSteps() > 1 ? 'true' : null\"\n    [attr.aria-labelledby]=\"titleId\"\n    [attr.aria-describedby]=\"descId\"\n    class=\"flex max-w-[342px]\"\n    [ngClass]=\"isArrowLeft || isArrowRight ? 'flex-row' : 'flex-col'\"\n>\n    @if (isArrowTop) {\n        <ng-container *ngTemplateOutlet=\"arrowTopTemplate\"></ng-container>\n    }\n\n    @if (isArrowLeft) {\n        <ng-container *ngTemplateOutlet=\"arrowLeftTemplate\"></ng-container>\n    }\n\n    <div\n        class=\"relative flex w-full flex-col overflow-hidden rounded-[4px] bg-grayscale-0\"\n        style=\"\n            box-shadow:\n                0 3px 5px rgba(0, 0, 0, 0.2),\n                0 1px 18px rgba(0, 0, 0, 0.12),\n                0 6px 10px rgba(0, 0, 0, 0.14);\n        \"\n    >\n        <!-- Regi\u00E3o aria-live para anuncia\u00E7\u00E3o de mudan\u00E7a de passo para leitores de tela -->\n        <span\n            class=\"sr-only\"\n            aria-live=\"polite\"\n            aria-atomic=\"true\"\n        >\n            @if (totalSteps() > 1) {\n                {{\n                    'platform.angular_components.step_progress'\n                        | translate: { current: currentStep(), total: totalSteps() }\n                }}\n            }\n        </span>\n        <div class=\"flex h-[40px] w-full items-center justify-between p-[12px]\">\n            <div class=\"flex min-w-0 flex-1 items-center gap-[8px]\">\n                <h2\n                    [id]=\"titleId\"\n                    class=\"flex-1 overflow-hidden overflow-ellipsis whitespace-nowrap font-open-sans text-[14px] font-bold leading-[1.5] text-grayscale-90\"\n                >\n                    @if (titleTemplate) {\n                        <ng-container *ngTemplateOutlet=\"titleTemplate\"></ng-container>\n                    } @else {\n                        {{ titleString }}\n                    }\n                </h2>\n            </div>\n            <button\n                (click)=\"onClose()\"\n                class=\"flex h-[16px] w-[16px] flex-none items-center justify-center text-grayscale-90 transition-colors hover:text-grayscale-100\"\n                [attr.aria-label]=\"'platform.angular_components.close' | translate\"\n            >\n                <i class=\"fas fa-times\"></i>\n            </button>\n        </div>\n\n        @if (content()) {\n            <ng-container *ngTemplateOutlet=\"content()\"></ng-container>\n        }\n\n        <div class=\"flex w-full flex-col items-start gap-[20px] bg-grayscale-0 p-[12px]\">\n            <div\n                [id]=\"descId\"\n                class=\"w-full whitespace-pre-wrap font-open-sans text-[14px] font-normal leading-[1.5] text-grayscale-90\"\n            >\n                @if (messageTemplate) {\n                    <ng-container *ngTemplateOutlet=\"messageTemplate\"></ng-container>\n                } @else {\n                    {{ messageString }}\n                }\n            </div>\n\n            <div class=\"flex w-full flex-wrap gap-3\">\n                @if (totalSteps() > 1) {\n                    <p class=\"font-open-sans text-[14px] font-normal leading-[1.5] text-grayscale-90\">\n                        {{\n                            'platform.angular_components.step_counter'\n                                | translate: { current: currentStep(), total: totalSteps() }\n                        }}\n                    </p>\n                }\n\n                @if (totalSteps() === 1 && showDoNotShowAgain()) {\n                    <s-checkbox\n                        [checked]=\"isDoNotShowAgainChecked()\"\n                        (checkedChange)=\"toggleDoNotShowAgain()\"\n                        [label]=\"'platform.angular_components.dont_show_again' | translate\"\n                    ></s-checkbox>\n                }\n\n                <div\n                    class=\"flex flex-wrap items-start justify-end gap-[8px]\"\n                    [ngClass]=\"totalSteps() > 1 ? 'w-full' : ''\"\n                >\n                    @for (action of actions(); track action.label) {\n                        <s-button\n                            [label]=\"action.label\"\n                            (clicked)=\"action.handler()\"\n                            priority=\"default\"\n                            size=\"small\"\n                            class=\"flex-none\"\n                        ></s-button>\n                    }\n\n                    @if (totalSteps() > 1 && currentStep() > 1) {\n                        <s-button\n                            [label]=\"'platform.angular_components.back' | translate\"\n                            (clicked)=\"onPrevious()\"\n                            priority=\"default\"\n                            size=\"small\"\n                            class=\"flex-none\"\n                        ></s-button>\n                    }\n\n                    <s-button\n                        [label]=\"\n                            totalSteps() <= 1\n                                ? ('platform.angular_components.understood' | translate)\n                                : currentStep() < totalSteps()\n                                  ? ('platform.angular_components.next' | translate)\n                                  : ('platform.angular_components.complete' | translate)\n                        \"\n                        (clicked)=\"totalSteps() > 1 ? onNext() : onUnderstand()\"\n                        priority=\"secondary\"\n                        size=\"small\"\n                        class=\"flex-none\"\n                    ></s-button>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    @if (isArrowBottom) {\n        <ng-container *ngTemplateOutlet=\"arrowBottomTemplate\"></ng-container>\n    }\n\n    @if (isArrowRight) {\n        <ng-container *ngTemplateOutlet=\"arrowRightTemplate\"></ng-container>\n    }\n</div>\n\n<!-- Arrow Templates -->\n<ng-template #arrowTopTemplate>\n    <div\n        class=\"relative z-10 flex h-[8px] w-full px-[12px] py-0\"\n        [ngClass]=\"arrowAlignmentClass\"\n        [ngStyle]=\"arrowPaddingStyle\"\n    >\n        <svg\n            width=\"16\"\n            height=\"8\"\n            viewBox=\"0 0 16 8\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            class=\"text-grayscale-0\"\n            [ngClass]=\"arrowRotation\"\n        >\n            <path\n                d=\"M0 8L8 0L16 8\"\n                fill=\"currentColor\"\n            />\n        </svg>\n    </div>\n</ng-template>\n\n<ng-template #arrowBottomTemplate>\n    <div\n        class=\"relative z-10 flex h-[8px] w-full px-[12px] py-0\"\n        [ngClass]=\"arrowAlignmentClass\"\n        [ngStyle]=\"arrowPaddingStyle\"\n    >\n        <svg\n            width=\"16\"\n            height=\"8\"\n            viewBox=\"0 0 16 8\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            class=\"text-grayscale-0\"\n            [ngClass]=\"arrowRotation\"\n        >\n            <path\n                d=\"M0 8L8 0L16 8\"\n                fill=\"currentColor\"\n            />\n        </svg>\n    </div>\n</ng-template>\n\n<ng-template #arrowLeftTemplate>\n    <div\n        class=\"relative z-10 flex w-[8px] flex-col items-center self-stretch px-0\"\n        [ngClass]=\"arrowAlignmentClass\"\n        [ngStyle]=\"arrowPaddingStyle\"\n    >\n        <svg\n            width=\"16\"\n            height=\"8\"\n            viewBox=\"0 0 16 8\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            class=\"text-grayscale-0\"\n            [ngClass]=\"arrowRotation\"\n        >\n            <path\n                d=\"M0 8L8 0L16 8\"\n                fill=\"currentColor\"\n            />\n        </svg>\n    </div>\n</ng-template>\n\n<ng-template #arrowRightTemplate>\n    <div\n        class=\"relative z-10 flex w-[8px] flex-col items-center self-stretch px-0\"\n        [ngClass]=\"arrowAlignmentClass\"\n        [ngStyle]=\"arrowPaddingStyle\"\n    >\n        <svg\n            width=\"16\"\n            height=\"8\"\n            viewBox=\"0 0 16 8\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            class=\"text-grayscale-0\"\n            [ngClass]=\"arrowRotation\"\n        >\n            <path\n                d=\"M0 8L8 0L16 8\"\n                fill=\"currentColor\"\n            />\n        </svg>\n    </div>\n</ng-template>\n\n" }]
        }] });

const POPOVER_WIDTH = 342;
const SPOTLIGHT_PADDING = 8;
const ARROW_HALF_SIZE = 8;
const ARROW_OFFSET_MIN = 4;
const ARROW_OFFSET_MAX = POPOVER_WIDTH - 4 - 16;
const MASK_BG = 'rgba(0,0,0,0.5)';
const MASK_TRANSITION = 'all 0.2s ease';
const OVERLAY_Z = '10000';
const POPOVER_Z = '10001';
function toConnectedPositions(position) {
    const [direction, alignment] = position.split('-');
    const p = SPOTLIGHT_PADDING + 2;
    const hAlign = alignment;
    const vAlignMap = { start: 'top', center: 'center', end: 'bottom' };
    const vAlign = vAlignMap[alignment] ?? 'center';
    let primary;
    let opposite;
    switch (direction) {
        case 'top':
            primary = { originX: hAlign, originY: 'top', overlayX: hAlign, overlayY: 'bottom', offsetY: -p };
            opposite = { originX: hAlign, originY: 'bottom', overlayX: hAlign, overlayY: 'top', offsetY: p };
            break;
        case 'right':
            primary = { originX: 'end', originY: vAlign, overlayX: 'start', overlayY: vAlign, offsetX: p };
            opposite = { originX: 'start', originY: vAlign, overlayX: 'end', overlayY: vAlign, offsetX: -p };
            break;
        case 'left':
            primary = { originX: 'start', originY: vAlign, overlayX: 'end', overlayY: vAlign, offsetX: -p };
            opposite = { originX: 'end', originY: vAlign, overlayX: 'start', overlayY: vAlign, offsetX: p };
            break;
        default: // 'bottom'
            primary = { originX: hAlign, originY: 'bottom', overlayX: hAlign, overlayY: 'top', offsetY: p };
            opposite = { originX: hAlign, originY: 'top', overlayX: hAlign, overlayY: 'bottom', offsetY: -p };
    }
    return [
        primary,
        opposite,
        { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: p },
        { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -p },
        { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: p },
        { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -p },
    ];
}
class SpotlightOverlayComponent {
    tourService = inject(SpotlightTourService);
    destroyRef = inject(DestroyRef);
    zone = inject(NgZone);
    cdkOverlay = inject(Overlay);
    environmentInjector = inject(EnvironmentInjector);
    focusTrapFactory = inject(FocusTrapFactory);
    /** @internal */
    isActive = this.tourService.isActive;
    /** @internal */
    currentStep = this.tourService.currentStep;
    /** @internal */
    currentIndex = this.tourService.currentIndex;
    /** @internal */
    totalSteps = this.tourService.totalSteps;
    /** @internal*/
    targetRect = signal(null);
    /** @internal */
    topMaskStyle = computed(() => {
        const rect = this.targetRect();
        const base = {
            position: 'fixed',
            'z-index': OVERLAY_Z,
            background: MASK_BG,
            transition: MASK_TRANSITION,
            cursor: 'default',
        };
        if (!rect) {
            return { ...base, top: '0', left: '0', right: '0', bottom: '0' };
        }
        const top = Math.max(0, rect.top - SPOTLIGHT_PADDING);
        return { ...base, top: '0', left: '0', right: '0', height: `${top}px` };
    });
    /** @internal */
    leftMaskStyle = computed(() => {
        const rect = this.targetRect();
        if (!rect) {
            return {};
        }
        const p = SPOTLIGHT_PADDING;
        const top = Math.max(0, rect.top - p);
        const bottom = Math.min(window.innerHeight, rect.bottom + p);
        const left = Math.max(0, rect.left - p);
        return {
            position: 'fixed',
            'z-index': OVERLAY_Z,
            background: MASK_BG,
            transition: MASK_TRANSITION,
            cursor: 'default',
            top: `${top}px`,
            left: '0',
            width: `${left}px`,
            height: `${bottom - top}px`,
        };
    });
    /** @internal */
    rightMaskStyle = computed(() => {
        const rect = this.targetRect();
        if (!rect) {
            return {};
        }
        const p = SPOTLIGHT_PADDING;
        const top = Math.max(0, rect.top - p);
        const bottom = Math.min(window.innerHeight, rect.bottom + p);
        const right = Math.min(window.innerWidth, rect.right + p);
        return {
            position: 'fixed',
            'z-index': OVERLAY_Z,
            background: MASK_BG,
            transition: MASK_TRANSITION,
            cursor: 'default',
            top: `${top}px`,
            left: `${right}px`,
            right: '0',
            height: `${bottom - top}px`,
        };
    });
    /** @internal */
    bottomMaskStyle = computed(() => {
        const rect = this.targetRect();
        if (!rect) {
            return {};
        }
        const p = SPOTLIGHT_PADDING;
        const bottom = Math.min(window.innerHeight, rect.bottom + p);
        return {
            position: 'fixed',
            'z-index': OVERLAY_Z,
            background: MASK_BG,
            transition: MASK_TRANSITION,
            cursor: 'default',
            top: `${bottom}px`,
            left: '0',
            right: '0',
            bottom: '0',
        };
    });
    /** @internal */
    transparentBlockerStyle = computed(() => ({
        position: 'fixed',
        top: '0',
        left: '0',
        right: '0',
        bottom: '0',
        'z-index': OVERLAY_Z,
        cursor: 'default',
    }));
    resizeObserver = null;
    popoverOverlayRef = null;
    popoverComponentRef = null;
    popoverSubs = [];
    focusTrap = null;
    previouslyFocusedElement = null;
    constructor() {
        combineLatest([
            toObservable(this.currentStep),
            toObservable(this.isActive),
            toObservable(this.tourService.registrationVersion),
        ])
            .pipe(takeUntilDestroyed(this.destroyRef))
            .subscribe(([step, active]) => {
            this.disconnectResizeObserver();
            if (!step || !active) {
                this.targetRect.set(null);
                this.destroyPopoverOverlay();
                return;
            }
            const el = this.tourService.getElement(step.stepId);
            if (el?.nativeElement) {
                el.nativeElement.scrollIntoView({ block: 'nearest' });
                const target = el.nativeElement;
                this.zone.runOutsideAngular(() => {
                    requestAnimationFrame(() => {
                        this.zone.run(() => {
                            if (!this.isActive()) {
                                return;
                            }
                            this.updateTargetRect(target);
                            this.observeElement(target);
                            this.updatePopoverOverlay(target, step);
                        });
                    });
                });
            }
            else {
                this.targetRect.set(null);
                this.updatePopoverOverlay(null, step);
            }
        });
    }
    ngOnInit() {
        this.zone.runOutsideAngular(() => {
            const scrollOpts = { capture: true, passive: true };
            fromEvent(document, 'scroll', scrollOpts)
                .pipe(debounceTime(16), takeUntilDestroyed(this.destroyRef))
                .subscribe(() => this.zone.run(() => {
                this.refreshRect();
                this.popoverOverlayRef?.updatePosition();
                this.scheduleSync();
            }));
            fromEvent(window, 'resize', { passive: true })
                .pipe(debounceTime(16), takeUntilDestroyed(this.destroyRef))
                .subscribe(() => this.zone.run(() => {
                this.refreshRect();
                this.popoverOverlayRef?.updatePosition();
                this.scheduleSync();
            }));
            fromEvent(document, 'keydown')
                .pipe(takeUntilDestroyed(this.destroyRef))
                .subscribe((event) => {
                if (event.key === 'Escape') {
                    this.zone.run(() => this.onDismiss());
                }
            });
        });
    }
    ngOnDestroy() {
        this.destroyPopoverOverlay();
    }
    /** @internal */
    onNext() {
        this.tourService.next();
    }
    /** @internal */
    onPrevious() {
        this.tourService.previous();
    }
    /** @internal */
    onClose() {
        this.tourService.stop();
    }
    /** @internal */
    onDismiss() {
        const step = this.currentStep();
        if (!step || step.dismissible === false) {
            return;
        }
        this.tourService.stop({
            reason: this.totalSteps() === 1 ? 'dismissed' : 'interrupted',
            doNotShowAgain: false,
        });
    }
    updatePopoverOverlay(targetEl, step) {
        const strategy = targetEl
            ? this.cdkOverlay
                .position()
                .flexibleConnectedTo(targetEl)
                .withPositions(toConnectedPositions(step.position ?? 'bottom-center'))
                .withFlexibleDimensions(false)
                .withPush(true)
                .withViewportMargin(8)
            : this.cdkOverlay.position().global().centerHorizontally().centerVertically();
        if (!this.popoverOverlayRef) {
            this.popoverOverlayRef = this.cdkOverlay.create({
                hasBackdrop: false,
                scrollStrategy: targetEl
                    ? this.cdkOverlay.scrollStrategies.reposition()
                    : this.cdkOverlay.scrollStrategies.noop(),
                positionStrategy: strategy,
                width: POPOVER_WIDTH,
            });
            this.setPopoverZIndex();
            this.attachPopoverPortal(step);
        }
        else {
            this.popoverOverlayRef.updatePositionStrategy(strategy);
            this.popoverOverlayRef.updatePosition();
            this.updatePopoverInputs(step);
            if (targetEl) {
                this.scheduleSync();
            }
            this.scheduleFocusTrapRefocus();
        }
    }
    setPopoverZIndex() {
        if (!this.popoverOverlayRef) {
            return;
        }
        this.popoverOverlayRef.overlayElement.style.zIndex = POPOVER_Z;
        const host = this.popoverOverlayRef.hostElement;
        if (host !== this.popoverOverlayRef.overlayElement) {
            host.style.zIndex = POPOVER_Z;
        }
    }
    attachPopoverPortal(step) {
        this.previouslyFocusedElement = document.activeElement;
        const portal = new ComponentPortal(SpotlightComponent, null, this.environmentInjector);
        this.popoverComponentRef = this.popoverOverlayRef.attach(portal);
        this.updatePopoverInputs(step);
        this.scheduleSync();
        if (this.totalSteps() > 1) {
            this.activateTourMode();
        }
        this.popoverSubs.push(this.popoverComponentRef.instance.next.subscribe(() => {
            const doNotShowAgain = this.popoverComponentRef?.instance.isDoNotShowAgainChecked() ?? false;
            this.tourService.next(doNotShowAgain);
        }), this.popoverComponentRef.instance.previous.subscribe(() => this.tourService.previous()), this.popoverComponentRef.instance.closed.subscribe(() => this.tourService.stop({
            reason: this.totalSteps() === 1 ? 'dismissed' : 'interrupted',
            doNotShowAgain: false,
        })), this.popoverComponentRef.instance.understand.subscribe(() => {
            const doNotShowAgain = this.popoverComponentRef?.instance.isDoNotShowAgainChecked() ?? false;
            this.tourService.stop({ reason: 'completed', doNotShowAgain });
        }));
    }
    updatePopoverInputs(step) {
        const ref = this.popoverComponentRef;
        if (!ref) {
            return;
        }
        ref.setInput('title', step.title);
        ref.setInput('message', step.message);
        ref.setInput('position', step.position ?? 'bottom-center');
        ref.setInput('currentStep', this.currentIndex() + 1);
        ref.setInput('totalSteps', this.totalSteps());
        ref.setInput('content', step.content ?? null);
        ref.setInput('actions', step.actions ?? []);
        ref.setInput('showDoNotShowAgain', step.showDoNotShowAgain ?? true);
        ref.setInput('arrowOffsetPx', null);
    }
    scheduleSync() {
        this.zone.runOutsideAngular(() => {
            requestAnimationFrame(() => this.zone.run(() => this.syncDirectionAndArrow()));
        });
    }
    activateTourMode() {
        document.body.style.overflow = 'hidden';
        this.zone.runOutsideAngular(() => {
            requestAnimationFrame(() => {
                this.zone.run(() => {
                    const paneEl = this.popoverOverlayRef?.overlayElement;
                    if (paneEl) {
                        this.focusTrap = this.focusTrapFactory.create(paneEl);
                        this.focusTrap.focusInitialElementWhenReady();
                    }
                });
            });
        });
    }
    /**
     * After a step change, moves focus back to the first tabbable element inside the
     * popover so the user does not lose keyboard position.
     * No-op when there is no active focus trap (simple spotlight mode).
     */
    scheduleFocusTrapRefocus() {
        if (!this.focusTrap)
            return;
        this.zone.runOutsideAngular(() => {
            requestAnimationFrame(() => {
                this.zone.run(() => this.focusTrap?.focusFirstTabbableElement());
            });
        });
    }
    syncDirectionAndArrow() {
        const ref = this.popoverComponentRef;
        const paneEl = this.popoverOverlayRef?.overlayElement;
        const rect = this.targetRect();
        if (!ref || !paneEl || !rect) {
            ref?.setInput('arrowOffsetPx', null);
            return;
        }
        const pane = paneEl.getBoundingClientRect();
        const tol = SPOTLIGHT_PADDING + 4;
        let dir;
        if (pane.top >= rect.bottom - tol) {
            dir = 'bottom';
        }
        else if (pane.bottom <= rect.top + tol) {
            dir = 'top';
        }
        else if (pane.left >= rect.right - tol) {
            dir = 'right';
        }
        else if (pane.right <= rect.left + tol) {
            dir = 'left';
        }
        else {
            const dy = Math.abs(pane.top + pane.height / 2 - (rect.top + rect.height / 2));
            const dx = Math.abs(pane.left + pane.width / 2 - (rect.left + rect.width / 2));
            dir =
                dy >= dx
                    ? pane.top + pane.height / 2 < rect.top + rect.height / 2
                        ? 'top'
                        : 'bottom'
                    : pane.left + pane.width / 2 < rect.left + rect.width / 2
                        ? 'left'
                        : 'right';
        }
        const requestedAlignment = (this.currentStep()?.position ?? 'bottom-center').split('-')[1];
        ref.setInput('position', `${dir}-${requestedAlignment}`);
        const ARROW_MARGIN = 12;
        let offset;
        if (requestedAlignment === 'start') {
            offset = ARROW_MARGIN;
        }
        else if (requestedAlignment === 'end') {
            const isVerticalArrow = dir === 'left' || dir === 'right';
            // SVG height in flex-col layout = 8px; SVG width in flex-row layout = 16px
            offset = isVerticalArrow ? pane.height - ARROW_MARGIN - 8 : pane.width - ARROW_MARGIN - 16;
        }
        else {
            const tgtX = rect.left + rect.width / 2;
            const tgtY = rect.top + rect.height / 2;
            const rawOffset = dir === 'top' || dir === 'bottom'
                ? tgtX - pane.left - ARROW_HALF_SIZE
                : tgtY - pane.top - ARROW_HALF_SIZE;
            offset = Math.max(ARROW_OFFSET_MIN, Math.min(ARROW_OFFSET_MAX, rawOffset));
        }
        ref.setInput('arrowOffsetPx', offset);
    }
    destroyPopoverOverlay() {
        this.popoverSubs.forEach((s) => s.unsubscribe());
        this.popoverSubs = [];
        this.popoverComponentRef = null;
        if (this.focusTrap) {
            this.focusTrap.destroy();
            this.focusTrap = null;
        }
        document.body.style.overflow = '';
        if (this.previouslyFocusedElement) {
            this.previouslyFocusedElement.focus();
            this.previouslyFocusedElement = null;
        }
        if (this.popoverOverlayRef) {
            this.popoverOverlayRef.detach();
            this.popoverOverlayRef.dispose();
            this.popoverOverlayRef = null;
        }
    }
    updateTargetRect(el) {
        this.targetRect.set(el.getBoundingClientRect());
    }
    refreshRect() {
        const step = this.currentStep();
        if (!step || !this.isActive()) {
            return;
        }
        const el = this.tourService.getElement(step.stepId);
        if (el?.nativeElement) {
            this.updateTargetRect(el.nativeElement);
        }
    }
    observeElement(el) {
        this.resizeObserver = new ResizeObserver(() => {
            this.zone.run(() => this.updateTargetRect(el));
        });
        this.resizeObserver.observe(el);
    }
    disconnectResizeObserver() {
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
            this.resizeObserver = null;
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SpotlightOverlayComponent, isStandalone: true, selector: "s-spotlight-overlay", ngImport: i0, template: "@if (isActive() && currentStep(); as step) {\n    @if (step.showBackdrop !== false) {\n        <div\n            [ngStyle]=\"topMaskStyle()\"\n            (click)=\"onDismiss()\"\n        ></div>\n\n        @if (targetRect()) {\n            <div\n                [ngStyle]=\"leftMaskStyle()\"\n                (click)=\"onDismiss()\"\n            ></div>\n            <div\n                [ngStyle]=\"rightMaskStyle()\"\n                (click)=\"onDismiss()\"\n            ></div>\n            <div\n                [ngStyle]=\"bottomMaskStyle()\"\n                (click)=\"onDismiss()\"\n            ></div>\n        }\n    }\n\n    @if (step.showBackdrop === false) {\n        @if (step.dismissible === false) {\n            <div [ngStyle]=\"transparentBlockerStyle()\"></div>\n        } @else {\n            <div\n                [ngStyle]=\"transparentBlockerStyle()\"\n                (click)=\"onDismiss()\"\n            ></div>\n        }\n    }\n}\n\n", dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightOverlayComponent, decorators: [{
            type: Component,
            args: [{ selector: 's-spotlight-overlay', standalone: true, imports: [NgStyle], template: "@if (isActive() && currentStep(); as step) {\n    @if (step.showBackdrop !== false) {\n        <div\n            [ngStyle]=\"topMaskStyle()\"\n            (click)=\"onDismiss()\"\n        ></div>\n\n        @if (targetRect()) {\n            <div\n                [ngStyle]=\"leftMaskStyle()\"\n                (click)=\"onDismiss()\"\n            ></div>\n            <div\n                [ngStyle]=\"rightMaskStyle()\"\n                (click)=\"onDismiss()\"\n            ></div>\n            <div\n                [ngStyle]=\"bottomMaskStyle()\"\n                (click)=\"onDismiss()\"\n            ></div>\n        }\n    }\n\n    @if (step.showBackdrop === false) {\n        @if (step.dismissible === false) {\n            <div [ngStyle]=\"transparentBlockerStyle()\"></div>\n        } @else {\n            <div\n                [ngStyle]=\"transparentBlockerStyle()\"\n                (click)=\"onDismiss()\"\n            ></div>\n        }\n    }\n}\n\n" }]
        }], ctorParameters: () => [] });

/**
 * Serviço central do Spotlight Tour.
 *
 * Gerencia o estado do tour (passos, índice atual, ativo/inativo), a navegação entre
 * passos e o registro de elementos do DOM associados a cada `stepId`.
 *
 * Use `start()` para iniciar um tour com múltiplos passos ou `spotlight()` para
 * exibir um destaque simples em um único elemento.
 *
 * @example
 * ```typescript
 * // Tour com múltiplos passos
 * this.tourService.start([
 *   { stepId: 'passo-1', title: 'Título', message: 'Mensagem' },
 *   { stepId: 'passo-2', title: 'Título', message: 'Mensagem' },
 * ]);
 *
 * // Destaque simples
 * this.tourService.spotlight('meu-elemento', { title: 'Dica', message: 'Detalhes' });
 * ```
 */
class SpotlightTourService {
    overlay = inject(Overlay);
    environmentInjector = inject(EnvironmentInjector);
    overlayRef = null;
    _steps = signal([]);
    _currentIndex = signal(0);
    _isActive = signal(false);
    _registrationVersion = signal(0);
    _registeredElements = new Map();
    _pendingDoNotShowAgain = false;
    _stopped$ = new Subject();
    _stepChanged$ = new Subject();
    /** Signal somente-leitura que indica se o tour está ativo no momento. */
    isActive = this._isActive.asReadonly();
    /** Signal somente-leitura com o índice (0-based) do passo exibido atualmente. */
    currentIndex = this._currentIndex.asReadonly();
    /** Signal computado com o total de passos do tour em andamento. */
    totalSteps = computed(() => this._steps().length);
    /** Signal computado com os dados do passo atualmente exibido. */
    currentStep = computed(() => this._steps()[this._currentIndex()]);
    /**
     * Observable emitido quando o tour é encerrado, seja por conclusão, interrupção
     * ou descarte. Carrega um `SpotlightStopEvent` com o motivo e o estado final.
     */
    stopped$ = this._stopped$.asObservable();
    /**
     * Observable emitido sempre que o passo exibido muda, incluindo o início do tour.
     * Carrega um `SpotlightStepChangedEvent` com o `stepId` e o índice do novo passo.
     */
    stepChanged$ = this._stepChanged$.asObservable();
    /**
     * Signal somente-leitura incrementado a cada chamada de `registerElement` ou
     * `unregisterElement`. Permite que outros componentes reajam a mudanças no
     * registro de elementos sem polling.
     */
    registrationVersion = this._registrationVersion.asReadonly();
    /**
     * Inicia um tour com a lista de passos fornecida.
     *
     * O tour começa pelo primeiro passo da lista. Emite `stepChanged$` para o passo inicial.
     * Se `steps` for um array vazio, o método não faz nada.
     * Se já houver um tour ativo, ele é encerrado (emitindo `stopped$` com `reason: 'interrupted'`)
     * antes de o novo tour começar.
     *
     * @param steps Lista de passos a percorrer em ordem.
     */
    start(steps) {
        if (steps.length === 0)
            return;
        if (this._isActive()) {
            this.stop();
        }
        this._steps.set(steps);
        this._currentIndex.set(0);
        this._isActive.set(true);
        this.attachOverlay();
        this._stepChanged$.next({ stepId: steps[0].stepId, stepIndex: 0, totalSteps: steps.length });
    }
    /**
     * Exibe um destaque simples (passo único) no elemento identificado por `stepId`.
     *
     * Equivalente a chamar `start()` com um array de um único passo.
     * O checkbox "Não mostrar novamente" é exibido por padrão (`showDoNotShowAgain: true`);
     * passe `showDoNotShowAgain: false` em `config` para suprimi-lo.
     *
     * @param stepId ID do elemento registrado via `sSpotlightStep` ou `registerElement`.
     * @param config Configuração visual e comportamental do destaque.
     */
    spotlight(stepId, config) {
        const step = { stepId, ...config };
        this.start([step]);
    }
    /**
     * Avança para o próximo passo do tour.
     *
     * Se o passo atual definir `beforeNext`, aguarda sua resolução antes de avançar.
     * No último passo, encerra o tour com `reason: 'completed'`.
     *
     * @param doNotShowAgain Quando `true`, o evento `stopped$` será emitido com
     *   `doNotShowAgain: true` ao concluir o tour. Relevante apenas no último passo.
     */
    next(doNotShowAgain = false) {
        const current = this.currentStep();
        this._pendingDoNotShowAgain = doNotShowAgain;
        if (current?.beforeNext) {
            const result = current.beforeNext();
            if (result instanceof Promise) {
                result.then(() => this.advance()).catch(() => { });
            }
            else {
                this.advance();
            }
        }
        else {
            this.advance();
        }
    }
    /**
     * Retorna ao passo anterior do tour.
     *
     * Se o passo atual definir `beforePrevious`, aguarda sua resolução antes de voltar.
     * Não faz nada se o tour estiver no primeiro passo.
     */
    previous() {
        if (this._currentIndex() <= 0)
            return;
        const current = this.currentStep();
        if (current?.beforePrevious) {
            const result = current.beforePrevious();
            if (result instanceof Promise) {
                result.then(() => this.retreat()).catch(() => { });
            }
            else {
                this.retreat();
            }
        }
        else {
            this.retreat();
        }
    }
    /**
     * Encerra o tour imediatamente e emite o evento `stopped$`.
     *
     * @param event Dados parciais do evento de parada. Valores não fornecidos são
     *   preenchidos com os defaults: `reason: 'interrupted'`, `doNotShowAgain: false`
     *   e o `stepId`/`stepIndex`/`totalSteps` do momento atual.
     */
    stop(event) {
        const steps = this._steps();
        const index = this._currentIndex();
        const fullEvent = {
            reason: 'interrupted',
            doNotShowAgain: false,
            stepId: steps[index]?.stepId ?? '',
            stepIndex: index,
            totalSteps: steps.length,
            ...event,
        };
        this._isActive.set(false);
        this._steps.set([]);
        this._currentIndex.set(0);
        this._pendingDoNotShowAgain = false;
        this._stopped$.next(fullEvent);
        this.detachOverlay();
    }
    /**
     * Registra um elemento do DOM como alvo do passo identificado por `stepId`.
     *
     * Normalmente chamado pela diretiva `sSpotlightStep`. Use diretamente apenas
     * quando precisar registrar elementos criados programaticamente.
     *
     * @param stepId ID único do passo ao qual o elemento pertence.
     * @param el Referência ao elemento do DOM.
     */
    registerElement(stepId, el) {
        this._registeredElements.set(stepId, el);
        this._registrationVersion.update((v) => v + 1);
    }
    /**
     * Remove o registro do elemento associado a `stepId`.
     *
     * Normalmente chamado pela diretiva `sSpotlightStep` no `ngOnDestroy`.
     *
     * @param stepId ID do passo cujo elemento deve ser removido.
     */
    unregisterElement(stepId) {
        this._registeredElements.delete(stepId);
        this._registrationVersion.update((v) => v + 1);
    }
    /**
     * Retorna o `ElementRef` registrado para o `stepId` informado,
     * ou `undefined` se nenhum elemento estiver registrado.
     *
     * @param stepId ID do passo a buscar.
     */
    getElement(stepId) {
        return this._registeredElements.get(stepId);
    }
    advance() {
        const steps = this._steps();
        const currentIndex = this._currentIndex();
        if (currentIndex < steps.length - 1) {
            const newIndex = currentIndex + 1;
            this._pendingDoNotShowAgain = false;
            this._currentIndex.set(newIndex);
            this._stepChanged$.next({ stepId: steps[newIndex].stepId, stepIndex: newIndex, totalSteps: steps.length });
        }
        else {
            this.stop({ reason: 'completed', doNotShowAgain: this._pendingDoNotShowAgain });
        }
    }
    retreat() {
        const steps = this._steps();
        const newIndex = this._currentIndex() - 1;
        this._currentIndex.set(newIndex);
        this._stepChanged$.next({ stepId: steps[newIndex].stepId, stepIndex: newIndex, totalSteps: steps.length });
    }
    attachOverlay() {
        if (this.overlayRef) {
            return;
        }
        this.overlayRef = this.overlay.create({
            hasBackdrop: false,
            scrollStrategy: this.overlay.scrollStrategies.noop(),
            positionStrategy: this.overlay.position().global(),
        });
        const portal = new ComponentPortal(SpotlightOverlayComponent, null, this.environmentInjector);
        this.overlayRef.attach(portal);
    }
    detachOverlay() {
        if (this.overlayRef) {
            this.overlayRef.detach();
            this.overlayRef.dispose();
            this.overlayRef = null;
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightTourService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightTourService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightTourService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }] });

/**
 * Diretiva que registra um elemento do DOM como alvo de um passo do Spotlight Tour.
 *
 * Aplique a diretiva em qualquer elemento e forneça um ID único que corresponda
 * ao `stepId` configurado no `SpotlightTourService`. O elemento será automaticamente
 * registrado ao ser criado e atualizado caso o ID mude dinamicamente.
 *
 * @example
 * ```html
 * <button [sSpotlightStep]="'meu-botao'">Clique aqui</button>
 * ```
 */
class SpotlightStepDirective {
    /**
     * ID único do passo do tour ao qual este elemento está associado.
     * Deve corresponder ao `stepId` definido em `SpotlightStep`.
     */
    sSpotlightStep = input.required();
    el = inject(ElementRef);
    tourService = inject(SpotlightTourService);
    currentId = null;
    constructor() {
        effect(() => {
            const newId = this.sSpotlightStep();
            if (this.currentId !== null && this.currentId !== newId) {
                this.tourService.unregisterElement(this.currentId);
            }
            this.currentId = newId;
            this.tourService.registerElement(newId, this.el);
        }, { allowSignalWrites: true });
    }
    ngOnDestroy() {
        if (this.currentId !== null) {
            this.tourService.unregisterElement(this.currentId);
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightStepDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.14", type: SpotlightStepDirective, isStandalone: true, selector: "[sSpotlightStep]", inputs: { sSpotlightStep: { classPropertyName: "sSpotlightStep", publicName: "sSpotlightStep", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SpotlightStepDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[sSpotlightStep]',
                    standalone: true,
                }]
        }], ctorParameters: () => [] });

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

export { SpotlightComponent, SpotlightStepDirective, SpotlightTourService };
//# sourceMappingURL=seniorsistemas-angular-components-spotlight.mjs.map
