import * as i0 from '@angular/core';
import { Component, Input, NgModule, inject, Renderer2, LOCALE_ID, Directive, HostListener, ElementRef } from '@angular/core';
import { NgClass, DOCUMENT } from '@angular/common';
import { TooltipDirective } from '@seniorsistemas/angular-components/tooltip';
import { DatePicker } from 'primeng/datepicker';
import { TranslateService } from '@ngx-translate/core';

var EnumSeverity;
(function (EnumSeverity) {
    EnumSeverity["Default"] = "default";
    EnumSeverity["Info"] = "info";
    EnumSeverity["Warn"] = "warn";
    EnumSeverity["Error"] = "error";
    EnumSeverity["Success"] = "success";
})(EnumSeverity || (EnumSeverity = {}));

/**
 * @description Botão com borda que varia de estilo de acordo com a severidade informada.
 * Utilizado internamente por outros componentes da biblioteca.
 *
 * @category Shared
 */
class BorderButtonComponent {
    /** @description Nível de severidade que define a cor e estilo do botão. @default 'default' */
    severity = 'default';
    /** @description Opções de configuração do botão (rótulo, ação, etc.). */
    options;
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BorderButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: BorderButtonComponent, isStandalone: true, selector: "s-border-button", inputs: { severity: "severity", options: "options" }, ngImport: i0, template: "<button\n    class=\"border-button\"\n    [ngClass]=\"{\n        'border-button--severity-default': severity === 'default',\n        'border-button--severity-info': severity === 'info',\n        'border-button--severity-warn': severity === 'warn',\n        'border-button--severity-error': severity === 'error',\n        'border-button--severity-success': severity === 'success',\n        'border-button--disabled': options?.disabled ? options?.disabled(severity) : false,\n    }\"\n    (click)=\"options?.onClick ? options?.onClick(severity) : null\"\n    [sTooltip]=\"options?.tooltip?.(severity)\"\n    tooltipPosition=\"left\"\n    [disabled]=\"options?.disabled ? options?.disabled(severity) : false\"\n>\n    <span class=\"border-button__label\">\n        {{ options?.label ? options?.label(severity) : null }}\n    </span>\n    @if (options?.icon ? options?.icon(severity) : false) {\n        <span class=\"border-button__icon {{ options?.icon(severity) }}\"></span>\n    }\n</button>\n", styles: [".border-button{padding:0 8px;border:1px solid;border-radius:12px;height:23px;max-width:320px;display:flex;justify-content:center;align-items:center;cursor:pointer}.border-button__label{font-family:Open Sans,sans-serif;font-size:12px;line-height:150%;width:100%;display:block;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.border-button__icon{font-size:12px;color:#333;margin-left:8px}.border-button--severity-default{border-color:#ccc;background-color:#fff}.border-button--severity-info{border-color:#428bca;background-color:#d5e8ec;transition:background-color .5s ease,border-color .5s ease}.border-button--severity-info:enabled:hover{background-color:#9ecad4;cursor:pointer}.border-button--severity-info:enabled:active{transition:none;background-color:#67acbc;border-color:#67acbc}.border-button--severity-warn{border-color:#f8931f;background-color:#fce3ba;transition:background-color .5s ease,border-color .5s ease}.border-button--severity-warn:enabled:hover{background-color:#f8bf5e;cursor:pointer}.border-button--severity-warn:enabled:active{transition:none;background-color:#f5a319;border-color:#f5a319}.border-button--severity-error{border-color:#c13018;background-color:#fcd2d2;transition:background-color .5s ease,border-color .5s ease}.border-button--severity-error:enabled:hover{background-color:#f89696;cursor:pointer}.border-button--severity-error:enabled:active{transition:none;background-color:#f45b5b;border-color:#f45b5b}.border-button--severity-success{border-color:#0c9348;background-color:#e6ffb3;transition:background-color .5s ease,border-color .5s ease}.border-button--severity-success:enabled:hover{background-color:#c8ff5c;cursor:pointer}.border-button--severity-success:enabled:active{transition:none;background-color:#ade500;border-color:#ade500}.border-button--disabled:disabled:hover{cursor:default}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: TooltipDirective, selector: "[sTooltip]", inputs: ["sTooltip", "tooltipPosition", "showDelay", "displayTime", "tooltipEvent", "escape", "visible", "mobileBehavior", "focusedInputRef", "checkTruncatedText"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BorderButtonComponent, decorators: [{
            type: Component,
            args: [{ selector: 's-border-button', standalone: true, imports: [NgClass, TooltipDirective], template: "<button\n    class=\"border-button\"\n    [ngClass]=\"{\n        'border-button--severity-default': severity === 'default',\n        'border-button--severity-info': severity === 'info',\n        'border-button--severity-warn': severity === 'warn',\n        'border-button--severity-error': severity === 'error',\n        'border-button--severity-success': severity === 'success',\n        'border-button--disabled': options?.disabled ? options?.disabled(severity) : false,\n    }\"\n    (click)=\"options?.onClick ? options?.onClick(severity) : null\"\n    [sTooltip]=\"options?.tooltip?.(severity)\"\n    tooltipPosition=\"left\"\n    [disabled]=\"options?.disabled ? options?.disabled(severity) : false\"\n>\n    <span class=\"border-button__label\">\n        {{ options?.label ? options?.label(severity) : null }}\n    </span>\n    @if (options?.icon ? options?.icon(severity) : false) {\n        <span class=\"border-button__icon {{ options?.icon(severity) }}\"></span>\n    }\n</button>\n", styles: [".border-button{padding:0 8px;border:1px solid;border-radius:12px;height:23px;max-width:320px;display:flex;justify-content:center;align-items:center;cursor:pointer}.border-button__label{font-family:Open Sans,sans-serif;font-size:12px;line-height:150%;width:100%;display:block;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.border-button__icon{font-size:12px;color:#333;margin-left:8px}.border-button--severity-default{border-color:#ccc;background-color:#fff}.border-button--severity-info{border-color:#428bca;background-color:#d5e8ec;transition:background-color .5s ease,border-color .5s ease}.border-button--severity-info:enabled:hover{background-color:#9ecad4;cursor:pointer}.border-button--severity-info:enabled:active{transition:none;background-color:#67acbc;border-color:#67acbc}.border-button--severity-warn{border-color:#f8931f;background-color:#fce3ba;transition:background-color .5s ease,border-color .5s ease}.border-button--severity-warn:enabled:hover{background-color:#f8bf5e;cursor:pointer}.border-button--severity-warn:enabled:active{transition:none;background-color:#f5a319;border-color:#f5a319}.border-button--severity-error{border-color:#c13018;background-color:#fcd2d2;transition:background-color .5s ease,border-color .5s ease}.border-button--severity-error:enabled:hover{background-color:#f89696;cursor:pointer}.border-button--severity-error:enabled:active{transition:none;background-color:#f45b5b;border-color:#f45b5b}.border-button--severity-success{border-color:#0c9348;background-color:#e6ffb3;transition:background-color .5s ease,border-color .5s ease}.border-button--severity-success:enabled:hover{background-color:#c8ff5c;cursor:pointer}.border-button--severity-success:enabled:active{transition:none;background-color:#ade500;border-color:#ade500}.border-button--disabled:disabled:hover{cursor:default}\n"] }]
        }], propDecorators: { severity: [{
                type: Input
            }], options: [{
                type: Input
            }] } });

class BorderButtonModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BorderButtonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: BorderButtonModule, imports: [BorderButtonComponent], exports: [BorderButtonComponent] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BorderButtonModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BorderButtonModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [BorderButtonComponent],
                    exports: [BorderButtonComponent],
                }]
        }] });

/**
 * A decorator that can be used to disable functions based on a boolean property on the component.
 *
 * @param disabledField The name of the boolean property that will be used to determine if the decorated
 * function should be disabled. Defaults to 'disabled'.
 * @returns A decorator function that can be used to decorate a function.
 *
 * @example
 * class MyComponent {
 *   disabled = true;
 *
 *   @CheckDisabled()
 *   onClick() {
 *     console.log('Button was clicked');
 *   }
 * }
 */
function CheckDisabled(disabledField = 'disabled') {
    return function (_target, _propertyKey, descriptor) {
        const originalMethod = descriptor.value;
        descriptor.value = function (...args) {
            const self = this;
            if (self[disabledField]) {
                return;
            }
            return originalMethod.apply(this, args);
        };
        return descriptor;
    };
}

/**
 * CSS customizado injetado globalmente para focus-visible nos internals do DatePicker.
 * Necessário porque com `appendTo="body"` o overlay fica fora do host component,
 * e estilos com `:host ::ng-deep` ou ViewEncapsulation.Emulated não alcançam.
 */
const FOCUS_STYLE_ID = 's-datepicker-a11y-focus-styles';
/** Delay em ms para foco pós-abertura e navegação (permite NVDA processar dialog announce). */
const FOCUS_DELAY_MS = 50;
/** Delay em ms para debounce do MutationObserver (evita re-execução por ripple/animações). */
const MUTATION_DEBOUNCE_MS = 100;
/** Attribute name constant to avoid SonarQube literal duplication warning. */
const ARIA_LABEL_ATTR = 'aria-label';
const FOCUS_STYLES = `
.p-datepicker-day:focus-visible,
.p-datepicker-day.s-datepicker-day-focused {
    outline: 2px solid var(--p-primary-color, #3b82f6) !important;
    outline-offset: -2px;
    border-radius: 4px;
}
.p-datepicker-month:focus-visible,
.p-datepicker-month.s-datepicker-day-focused {
    outline: 2px solid var(--p-primary-color, #3b82f6) !important;
    outline-offset: -2px;
    border-radius: 4px;
}
.p-datepicker-year:focus-visible,
.p-datepicker-year.s-datepicker-day-focused {
    outline: 2px solid var(--p-primary-color, #3b82f6) !important;
    outline-offset: -2px;
    border-radius: 4px;
}
.p-datepicker-select-month:focus-visible,
.p-datepicker-select-year:focus-visible {
    outline: 2px solid var(--p-primary-color, #3b82f6) !important;
    outline-offset: 2px;
    border-radius: 4px;
}
.p-datepicker-prev-button:focus-visible,
.p-datepicker-next-button:focus-visible {
    outline: 2px solid var(--p-primary-color, #3b82f6) !important;
    outline-offset: 2px;
    border-radius: 50%;
}
`;
/**
 * Traduções pt-BR para aria-labels do DatePicker PrimeNG.
 * PrimeNG usa `getTranslation()` que retorna inglês por padrão
 * se não configurado via `PrimeNGConfig.setTranslation()`.
 *
 * Keys correspondem ao texto exato renderizado pelo PrimeNG no DOM:
 * - "Previous Month" (não "Prev Month")
 * - "Choose Date", "Choose Month", "Choose Year"
 */
const PREV_DECADE_PT = 'Década anterior';
const PREV_DECADE_ES = 'Década anterior';
const ARIA_TRANSLATIONS_PT_BR = {
    'Choose Date': 'Selecionar data',
    'Choose Month': 'Selecionar mês',
    'Choose Year': 'Selecionar ano',
    'Previous Month': 'Mês anterior',
    'Next Month': 'Próximo mês',
    'Previous Year': 'Ano anterior',
    'Next Year': 'Próximo ano',
    'Previous Decade': PREV_DECADE_PT,
    'Next Decade': 'Próxima década',
    'Prev Month': 'Mês anterior',
    'Prev Year': 'Ano anterior',
    'Prev Decade': PREV_DECADE_PT,
};
const ARIA_TRANSLATIONS_ES = {
    'Choose Date': 'Seleccionar fecha',
    'Choose Month': 'Seleccionar mes',
    'Choose Year': 'Seleccionar año',
    'Previous Month': 'Mes anterior',
    'Next Month': 'Próximo mes',
    'Previous Year': 'Año anterior',
    'Next Year': 'Próximo año',
    'Previous Decade': PREV_DECADE_ES,
    'Next Decade': 'Próxima década',
    'Prev Month': 'Mes anterior',
    'Prev Year': 'Año anterior',
    'Prev Decade': PREV_DECADE_ES,
};
const ARIA_TRANSLATIONS = {
    'pt-BR': ARIA_TRANSLATIONS_PT_BR,
    'pt': ARIA_TRANSLATIONS_PT_BR,
    'es': ARIA_TRANSLATIONS_ES,
    'es-CO': ARIA_TRANSLATIONS_ES,
    'es-ES': ARIA_TRANSLATIONS_ES,
};
/**
 * Diretiva para corrigir a acessibilidade do painel do DatePicker PrimeNG.
 *
 * Resolve os seguintes problemas:
 *
 * 1. **Foco inicial ao abrir overlay**: move foco programaticamente para
 *    a célula selecionada, hoje, ou primeira célula disponível — evitando
 *    que NVDA leia toda estrutura do grid ao entrar no painel.
 *
 * 2. **Re-foco ao trocar view (mês/ano)**: ao navegar para views de mês ou
 *    ano, o DOM é destruído e recriado. Sem intervenção, foco escapa para
 *    `<body>` e NVDA lê conteúdo fora do overlay. A diretiva re-foca o
 *    primeiro elemento interativo da nova view.
 *
 * 3. **Focus-visible nos elementos internos**: injeta CSS global com
 *    outline para todos elementos interativos do overlay, garantindo
 *    feedback visual mesmo com `appendTo="body"`.
 *
 * 4. **aria-label enriquecido nos day cells**: PrimeNG seta apenas o
 *    número do dia. A diretiva sobrescreve com data completa formatada
 *    (ex: "3 de junho de 2026, Qua") — NVDA narra label sem precisar
 *    contextualizar toda grid.
 *
 * 5. **View de meses/anos sem tabindex**: spans de mês/ano recebem
 *    `tabindex="0"` e `role="option"` para navegação por teclado.
 *
 * Utiliza `MutationObserver` para detectar mudanças internas de view,
 * já que PrimeNG não emite eventos para essas transições.
 *
 * **CSS**: A diretiva injeta um `<style>` global no `<head>` (uma vez).
 * Para projetos que preferem controle manual, desabilite via Input
 * `[sDatepickerInjectStyles]="false"` e importe os estilos manualmente.
 *
 * Uso: `<p-datepicker sDatepickerNoPeriodTab ...>`
 *
 * @deprecated Use `s-datepicker` (`<s-datepicker>`), o componente oficial do
 * Design System da Senior, que implementa toda a acessibilidade necessária
 * nativamente. Esta diretiva será removida na próxima major release.
 *
 * @category Directives
 */
class DatepickerNoPeriodTabDirective {
    datePicker = inject(DatePicker);
    renderer = inject(Renderer2);
    locale = inject(LOCALE_ID);
    document = inject(DOCUMENT);
    observer = null;
    focusListenerCleanups = [];
    constructor() {
        this.injectGlobalFocusStyles();
    }
    onPanelShow() {
        setTimeout(() => {
            this.fixPanelAccessibility();
            // Não chamar focusBestTarget() aqui — PrimeNG initFocusableCell()
            // já move foco pro day cell com tabindex="0" na abertura.
            // Chamar de novo causa double-announce no NVDA.
            setTimeout(() => this.observePanelChanges(), MUTATION_DEBOUNCE_MS);
        }, FOCUS_DELAY_MS);
    }
    onNavigationChange() {
        setTimeout(() => {
            this.fixPanelAccessibility();
            this.focusBestTarget();
        }, FOCUS_DELAY_MS);
    }
    ngOnDestroy() {
        this.disconnectObserver();
        this.removeFocusListeners();
    }
    /**
     * Move foco para melhor alvo disponível no painel.
     * Usado ao abrir overlay e ao trocar view (mês/ano).
     *
     * Ao abrir: evita que NVDA leia toda estrutura do grid.
     * Ao trocar view: previne foco escapar para `<body>` quando
     * PrimeNG destrói DOM da view anterior.
     *
     * Prioridade: selecionado > hoje > primeiro disponível.
     * Pula se foco já está no target correto (evita double-announce no NVDA).
     */
    focusBestTarget() {
        const panel = this.datePicker.overlay;
        if (!panel) {
            return;
        }
        const target = this.findFocusTarget(panel);
        if (target && this.document.activeElement !== target) {
            target.tabIndex = 0;
            target.focus();
        }
    }
    /**
     * Injeta CSS global de focus-visible no `<head>` do documento.
     * Executa apenas uma vez (idempotente via ID do style element).
     * Necessário porque overlay com `appendTo="body"` fica fora do
     * escopo de ViewEncapsulation do componente host.
     */
    injectGlobalFocusStyles() {
        if (this.document.getElementById(FOCUS_STYLE_ID)) {
            return;
        }
        const style = this.renderer.createElement('style');
        this.renderer.setAttribute(style, 'id', FOCUS_STYLE_ID);
        this.renderer.setAttribute(style, 'type', 'text/css');
        const text = this.renderer.createText(FOCUS_STYLES);
        this.renderer.appendChild(style, text);
        this.renderer.appendChild(this.document.head, style);
    }
    /**
     * Encontra melhor elemento para receber foco no painel atual.
     * Busca em ordem: selecionado → hoje → primeiro disponível.
     * Funciona para views de dias, meses e anos.
     */
    findFocusTarget(panel) {
        // View de dias
        const selectedDay = panel.querySelector('.p-datepicker-day-selected, .p-datepicker-day[aria-selected="true"]');
        if (selectedDay) {
            return selectedDay;
        }
        const today = panel.querySelector('.p-datepicker-today .p-datepicker-day');
        if (today) {
            return today;
        }
        // View de meses
        const selectedMonth = panel.querySelector('.p-datepicker-month.p-datepicker-month-selected');
        if (selectedMonth) {
            return selectedMonth;
        }
        const firstMonth = panel.querySelector('.p-datepicker-month:not(.p-disabled)');
        if (firstMonth) {
            return firstMonth;
        }
        // View de anos
        const selectedYear = panel.querySelector('.p-datepicker-year.p-datepicker-year-selected');
        if (selectedYear) {
            return selectedYear;
        }
        const firstYear = panel.querySelector('.p-datepicker-year:not(.p-disabled)');
        if (firstYear) {
            return firstYear;
        }
        // Fallback: primeiro day cell disponível
        const firstDay = panel.querySelector('.p-datepicker-day:not(.p-disabled)');
        return firstDay;
    }
    /**
     * Aplica correções de acessibilidade no painel do DatePicker,
     * independente da view interna ativa (dias, meses ou anos).
     */
    fixPanelAccessibility() {
        const panel = this.datePicker.overlay;
        if (!panel) {
            return;
        }
        panel.querySelectorAll('.p-datepicker-select-month, .p-datepicker-select-year').forEach((btn) => {
            this.renderer.setAttribute(btn, 'tabindex', '0');
        });
        panel.querySelectorAll('.p-datepicker-month:not([tabindex])').forEach((month) => {
            this.renderer.setAttribute(month, 'tabindex', '0');
            this.renderer.setAttribute(month, 'role', 'option');
        });
        panel.querySelectorAll('.p-datepicker-year:not([tabindex])').forEach((year) => {
            this.renderer.setAttribute(year, 'tabindex', '0');
            this.renderer.setAttribute(year, 'role', 'option');
        });
        this.applyGridcellRoleToDays(panel);
        this.enrichDayCellAriaLabels(panel);
        this.enrichGridAriaLabel(panel);
        this.translateAriaLabels(panel);
        this.fixNavigationButtonLabels(panel);
        this.removeApplicationRoleFromContainer(panel);
        this.setupFocusTracking(panel);
    }
    /**
     * Adiciona `role="gridcell"` nos `<span class="p-datepicker-day">` que recebem foco.
     *
     * PrimeNG coloca `tabindex` no `<span>` dentro do `<td>`, mas sem role explícito.
     * NVDA não entra automaticamente em focus mode quando foca um elemento sem
     * role de widget (gridcell, button, etc). Resultado: NVDA fica em browse mode
     * e lê toda a tabela sequencialmente ao invés de anunciar só a célula focada.
     *
     * Ao adicionar `role="gridcell"` no span focável, NVDA reconhece que é um
     * widget interativo e entra em focus mode — anunciando apenas o aria-label
     * da célula focada.
     */
    applyGridcellRoleToDays(panel) {
        panel.querySelectorAll('.p-datepicker-day:not(.p-disabled)').forEach((daySpan) => {
            if (!daySpan.getAttribute('role')) {
                this.renderer.setAttribute(daySpan, 'role', 'gridcell');
            }
        });
    }
    /**
     * Enriquece `aria-label` dos day cells com data completa formatada.
     * PrimeNG por padrão usa apenas o número do dia, forçando NVDA
     * a narrar contexto de grid (linha/coluna/weekday) para informar a data.
     * Com aria-label completo, NVDA narra diretamente a data sem verbosidade.
     */
    enrichDayCellAriaLabels(panel) {
        const { currentMonth, currentYear } = this.datePicker;
        if (currentMonth == null || currentYear == null) {
            return;
        }
        const weekdayHeaders = panel.querySelectorAll('.p-datepicker-weekday');
        const weekdays = [];
        weekdayHeaders.forEach((header) => {
            weekdays.push(header.textContent?.trim() || '');
        });
        const rows = panel.querySelectorAll('.p-datepicker-day-view tbody tr');
        rows.forEach((row) => {
            const cells = row.querySelectorAll('td');
            cells.forEach((cell, cellIndex) => {
                const daySpan = cell.querySelector('.p-datepicker-day');
                if (!daySpan) {
                    return;
                }
                const dayNumber = parseInt(daySpan.textContent?.trim() || '0', 10);
                if (!dayNumber) {
                    return;
                }
                const isOtherMonth = cell.classList.contains('p-datepicker-other-month');
                if (isOtherMonth) {
                    return;
                }
                const date = new Date(currentYear, currentMonth, dayNumber);
                const formattedDate = this.formatDateForAriaLabel(date);
                const weekday = weekdays[cellIndex] || '';
                const ariaLabel = weekday ? `${formattedDate}, ${weekday}` : formattedDate;
                this.renderer.setAttribute(daySpan, ARIA_LABEL_ATTR, ariaLabel);
            });
        });
    }
    /**
     * Adiciona aria-label no grid com mês/ano atual para dar contexto
     * imediato ao NVDA ao entrar na tabela de dias.
     * Exemplo: "Calendário, Junho 2026"
     */
    enrichGridAriaLabel(panel) {
        const grid = panel.querySelector('.p-datepicker-day-view[role="grid"]');
        if (!grid) {
            return;
        }
        const { currentMonth, currentYear } = this.datePicker;
        if (currentMonth == null || currentYear == null) {
            return;
        }
        const monthName = new Date(currentYear, currentMonth, 1).toLocaleDateString('pt-BR', {
            month: 'long',
        });
        const capitalizedMonth = monthName.charAt(0).toUpperCase() + monthName.slice(1);
        const label = `Calendário, ${capitalizedMonth} ${currentYear}`;
        this.renderer.setAttribute(grid, ARIA_LABEL_ATTR, label);
    }
    /**
     * Formata data para aria-label legível por leitor de tela.
     * Sempre usa pt-BR para garantir consistência com labels traduzidos,
     * independente do LOCALE_ID configurado no Angular.
     * Exemplo: "3 de junho de 2026"
     */
    formatDateForAriaLabel(date) {
        try {
            return date.toLocaleDateString('pt-BR', {
                day: 'numeric',
                month: 'long',
                year: 'numeric',
            });
        }
        catch {
            return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`;
        }
    }
    /**
     * Retorna locale string para formatação.
     */
    getLocale() {
        return this.locale || 'pt-BR';
    }
    /**
     * Traduz aria-labels dos botões do header que PrimeNG renderiza em inglês.
     * PrimeNG usa `getTranslation('chooseDate')` etc, que retorna inglês
     * se `PrimeNGConfig.setTranslation()` não foi configurado pelo projeto.
     *
     * Busca botões com aria-label em inglês e traduz pro locale atual.
     */
    translateAriaLabels(panel) {
        const translations = this.getTranslations();
        // Dialog aria-label ("Choose Date")
        const dialog = panel.closest('[role="dialog"]') || panel;
        const dialogLabel = dialog.getAttribute(ARIA_LABEL_ATTR);
        if (dialogLabel && translations[dialogLabel]) {
            this.renderer.setAttribute(dialog, ARIA_LABEL_ATTR, translations[dialogLabel]);
        }
        // Botões "Choose Month" e "Choose Year" no header
        panel.querySelectorAll('.p-datepicker-select-month, .p-datepicker-select-year').forEach((btn) => {
            const label = btn.getAttribute(ARIA_LABEL_ATTR);
            if (label && translations[label]) {
                this.renderer.setAttribute(btn, ARIA_LABEL_ATTR, translations[label]);
            }
        });
    }
    /**
     * Corrige aria-label dos botões prev/next do PrimeNG.
     * PrimeNG usa `p-button` component que seta `aria-label` no host element `<p-button>`,
     * mas NVDA foca o `<button>` interno que não herda o label do custom element.
     *
     * Estrutura DOM: `<p-button aria-label="Previous Month"><button class="p-datepicker-prev-button">...</button></p-button>`
     *
     * Fix: lê aria-label do `<p-button>` host, traduz, e propaga pro `<button>` interno.
     */
    fixNavigationButtonLabels(panel) {
        const translations = this.getTranslations();
        // Buscar <p-button> hosts que contém os botões prev/next
        const pButtons = panel.querySelectorAll('p-button');
        pButtons.forEach((pBtn) => {
            const innerButton = pBtn.querySelector('button.p-datepicker-prev-button, button.p-datepicker-next-button');
            if (!innerButton) {
                return;
            }
            let label = pBtn.getAttribute(ARIA_LABEL_ATTR) || '';
            // Traduzir
            if (label && translations[label]) {
                label = translations[label];
                this.renderer.setAttribute(pBtn, ARIA_LABEL_ATTR, label);
            }
            // Propagar pro <button> interno
            if (label) {
                this.renderer.setAttribute(innerButton, ARIA_LABEL_ATTR, label);
            }
        });
    }
    /**
     * Remove `role="application"` do container do calendário.
     *
     * PrimeNG seta `role="application"` no `.p-datepicker-calendar-container`
     * para que arrow keys cheguem no JavaScript sem interceptação do browse mode.
     * Porém `role="grid"` na table já garante esse comportamento — NVDA entra
     * automaticamente em focus mode ao focar uma gridcell.
     *
     * O `role="application"` no container PAI causa NVDA a despeja o conteúdo
     * virtual do container inteiro ao entrar no dialog, antes de pousar na célula.
     * Removê-lo resolve a leitura excessiva sem quebrar navegação por setas.
     */
    removeApplicationRoleFromContainer(panel) {
        const calendarContainer = panel.querySelector('.p-datepicker-calendar-container');
        if (calendarContainer?.getAttribute('role') === 'application') {
            this.renderer.removeAttribute(calendarContainer, 'role');
        }
    }
    /**
     * Retorna mapa de traduções pro locale atual.
     * Se locale é inglês ou não reconhecido, fallback pra pt-BR
     * (assumimos que labels em inglês devem ser traduzidos).
     */
    getTranslations() {
        const locale = this.getLocale();
        return ARIA_TRANSLATIONS[locale]
            || ARIA_TRANSLATIONS[locale.split('-')[0]]
            || ARIA_TRANSLATIONS_PT_BR;
    }
    /**
     * Adiciona listeners de focus/blur nos elementos interativos para
     * garantir indicador visual quando `.focus()` é chamado programaticamente.
     *
     * `:focus-visible` pode não ser aplicado quando foco é movido via JS,
     * então usamos classe auxiliar `s-datepicker-day-focused` como fallback.
     */
    setupFocusTracking(panel) {
        this.removeFocusListeners();
        const focusableElements = panel.querySelectorAll('.p-datepicker-day, .p-datepicker-month, .p-datepicker-year');
        focusableElements.forEach((el) => {
            const focusCleanup = this.renderer.listen(el, 'focus', () => {
                this.renderer.addClass(el, 's-datepicker-day-focused');
            });
            const blurCleanup = this.renderer.listen(el, 'blur', () => {
                this.renderer.removeClass(el, 's-datepicker-day-focused');
            });
            this.focusListenerCleanups.push(focusCleanup, blurCleanup);
        });
    }
    /**
     * Remove listeners de focus/blur registrados anteriormente.
     */
    removeFocusListeners() {
        this.focusListenerCleanups.forEach((cleanup) => cleanup());
        this.focusListenerCleanups = [];
    }
    /**
     * Observa mudanças no DOM do painel para reaplicar correções
     * quando o PrimeNG troca a view interna (dias → meses → anos).
     * Usa debounce e só reage a childList changes (não attributes)
     * para evitar loop infinito com as próprias mutações da diretiva.
     */
    observePanelChanges() {
        this.disconnectObserver();
        const panel = this.datePicker.overlay;
        if (!panel) {
            return;
        }
        let debounceTimer = null;
        let isProcessing = false;
        this.observer = new MutationObserver((mutations) => {
            if (isProcessing) {
                return;
            }
            // Só reagir se houve adição/remoção de nós (troca de view)
            const hasStructuralChange = mutations.some((m) => m.type === 'childList' && (m.addedNodes.length > 0 || m.removedNodes.length > 0));
            if (!hasStructuralChange) {
                return;
            }
            if (debounceTimer) {
                clearTimeout(debounceTimer);
            }
            debounceTimer = setTimeout(() => {
                isProcessing = true;
                this.fixPanelAccessibility();
                this.focusBestTarget();
                isProcessing = false;
            }, MUTATION_DEBOUNCE_MS);
        });
        this.observer.observe(panel, {
            childList: true,
            subtree: true,
        });
    }
    disconnectObserver() {
        if (this.observer) {
            this.observer.disconnect();
            this.observer = null;
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatepickerNoPeriodTabDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: DatepickerNoPeriodTabDirective, isStandalone: true, selector: "[sDatepickerNoPeriodTab]", host: { listeners: { "onShow": "onPanelShow()", "onMonthChange": "onNavigationChange()", "onYearChange": "onNavigationChange()" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatepickerNoPeriodTabDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[sDatepickerNoPeriodTab]',
                    standalone: true,
                }]
        }], ctorParameters: () => [], propDecorators: { onPanelShow: [{
                type: HostListener,
                args: ['onShow']
            }], onNavigationChange: [{
                type: HostListener,
                args: ['onMonthChange']
            }, {
                type: HostListener,
                args: ['onYearChange']
            }] } });

/**
 * Diretiva para melhorar a acessibilidade dos botões do paginador PrimeNG
 * Adiciona tabindex="0" aos botões habilitados e tabindex="-1" aos desabilitados
 * Adiciona aria-labels traduzidos para os botões do paginador
 */
class PaginatorAccessibilityDirective {
    el = inject(ElementRef);
    renderer = inject(Renderer2);
    translateService = inject(TranslateService);
    observer = null;
    equalWebSpanMarker = 'data-equalweb-sr-only';
    isObserverPaused = false;
    observedPaginatorElement = null;
    ngOnInit() {
        // Aguarda o próximo ciclo para garantir que o paginador foi renderizado
        setTimeout(() => {
            this.updatePaginatorButtons();
            this.observePaginatorChanges();
        });
    }
    ngOnDestroy() {
        if (this.observer) {
            this.observer.disconnect();
        }
    }
    updatePaginatorButtons() {
        const paginatorElement = this.el.nativeElement.querySelector('p-paginator');
        if (!paginatorElement) {
            return;
        }
        // Atualiza botões de navegação (first, prev, next, last)
        const navigationSelectors = {
            '.p-paginator-first': this.translateService.instant('platform.angular_components.aria_first_page'),
            '.p-paginator-prev': this.translateService.instant('platform.angular_components.aria_previous_page'),
            '.p-paginator-next': this.translateService.instant('platform.angular_components.aria_next_page'),
            '.p-paginator-last': this.translateService.instant('platform.angular_components.aria_last_page'),
            '.p-select-label': this.translateService.instant('platform.angular_components.aria_page_selection')
        };
        Object.entries(navigationSelectors).forEach(([selector, label]) => {
            const button = paginatorElement.querySelector(selector);
            if (button) {
                const isDisabled = this.isButtonDisabled(button);
                this.updateTabIndex(button, isDisabled);
                if (isDisabled) {
                    this.renderer.removeAttribute(button, 'data-ind-readable');
                }
                else {
                    this.renderer.setAttribute(button, 'data-ind-readable', 'true');
                }
                this.renderer.setAttribute(button, 'aria-label', label);
                this.applyEqualWebTextFix(button, label, isDisabled);
            }
        });
        // Atualiza botões de página numérica
        const pageButtons = paginatorElement.querySelectorAll('.p-paginator-page');
        pageButtons.forEach((button) => {
            const pageNumber = this.getPaginatorPageNumber(button);
            if (pageNumber) {
                const isDisabled = this.isButtonDisabled(button);
                const isSelected = button.classList.contains('p-paginator-page-selected');
                const ariaLabel = isSelected
                    ? this.translateService.instant('platform.angular_components.aria_current_page', { page: pageNumber })
                    : this.translateService.instant('platform.angular_components.aria_page_number', { page: pageNumber });
                this.renderer.setAttribute(button, 'aria-label', ariaLabel);
                this.updateTabIndex(button, isDisabled);
                this.applyEqualWebTextFix(button, ariaLabel, isDisabled);
                if (isSelected) {
                    this.renderer.setAttribute(button, 'aria-current', 'page');
                }
                else {
                    this.renderer.removeAttribute(button, 'aria-current');
                }
            }
        });
    }
    isButtonDisabled(button) {
        return button.hasAttribute('disabled') || button.classList.contains('p-disabled');
    }
    updateTabIndex(button, isDisabled) {
        if (isDisabled) {
            this.renderer.removeAttribute(button, 'tabindex');
            return;
        }
        this.renderer.setAttribute(button, 'tabindex', '0');
    }
    getPaginatorPageNumber(button) {
        const buttonElement = button;
        // Evita pegar texto do span sr-only criado pela diretiva.
        const visualLabel = buttonElement.querySelector(`span:not([${this.equalWebSpanMarker}])`);
        const visualText = visualLabel?.textContent?.trim();
        if (visualText) {
            return visualText;
        }
        // Fallback para casos em que o PrimeNG renderiza sem span interno.
        const srOnlyText = buttonElement.querySelector(`span[${this.equalWebSpanMarker}="true"]`)?.textContent?.trim() || '';
        const fullText = buttonElement.textContent?.trim() || '';
        return fullText.replace(srOnlyText, '').trim();
    }
    applyEqualWebTextFix(button, accessibleText, isDisabled) {
        const buttonElement = button;
        // Oculta spans visuais do PrimeNG para o script do EqualWeb.
        const visualSpans = buttonElement.querySelectorAll(`span:not([${this.equalWebSpanMarker}])`);
        visualSpans.forEach((span) => {
            this.renderer.setAttribute(span, 'aria-hidden', 'true');
        });
        const existingSrOnly = buttonElement.querySelector(`span[${this.equalWebSpanMarker}="true"]`);
        // Não mantém texto extra em botões desabilitados.
        if (isDisabled) {
            if (existingSrOnly) {
                this.renderer.removeChild(buttonElement, existingSrOnly);
            }
            return;
        }
        if (existingSrOnly) {
            this.renderer.removeAttribute(existingSrOnly, 'tabindex');
            this.renderer.setProperty(existingSrOnly, 'textContent', accessibleText);
            return;
        }
        const srOnlySpan = this.renderer.createElement('span');
        this.renderer.addClass(srOnlySpan, 'sr-only');
        this.renderer.setAttribute(srOnlySpan, this.equalWebSpanMarker, 'true');
        this.renderer.removeAttribute(srOnlySpan, 'tabindex');
        const srOnlyText = this.renderer.createText(accessibleText);
        this.renderer.appendChild(srOnlySpan, srOnlyText);
        this.renderer.appendChild(buttonElement, srOnlySpan);
    }
    observePaginatorChanges() {
        const paginatorElement = this.el.nativeElement.querySelector('p-paginator');
        if (!paginatorElement) {
            return;
        }
        this.observedPaginatorElement = paginatorElement;
        // Observa mudanças no paginador (quando botões são habilitados/desabilitados)
        this.observer = new MutationObserver(() => {
            this.updateWithObserverPaused();
        });
        this.startObserving();
    }
    updateWithObserverPaused() {
        if (!this.observer || this.isObserverPaused) {
            return;
        }
        this.isObserverPaused = true;
        this.observer.disconnect();
        try {
            this.updatePaginatorButtons();
        }
        finally {
            this.startObserving();
            this.isObserverPaused = false;
        }
    }
    startObserving() {
        if (!this.observer || !this.observedPaginatorElement) {
            return;
        }
        this.observer.observe(this.observedPaginatorElement, {
            attributes: true,
            childList: true,
            subtree: true,
            attributeFilter: ['disabled', 'class', 'tabindex']
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginatorAccessibilityDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: PaginatorAccessibilityDirective, isStandalone: true, selector: "[sPaginatorAccessibility]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginatorAccessibilityDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[sPaginatorAccessibility]',
                    standalone: true
                }]
        }] });

/**
 * Diretiva para corrigir a acessibilidade de checkboxes em tabelas PrimeNG.
 *
 * Propaga o `aria-label` dos custom elements wrapper (`p-tablecheckbox` e
 * `p-tableheadercheckbox`) para os `<input type="checkbox">` internos e
 * remove o atributo do wrapper, eliminando as violações WCAG 4.1.2:
 * - `label` (crítica): input sem nome acessível
 * - `aria-prohibited-attr` (séria): aria-label em custom element sem role ARIA
 *
 * Remove também o `aria-label` do `p-checkbox` intermediário e monitora
 * mutations de atributo para re-aplicar o label correto caso o binding
 * interno do PrimeNG sobrescreva o valor no input via change detection.
 *
 * Utiliza MutationObserver para tratar linhas adicionadas dinamicamente
 * (paginação, lazy loading).
 *
 * Uso: `<p-table sTableCheckboxAccessibility ...>`
 */
class TableCheckboxAccessibilityDirective {
    el = inject(ElementRef);
    childListObserver = null;
    attributeObserver = null;
    isChildListPaused = false;
    isAttributePaused = false;
    observedElements = [];
    inputLabelMap = new Map();
    static CHECKBOX_SELECTOR = 'p-tablecheckbox, p-tableheadercheckbox';
    static INNER_CHECKBOX_SELECTOR = 'p-checkbox';
    static INPUT_SELECTOR = 'input[type="checkbox"]';
    static ARIA_LABEL_ATTR = 'aria-label';
    ngOnInit() {
        setTimeout(() => {
            this.updateCheckboxLabels();
            this.observeTableChanges();
        });
    }
    ngOnDestroy() {
        this.childListObserver?.disconnect();
        this.attributeObserver?.disconnect();
        this.inputLabelMap.clear();
    }
    updateCheckboxLabels() {
        const host = this.el.nativeElement;
        const checkboxWrappers = host.querySelectorAll(TableCheckboxAccessibilityDirective.CHECKBOX_SELECTOR);
        checkboxWrappers.forEach((wrapper) => {
            const wrapperAriaLabel = wrapper.getAttribute(TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR);
            if (!wrapperAriaLabel?.trim()) {
                return;
            }
            const input = wrapper.querySelector(TableCheckboxAccessibilityDirective.INPUT_SELECTOR);
            if (!input) {
                return;
            }
            this.applyLabelToInput(input, wrapperAriaLabel);
            wrapper.removeAttribute(TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR);
            this.removeInnerCheckboxAriaLabel(wrapper);
        });
    }
    applyLabelToInput(input, label) {
        this.inputLabelMap.set(input, label);
        input.setAttribute(TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR, label);
    }
    removeInnerCheckboxAriaLabel(wrapper) {
        const innerCheckbox = wrapper.querySelector(TableCheckboxAccessibilityDirective.INNER_CHECKBOX_SELECTOR);
        if (innerCheckbox) {
            innerCheckbox.removeAttribute(TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR);
        }
    }
    observeTableChanges() {
        const host = this.el.nativeElement;
        const tbody = host.querySelector('tbody');
        const thead = host.querySelector('thead');
        if (tbody) {
            this.observedElements.push(tbody);
        }
        if (thead) {
            this.observedElements.push(thead);
        }
        if (this.observedElements.length === 0) {
            return;
        }
        this.childListObserver = new MutationObserver(() => {
            this.handleChildListMutation();
        });
        this.attributeObserver = new MutationObserver((mutations) => {
            this.handleAttributeMutations(mutations);
        });
        this.startObserving();
    }
    handleAttributeMutations(mutations) {
        if (this.isAttributePaused) {
            return;
        }
        this.isAttributePaused = true;
        try {
            mutations
                .filter((m) => m.attributeName === TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR)
                .forEach((mutation) => {
                const target = mutation.target;
                const tagName = target.tagName?.toLowerCase();
                if (tagName === 'p-checkbox') {
                    target.removeAttribute(TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR);
                }
                else if (tagName === 'input') {
                    this.enforceInputLabel(target);
                }
                else {
                    // Outros elementos não precisam de tratamento
                }
            });
        }
        finally {
            this.isAttributePaused = false;
        }
    }
    enforceInputLabel(input) {
        const correctLabel = this.inputLabelMap.get(input);
        if (!correctLabel) {
            return;
        }
        const currentLabel = input.getAttribute(TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR);
        if (currentLabel !== correctLabel) {
            input.setAttribute(TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR, correctLabel);
        }
    }
    handleChildListMutation() {
        if (!this.childListObserver || this.isChildListPaused) {
            return;
        }
        this.isChildListPaused = true;
        this.childListObserver.disconnect();
        try {
            this.updateCheckboxLabels();
        }
        finally {
            this.startObserving();
            this.isChildListPaused = false;
        }
    }
    startObserving() {
        const { childListObserver, attributeObserver, observedElements } = this;
        if (!childListObserver) {
            return;
        }
        observedElements.forEach((element) => {
            childListObserver.observe(element, {
                childList: true,
                subtree: true,
            });
            if (attributeObserver) {
                attributeObserver.observe(element, {
                    attributes: true,
                    subtree: true,
                    attributeFilter: [TableCheckboxAccessibilityDirective.ARIA_LABEL_ATTR],
                });
            }
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TableCheckboxAccessibilityDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: TableCheckboxAccessibilityDirective, isStandalone: true, selector: "[sTableCheckboxAccessibility]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TableCheckboxAccessibilityDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[sTableCheckboxAccessibility]',
                    standalone: true,
                }]
        }] });

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

export { BorderButtonComponent, BorderButtonModule, CheckDisabled, DatepickerNoPeriodTabDirective, EnumSeverity, PaginatorAccessibilityDirective, TableCheckboxAccessibilityDirective };
//# sourceMappingURL=seniorsistemas-angular-components-shared.mjs.map
