import * as i3 from '@angular/cdk/overlay';
import { OverlayModule } from '@angular/cdk/overlay';
import * as i4 from '@angular/cdk/scrolling';
import { ScrollingModule } from '@angular/cdk/scrolling';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { input, output, Component, model, signal, viewChild, inject, DestroyRef, computed, forwardRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import * as i2 from '@angular/forms';
import { NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
import * as i5 from '@ngx-translate/core';
import { TranslateModule } from '@ngx-translate/core';
import { Subject, Observable } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap, filter } from 'rxjs/operators';

class AutocompleteChipComponent {
    suggestion = input.required();
    suggestionLabel = input();
    suggestionRemoved = output();
    removeSuggestion() {
        this.suggestionRemoved.emit(this.suggestion());
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AutocompleteChipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.14", type: AutocompleteChipComponent, isStandalone: true, selector: "s-autocomplete-chip", inputs: { suggestion: { classPropertyName: "suggestion", publicName: "suggestion", isSignal: true, isRequired: true, transformFunction: null }, suggestionLabel: { classPropertyName: "suggestionLabel", publicName: "suggestionLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { suggestionRemoved: "suggestionRemoved" }, ngImport: i0, template: "<div class=\"flex items-center gap-2 rounded-[4px] border border-grayscale-50 bg-grayscale-10 px-2\">\n    <span class=\"text-nowrap\">{{ suggestionLabel() ? suggestion()[suggestionLabel()!] : suggestion() }}</span>\n    <button (click)=\"removeSuggestion()\">\n        <i class=\"far fa-times\"></i>\n    </button>\n</div>\n" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AutocompleteChipComponent, decorators: [{
            type: Component,
            args: [{ selector: 's-autocomplete-chip', standalone: true, template: "<div class=\"flex items-center gap-2 rounded-[4px] border border-grayscale-50 bg-grayscale-10 px-2\">\n    <span class=\"text-nowrap\">{{ suggestionLabel() ? suggestion()[suggestionLabel()!] : suggestion() }}</span>\n    <button (click)=\"removeSuggestion()\">\n        <i class=\"far fa-times\"></i>\n    </button>\n</div>\n" }]
        }] });

class AutocompleteComponent {
    static nextId = 0;
    suggestions = input([]);
    placeholder = input();
    suggestionValue = input();
    suggestionLabel = input();
    readonly = input(false);
    emptyMessage = input();
    delay = input(300);
    invalid = input(false);
    virtualScroll = input(false);
    virtualScrollItemSize = input(37);
    lazy = input(false);
    dropdown = input(false);
    forceSelection = input(false);
    checkmark = input(false);
    multiple = input(false);
    minLengthToSearch = input(1);
    inputClass = input('');
    dataKey = input();
    value = model();
    values = model([]);
    disabled = model(false);
    lazyLoad = output();
    selected = output();
    unselected = output();
    blurred = output();
    cleared = output();
    keyUp = output();
    focused = output();
    completeMethod = output();
    focusedIndex = signal(-1);
    isOpen = signal(false);
    filteredSuggestions = signal([]);
    showEmptyMessage = signal(false);
    filterText = signal('');
    inputValue = signal('');
    loading = signal(false);
    componentId = `autocomplete_${AutocompleteComponent.nextId++}`;
    inputEl = viewChild('inputEl');
    _inputSubject$ = new Subject();
    _lazyLoadSubject$ = new Subject();
    _destroyRef = inject(DestroyRef);
    _onChange;
    _onTouched;
    /**
     * Computed que retorna uma lista de sugestões do tipo `SuggestionWrapper<T>`,
     * adicionando um identificador único a cada sugestão.
     * @returns Uma lista de sugestões processadas com identificadores únicos.
     */
    internalSuggestion = computed(() => {
        const opts = this.suggestions();
        return this._addIdToSuggestions(opts);
    });
    /**
     * Retorna um conjunto (`Set`) com os IDs das sugestões selecionadas.
     */
    selectedSuggestionIds = computed(() => {
        if (!this.multiple()) {
            return new Set();
        }
        const currentValues = this.values();
        return new Set(currentValues.map((value) => {
            return this.internalSuggestion().find((s) => JSON.stringify(s.data) === JSON.stringify(value))?.id;
        }));
    });
    /**
     * Retorna uma lista de sugestões filtradas, enriquecidas com a propriedade `isSelected`.
     * Cada sugestão recebe um campo booleano `isSelected` indicando se ela está selecionada,
     * com base nos IDs das sugestões selecionadas e no valor da sugestão.
     * @returns Uma lista de sugestões filtradas, cada uma com a propriedade adicional `isSelected`.
     */
    enrichedFilteredSuggestions = computed(() => {
        const filtered = this.filteredSuggestions();
        const selectedIds = this.selectedSuggestionIds();
        return filtered.map((suggestion) => ({
            ...suggestion,
            isSelected: selectedIds.has(suggestion.id),
        }));
    });
    constructor() {
        this._validateInputs();
        this._setupInputDebounce();
        this._setupLazyLoadDebounce();
    }
    /**
     * Define o valor do autocomplete.
     * @param value Valor a ser definido, único ou array, conforme seleção múltipla.
     * @throws Se múltiplo for falso e value for array.
     */
    writeValue(value) {
        const suggestionLabel = this.suggestionLabel();
        if (value && this.multiple()) {
            if (Array.isArray(value)) {
                this.values.set(value);
            }
            else {
                this.values.set([value]);
            }
        }
        else {
            if (Array.isArray(value)) {
                throw new Error('The value must not be an array when multiple is false.');
            }
            else {
                this.value.set(value);
            }
            this.inputValue.set(!value ? '' : suggestionLabel ? String(value[suggestionLabel]) : String(value));
        }
    }
    /**
     * Registra uma função de callback que será chamada sempre que o valor do componente mudar.
     * @param onChange Função a ser chamada quando o valor mudar. Recebe o novo valor como argumento, que pode ser um único valor ou um array de valores.
     */
    registerOnChange(onChange) {
        this._onChange = onChange;
    }
    /**
     * Registra uma função de callback que será chamada quando o componente for tocado (perder o foco).
     * @param onTouched Função de callback a ser chamada quando o componente for tocado.
     */
    registerOnTouched(onTouched) {
        this._onTouched = onTouched;
    }
    /**
     * Define o estado de desabilitado do componente.
     * @param disabled Indica se o componente deve ser desabilitado (`true`) ou habilitado (`false`).
     */
    setDisabledState(disabled) {
        this.disabled.set(disabled);
    }
    /**
     * Manipula o evento de entrada do usuário no campo de texto do autocomplete.
     * Este método é chamado sempre que o usuário digita algo no campo de entrada.
     * Ele executa as seguintes ações:
     * - Dispara o callback de "touched" para controle de formulários.
     * - Obtém o valor atual do campo de entrada.
     * - Se o modo lazy estiver ativado, emite o evento de lazyLoad com a consulta e abre o painel de sugestões.
     * - Caso contrário, atualiza o texto de filtro, notifica os observadores e abre o painel de sugestões se houver sugestões disponíveis.
     * @param event Evento de entrada do tipo `Event` proveniente do campo de texto.
     */
    onInput(event) {
        this._onTouched?.();
        const value = event.target.value;
        if (this.lazy()) {
            this._lazyLoadSubject$.next(value);
            this.isOpen.set(true);
            return;
        }
        this.filterText.set(value);
        this.completeMethod.emit({ query: value });
        this._inputSubject$.next(value);
        if (this.suggestions()) {
            this.isOpen.set(true);
        }
    }
    /**
     * Manipula o evento de perda de foco (blur) do campo de entrada do autocomplete.
     * Este método verifica se o valor digitado pelo usuário corresponde exatamente a algum dos itens sugeridos.
     * - Se houver correspondência:
     *   - No modo múltiplo (`multiple`), adiciona o item selecionado à lista de valores, caso ainda não esteja presente.
     *   - No modo simples, seleciona o item correspondente se ainda não estiver selecionado.
     * - Se não houver correspondência, limpa o campo de entrada.
     */
    onInputBlur(event) {
        const inputValue = String(this.inputValue()).toLowerCase();
        const suggestions = this.internalSuggestion();
        const match = suggestions.find(({ data }) => {
            const label = this.suggestionLabel() ? data[this.suggestionLabel()] : data;
            return String(label).toLowerCase() === inputValue;
        });
        if (match) {
            if (this.multiple()) {
                const currentValues = this.values();
                const exists = currentValues.some((value) => (this.suggestionValue() ? value[this.suggestionValue()] : value) ===
                    (this.suggestionValue() ? match.data[this.suggestionValue()] : match.data));
                if (!exists) {
                    this.values.set([...currentValues, match.data]);
                    this._onChange?.(this.values());
                }
                this.inputValue.set('');
            }
            else {
                if (this.value() !== match.data) {
                    this.selectSuggestion(match.data);
                }
            }
        }
        else {
            this.inputValue.set('');
        }
    }
    /**
     * Dispara o evento de foco quando o campo de entrada recebe foco.
     * @param event O evento de foco disparado pelo elemento de entrada.
     */
    onInputFocus(event) {
        this.focused.emit(event);
    }
    /**
     * Manipula eventos de teclado no componente de autocomplete.
     * Este método gerencia a navegação e seleção de sugestões usando as teclas do teclado.
     * - 'ArrowDown': Move o foco para a próxima sugestão.
     * - 'ArrowUp': Move o foco para a sugestão anterior.
     * - 'Enter' ou 'Tab': Seleciona a sugestão atualmente focada e fecha a lista de sugestões.
     * - 'Escape': Fecha a lista de sugestões sem selecionar nenhum item.
     * @param event O evento de teclado disparado pelo usuário.
     */
    onKeyDown(event) {
        const suggestions = this.filteredSuggestions();
        this._onTouched?.();
        const _selectSuggestion = () => {
            if (this.focusedIndex() >= 0 && this.focusedIndex() < suggestions.length) {
                event.preventDefault();
                this.selectSuggestion(suggestions[this.focusedIndex()].data);
            }
        };
        switch (event.key) {
            case 'ArrowDown':
                event.preventDefault();
                this._focusNextSuggestion(suggestions);
                break;
            case 'ArrowUp':
                event.preventDefault();
                this._focusPreviousSuggestion();
                break;
            case 'Enter':
            case 'Tab':
                _selectSuggestion();
                this.isOpen.set(false);
                break;
            case 'Escape':
                this.isOpen.set(false);
                break;
        }
    }
    /**
     * Emite um evento quando uma tecla é liberada no componente.     *
     * @param event O evento de teclado associado à tecla liberada.
     */
    onKeyUp(event) {
        this.keyUp.emit(event);
    }
    /**
     * Fecha o dropdown em eventos de redimensionamento de janela.
     */
    onWindowResize() {
        if (this.isOpen()) {
            this.isOpen.set(false);
        }
    }
    /**
     * Seleciona uma sugestão da lista de sugestões.
     * Se o modo múltiplo estiver ativado (`multiple()` retorna true), adiciona a sugestão à lista de suggestões selecionadas,
     * caso ela ainda não esteja presente. Em seguida, limpa o valor do campo de entrada.
     * Se o modo múltiplo não estiver ativado, define a sugestão como valor selecionado e atualiza o campo de entrada
     * com o rótulo correspondente.
     * Em ambos os casos, dispara o callback `_onChange` com o novo valor e fecha o painel de sugestões.
     * @param suggestion - A sugestão a ser selecionada.
     */
    selectSuggestion(suggestion) {
        if (this.multiple()) {
            const currentValues = this.values();
            const exists = currentValues.some((value) => (this.suggestionValue() ? value[this.suggestionValue()] : value) ===
                (this.suggestionValue() ? suggestion[this.suggestionValue()] : suggestion));
            if (!exists) {
                this.values.set([...currentValues, suggestion]);
                this._onChange?.(this.values());
            }
            this.inputValue.set('');
        }
        else {
            this.value.set(suggestion);
            const _value = this.suggestionValue() ? suggestion[this.suggestionValue()] : suggestion;
            const _inputValue = String(this.suggestionLabel() ? suggestion[this.suggestionLabel()] : suggestion);
            this.inputValue.set(_inputValue);
            this._onChange?.(_value);
        }
        this.selected.emit(suggestion);
        this.isOpen.set(false);
    }
    /**
     * Limpa o valor selecionado no componente de autocomplete.
     * Se o modo múltiplo estiver ativado, remove todos os valores selecionados.
     * Caso contrário, define o valor como nulo.
     * Também limpa as sugestões filtradas, fecha o painel de sugestões
     * e limpa o valor do campo de entrada.
     */
    clear() {
        if (this.multiple()) {
            this.values.set([]);
            this._onChange?.(this.values());
        }
        else {
            this.value.set(null);
            this._onChange?.(this.value());
        }
        this.filteredSuggestions.set([]);
        this.isOpen.set(false);
        this.inputValue.set('');
        this.cleared.emit();
    }
    /**
     * Alterna a exibição do dropdown de sugestões do autocomplete.
     * Este método configura o debounce do input, verifica se há sugestões filtradas
     * e, caso não haja sugestões e o texto do filtro esteja vazio, redefine as sugestões filtradas.
     * Por fim, alterna o estado de abertura do dropdown.
     */
    toggleDropdown() {
        this._setupInputDebounce();
        if (this.filterText() === '') {
            if (this.lazy()) {
                this._lazyLoadSubject$.next('');
            }
            else {
                this.resetFilteredSuggestions();
            }
        }
        this.isOpen.set(!this.isOpen());
    }
    /**
     * Função utilizada para otimizar a renderização de listas no Angular, permitindo que o framework
     * identifique cada item de forma única pelo seu `id`. Deve ser utilizada como função de `trackBy`
     * em diretivas como `*ngFor`.
     * @param _ - Índice do item na lista (não utilizado).
     * @param item - Objeto do tipo `SuggestionWrapper<T>` que representa o item atual.
     * @returns O identificador único (`id`) do item.
     */
    trackById(_, item) {
        return item.id;
    }
    /**
     * Remove uma sugestão da lista de valores selecionados.
     * @param suggestion O item a ser removido da lista de sugestões.
     */
    removeSuggestion(suggestion) {
        const suggestionValue = this.suggestionValue();
        this.values.set(this.values().filter((value) => {
            if (suggestionValue) {
                return value[suggestionValue] !== suggestion[suggestionValue];
            }
            return value !== suggestion;
        }));
        this._onChange?.(this.values());
        this.unselected.emit(suggestion);
    }
    /**
     * Reinicia a lista de sugestões filtradas.
     * Se o modo lazy estiver ativado, emite um evento para carregar sugestões com uma consulta vazia.
     * Em seguida, redefine as sugestões filtradas para o valor retornado por `internalSuggestion()`.
     * @private
     */
    resetFilteredSuggestions() {
        if (this.lazy()) {
            this._lazyLoadSubject$.next('');
        }
        else {
            this.filteredSuggestions.set(this.internalSuggestion());
        }
    }
    /**
     * Move o foco para a próxima sugestão na lista de sugestões, se houver.
     * @private
     * @param suggestions Lista de sugestões disponíveis.
     */
    _focusNextSuggestion(suggestions) {
        let nextIndex = this.focusedIndex() + 1;
        if (nextIndex < suggestions.length) {
            this.focusedIndex.set(nextIndex);
            this._scrollToFocusedSuggestion();
        }
    }
    /**
     * Move o foco para a sugestão anterior na lista de sugestões, se houver.
     * @private
     */
    _focusPreviousSuggestion() {
        let prevIndex = this.focusedIndex() - 1;
        if (prevIndex >= 0) {
            this.focusedIndex.set(prevIndex);
            this._scrollToFocusedSuggestion();
        }
    }
    /**
     * Rola a lista de sugestões para garantir que a sugestão atualmente focada esteja visível.
     * @private
     */
    _scrollToFocusedSuggestion() {
        const id = this.filteredSuggestions()[this.focusedIndex()]?.id;
        if (!id) {
            return;
        }
        const el = document.getElementById(id);
        el?.scrollIntoView({ block: 'nearest' });
    }
    /**
     * Adiciona um identificador único a cada sugestão fornecida.
     * @private
     * @param suggestions - Um array de sugestões do tipo T.
     * @returns Um array de objetos `SuggestionWrapper<T>`, cada um contendo a sugestão original e um identificador único.
     */
    _addIdToSuggestions(suggestions) {
        return (suggestions?.map((suggestion) => {
            return {
                data: suggestion,
                id: this.dataKey()
                    ? String(suggestion[this.dataKey()])
                    : ((typeof suggestion !== 'object'
                        ? suggestion?.toString()
                        : Object.values(suggestion).join('_')) ?? ''),
            };
        }) ?? []);
    }
    /**
     * Configura o debounce e switchMap para lazy loading, resolvendo race conditions.
     * Este método utiliza switchMap para cancelar requisições anteriores automaticamente
     * quando uma nova busca é iniciada, evitando que resultados antigos sobrescrevam
     * resultados mais recentes.
     * @private
     */
    _setupLazyLoadDebounce() {
        this._lazyLoadSubject$
            .pipe(debounceTime(this.delay()), distinctUntilChanged(), switchMap((query) => {
            this.loading.set(true);
            // TODO: Manter fechado o dropdownd até a busca estiver concluída
            return new Observable((subscriber) => {
                const timeoutId = setTimeout(() => {
                    if (!subscriber.closed) {
                        subscriber.error(new Error('Lazy load timeout'));
                    }
                }, 30000);
                const responseCallback = (data) => {
                    clearTimeout(timeoutId);
                    if (!subscriber.closed) {
                        subscriber.next(data);
                        subscriber.complete();
                    }
                };
                this.lazyLoad.emit({ query, response: responseCallback });
            });
        }), takeUntilDestroyed(this._destroyRef))
            .subscribe({
            next: (data) => {
                this.loading.set(false);
                // TODO: Abrir o dropdown somente aqui
                const wrappedSuggestions = this._addIdToSuggestions(data);
                this.filteredSuggestions.set(wrappedSuggestions);
                this.showEmptyMessage.set(wrappedSuggestions.length === 0);
            },
            error: (error) => {
                this.loading.set(false);
                // TODO: Abrir o dropdown somente aqui
                console.error('Lazy load error:', error);
                this.filteredSuggestions.set([]);
                this.showEmptyMessage.set(true);
            },
        });
    }
    /**
     * Configura o debounce para o input do autocomplete.
     * Este método utiliza um Subject para escutar as mudanças no valor do input,
     * aplicando um debounce com o tempo definido por `this.delay()`. Quando um novo valor é emitido:
     * - Se houver valor, filtra as sugestões com base no texto digitado e atualiza a lista de sugestões filtradas.
     * - Se não houver valor e o dropdown estiver ativo, reseta as sugestões filtradas.
     * - Caso contrário, limpa a lista de sugestões filtradas.
     * Também atualiza o estado da mensagem de lista vazia e, se a seleção for livre (`forceSelection` for falso),
     * propaga a mudança de valor para o formulário.
     * @private
     */
    _setupInputDebounce() {
        this._inputSubject$
            .pipe(debounceTime(this.delay()), distinctUntilChanged(), filter((value) => value.length >= this.minLengthToSearch() || value.length === 0), takeUntilDestroyed(this._destroyRef))
            .subscribe((value) => {
            if (value) {
                this.filteredSuggestions.set(this.internalSuggestion().filter(({ data }) => {
                    const label = String(this.suggestionLabel() ? data[this.suggestionLabel()] : data);
                    return label.toLowerCase().includes(value.toLowerCase());
                }));
                this.showEmptyMessage.set(this.filteredSuggestions().length === 0);
            }
            else if (this.dropdown()) {
                this.resetFilteredSuggestions();
            }
            else {
                this.filteredSuggestions.set([]);
            }
            if (!this.forceSelection()) {
                this._onChange?.(value);
            }
        });
    }
    /**
     * Valida as entradas do componente de autocomplete.
     * @private
     * @throws {Error} Se as sugestões forem objetos e `suggestionLabel` não for fornecido.
     */
    _validateInputs() {
        const suggestions = this.suggestions();
        if (!suggestions.length) {
            return;
        }
        const hasObjectSuggestions = suggestions.some((suggestion) => typeof suggestion === 'object' && suggestion !== null);
        if (hasObjectSuggestions) {
            if (!this.suggestionLabel()) {
                throw new Error('The suggestionLabel input must be provided when suggestions are objects.');
            }
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AutocompleteComponent, isStandalone: true, selector: "s-autocomplete", inputs: { suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, suggestionValue: { classPropertyName: "suggestionValue", publicName: "suggestionValue", isSignal: true, isRequired: false, transformFunction: null }, suggestionLabel: { classPropertyName: "suggestionLabel", publicName: "suggestionLabel", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollItemSize: { classPropertyName: "virtualScrollItemSize", publicName: "virtualScrollItemSize", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, dropdown: { classPropertyName: "dropdown", publicName: "dropdown", isSignal: true, isRequired: false, transformFunction: null }, forceSelection: { classPropertyName: "forceSelection", publicName: "forceSelection", isSignal: true, isRequired: false, transformFunction: null }, checkmark: { classPropertyName: "checkmark", publicName: "checkmark", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, minLengthToSearch: { classPropertyName: "minLengthToSearch", publicName: "minLengthToSearch", isSignal: true, isRequired: false, transformFunction: null }, inputClass: { classPropertyName: "inputClass", publicName: "inputClass", isSignal: true, isRequired: false, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", values: "valuesChange", disabled: "disabledChange", lazyLoad: "lazyLoad", selected: "selected", unselected: "unselected", blurred: "blurred", cleared: "cleared", keyUp: "keyUp", focused: "focused", completeMethod: "completeMethod" }, host: { attributes: { "role": "combobox" }, listeners: { "window:resize": "onWindowResize()" }, properties: { "attr.aria-expanded": "isOpen()", "attr.aria-haspopup": "\"listbox\"", "attr.aria-owns": "isOpen() ? \"dropdown-container-\" + componentId : null" } }, providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                useExisting: forwardRef(() => AutocompleteComponent),
                multi: true,
            },
        ], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n    #containerDiv\n    cdkOverlayOrigin\n    #trigger=\"cdkOverlayOrigin\"\n    class=\"flex h-[35px] w-full items-center overflow-hidden rounded-[4px] border focus-within:border-2 focus-within:border-primary hover:bg-grayscale-10\"\n    [class]=\"inputClass()\"\n    [ngClass]=\"{\n        'pointer-events-none border-grayscale-20 bg-grayscale-5 text-grayscale-30': disabled(),\n        'pointer-events-auto border-grayscale-30 bg-grayscale-0 text-grayscale-90': !disabled(),\n        'border-criticality-red': invalid(),\n    }\"\n>\n    <div\n        class=\"flex flex-grow gap-2 px-2\"\n        [ngClass]=\"{\n            'border-r': dropdown(),\n            'border-grayscale-20': dropdown() && disabled(),\n            'border-grayscale-30 focus-within:border-r-2 focus-within:border-r-primary': dropdown() && !disabled(),\n            'bg-grayscale-5': disabled(),\n            'bg-grayscale-0': !disabled(),\n        }\"\n    >\n        @if (multiple() && values().length > 0) {\n            <div class=\"flex flex-wrap items-center gap-2\">\n                @for (suggestion of values(); track suggestion) {\n                    <s-autocomplete-chip\n                        [suggestion]=\"suggestion\"\n                        [suggestionLabel]=\"suggestionLabel()\"\n                        (suggestionRemoved)=\"removeSuggestion($event)\"\n                    ></s-autocomplete-chip>\n                }\n            </div>\n        }\n        <input\n            #inputEl\n            class=\"min-h-[35px] grow outline-none\"\n            type=\"text\"\n            [placeholder]=\"placeholder() ?? 'platform.angular_components.type_to_search' | translate\"\n            [readOnly]=\"readonly()\"\n            [(ngModel)]=\"inputValue\"\n            [attr.aria-disabled]=\"disabled()\"\n            [attr.aria-autocomplete]=\"multiple() ? 'list' : 'both'\"\n            [attr.aria-activedescendant]=\"focusedIndex() >= 0 ? filteredSuggestions()[focusedIndex()].id : null\"\n            role=\"searchbox\"\n            (input)=\"onInput($event)\"\n            (keydown)=\"onKeyDown($event)\"\n            (keyUp)=\"onKeyUp($event)\"\n            (blur)=\"onInputBlur($event)\"\n            (focus)=\"onInputFocus($event)\"\n        />\n\n        @if (loading()) {\n            <div class=\"flex items-center justify-center\">\n                <svg\n                    width=\"20\"\n                    height=\"20\"\n                    viewBox=\"0 0 20 20\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    class=\"animate-spin\"\n                >\n                    <circle\n                        cx=\"10\"\n                        cy=\"10\"\n                        r=\"9\"\n                        stroke=\"#428bca\"\n                        stroke-width=\"2\"\n                        fill=\"none\"\n                        stroke-dasharray=\"56.5\"\n                        stroke-dashoffset=\"10\"\n                        stroke-linecap=\"round\"\n                    />\n                </svg>\n            </div>\n        } @else {\n            @if (value() && !this.disabled()) {\n                <button\n                    class=\"px-2\"\n                    (click)=\"clear()\"\n                    tabindex=\"-1\"\n                >\n                    <i class=\"far fa-times text-grayscale-60\"></i>\n                </button>\n            }\n        }\n    </div>\n\n    @if (dropdown()) {\n        <button\n            class=\"flex h-full w-[35px] flex-shrink-0 flex-grow-0 items-center justify-center hover:bg-grayscale-10\"\n            (click)=\"toggleDropdown()\"\n        >\n            <i\n                class=\"fas text-grayscale-90\"\n                [class.fa-caret-down]=\"!isOpen()\"\n                [class.fa-caret-up]=\"isOpen()\"\n            ></i>\n        </button>\n    }\n</div>\n\n@if (showEmptyMessage() || (filteredSuggestions().length > 0 && !readonly())) {\n    <ng-template\n        #dropdownTemplate\n        cdkConnectedOverlay\n        [cdkConnectedOverlayOrigin]=\"trigger\"\n        [cdkConnectedOverlayOpen]=\"isOpen()\"\n        [cdkConnectedOverlayHasBackdrop]=\"true\"\n        (backdropClick)=\"isOpen.set(false)\"\n        cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n        (detach)=\"isOpen.set(false)\"\n    >\n        <div\n            [id]=\"'dropdown-container-' + componentId\"\n            class=\"mt-0.5 rounded-[4px] bg-grayscale-0 py-1 shadow\"\n            [style.width.px]=\"containerDiv.offsetWidth\"\n        >\n            <ul\n                class=\"max-h-52 overflow-auto\"\n                role=\"listbox\"\n            >\n                <!-- Virtual scroll -->\n                @if (virtualScroll() && filteredSuggestions().length > 10) {\n                    <cdk-virtual-scroll-viewport\n                        [itemSize]=\"virtualScrollItemSize()\"\n                        class=\"h-52 overflow-auto\"\n                    >\n                        <ng-container\n                            *cdkVirtualFor=\"\n                                let suggestion of enrichedFilteredSuggestions();\n                                let i = $index;\n                                trackBy: trackById\n                            \"\n                        >\n                            <ng-container\n                                [ngTemplateOutlet]=\"suggestionItemTemplate\"\n                                [ngTemplateOutletContext]=\"{ suggestion, i }\"\n                            ></ng-container>\n                        </ng-container>\n                    </cdk-virtual-scroll-viewport>\n                }\n\n                <!-- Normal list -->\n                @if (!virtualScroll() || filteredSuggestions().length <= 10) {\n                    @for (suggestion of enrichedFilteredSuggestions(); track suggestion.id; let i = $index) {\n                        <ng-container\n                            [ngTemplateOutlet]=\"suggestionItemTemplate\"\n                            [ngTemplateOutletContext]=\"{ suggestion, i }\"\n                        ></ng-container>\n                    }\n                }\n\n                @if (showEmptyMessage()) {\n                    <span class=\"p-3 text-grayscale-60\">{{\n                        emptyMessage() ?? 'platform.angular_components.no_records_found' | translate\n                    }}</span>\n                }\n            </ul>\n        </div>\n    </ng-template>\n}\n\n<ng-template\n    #suggestionItemTemplate\n    let-suggestion=\"suggestion\"\n    let-i=\"i\"\n>\n    <li\n        [id]=\"suggestion.id\"\n        class=\"rounded-sm flex cursor-pointer items-center gap-2 px-3 py-2 text-grayscale-70\"\n        [class.bg-grayscale-10]=\"i === focusedIndex()\"\n        [class.bg-grayscale-20]=\"suggestion.isSelected\"\n        [attr.aria-selected]=\"suggestion.isSelected\"\n        role=\"option\"\n        (click)=\"selectSuggestion(suggestion.data)\"\n    >\n        @if (checkmark() && multiple() && suggestion.isSelected) {\n            <i class=\"far fa-check\"></i>\n        }\n        {{ suggestionLabel() ? suggestion.data[suggestionLabel()!] : suggestion.data }}\n    </li>\n</ng-template>\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: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: i4.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i4.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i4.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "component", type: AutocompleteChipComponent, selector: "s-autocomplete-chip", inputs: ["suggestion", "suggestionLabel"], outputs: ["suggestionRemoved"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AutocompleteComponent, decorators: [{
            type: Component,
            args: [{ selector: 's-autocomplete', standalone: true, imports: [
                        CommonModule,
                        FormsModule,
                        ReactiveFormsModule,
                        OverlayModule,
                        ScrollingModule,
                        TranslateModule,
                        AutocompleteChipComponent,
                    ], providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            useExisting: forwardRef(() => AutocompleteComponent),
                            multi: true,
                        },
                    ], host: {
                        role: 'combobox',
                        '[attr.aria-expanded]': 'isOpen()',
                        '[attr.aria-haspopup]': '"listbox"',
                        '[attr.aria-owns]': 'isOpen() ? "dropdown-container-" + componentId : null',
                        '(window:resize)': 'onWindowResize()',
                    }, template: "<div\n    #containerDiv\n    cdkOverlayOrigin\n    #trigger=\"cdkOverlayOrigin\"\n    class=\"flex h-[35px] w-full items-center overflow-hidden rounded-[4px] border focus-within:border-2 focus-within:border-primary hover:bg-grayscale-10\"\n    [class]=\"inputClass()\"\n    [ngClass]=\"{\n        'pointer-events-none border-grayscale-20 bg-grayscale-5 text-grayscale-30': disabled(),\n        'pointer-events-auto border-grayscale-30 bg-grayscale-0 text-grayscale-90': !disabled(),\n        'border-criticality-red': invalid(),\n    }\"\n>\n    <div\n        class=\"flex flex-grow gap-2 px-2\"\n        [ngClass]=\"{\n            'border-r': dropdown(),\n            'border-grayscale-20': dropdown() && disabled(),\n            'border-grayscale-30 focus-within:border-r-2 focus-within:border-r-primary': dropdown() && !disabled(),\n            'bg-grayscale-5': disabled(),\n            'bg-grayscale-0': !disabled(),\n        }\"\n    >\n        @if (multiple() && values().length > 0) {\n            <div class=\"flex flex-wrap items-center gap-2\">\n                @for (suggestion of values(); track suggestion) {\n                    <s-autocomplete-chip\n                        [suggestion]=\"suggestion\"\n                        [suggestionLabel]=\"suggestionLabel()\"\n                        (suggestionRemoved)=\"removeSuggestion($event)\"\n                    ></s-autocomplete-chip>\n                }\n            </div>\n        }\n        <input\n            #inputEl\n            class=\"min-h-[35px] grow outline-none\"\n            type=\"text\"\n            [placeholder]=\"placeholder() ?? 'platform.angular_components.type_to_search' | translate\"\n            [readOnly]=\"readonly()\"\n            [(ngModel)]=\"inputValue\"\n            [attr.aria-disabled]=\"disabled()\"\n            [attr.aria-autocomplete]=\"multiple() ? 'list' : 'both'\"\n            [attr.aria-activedescendant]=\"focusedIndex() >= 0 ? filteredSuggestions()[focusedIndex()].id : null\"\n            role=\"searchbox\"\n            (input)=\"onInput($event)\"\n            (keydown)=\"onKeyDown($event)\"\n            (keyUp)=\"onKeyUp($event)\"\n            (blur)=\"onInputBlur($event)\"\n            (focus)=\"onInputFocus($event)\"\n        />\n\n        @if (loading()) {\n            <div class=\"flex items-center justify-center\">\n                <svg\n                    width=\"20\"\n                    height=\"20\"\n                    viewBox=\"0 0 20 20\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    class=\"animate-spin\"\n                >\n                    <circle\n                        cx=\"10\"\n                        cy=\"10\"\n                        r=\"9\"\n                        stroke=\"#428bca\"\n                        stroke-width=\"2\"\n                        fill=\"none\"\n                        stroke-dasharray=\"56.5\"\n                        stroke-dashoffset=\"10\"\n                        stroke-linecap=\"round\"\n                    />\n                </svg>\n            </div>\n        } @else {\n            @if (value() && !this.disabled()) {\n                <button\n                    class=\"px-2\"\n                    (click)=\"clear()\"\n                    tabindex=\"-1\"\n                >\n                    <i class=\"far fa-times text-grayscale-60\"></i>\n                </button>\n            }\n        }\n    </div>\n\n    @if (dropdown()) {\n        <button\n            class=\"flex h-full w-[35px] flex-shrink-0 flex-grow-0 items-center justify-center hover:bg-grayscale-10\"\n            (click)=\"toggleDropdown()\"\n        >\n            <i\n                class=\"fas text-grayscale-90\"\n                [class.fa-caret-down]=\"!isOpen()\"\n                [class.fa-caret-up]=\"isOpen()\"\n            ></i>\n        </button>\n    }\n</div>\n\n@if (showEmptyMessage() || (filteredSuggestions().length > 0 && !readonly())) {\n    <ng-template\n        #dropdownTemplate\n        cdkConnectedOverlay\n        [cdkConnectedOverlayOrigin]=\"trigger\"\n        [cdkConnectedOverlayOpen]=\"isOpen()\"\n        [cdkConnectedOverlayHasBackdrop]=\"true\"\n        (backdropClick)=\"isOpen.set(false)\"\n        cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n        (detach)=\"isOpen.set(false)\"\n    >\n        <div\n            [id]=\"'dropdown-container-' + componentId\"\n            class=\"mt-0.5 rounded-[4px] bg-grayscale-0 py-1 shadow\"\n            [style.width.px]=\"containerDiv.offsetWidth\"\n        >\n            <ul\n                class=\"max-h-52 overflow-auto\"\n                role=\"listbox\"\n            >\n                <!-- Virtual scroll -->\n                @if (virtualScroll() && filteredSuggestions().length > 10) {\n                    <cdk-virtual-scroll-viewport\n                        [itemSize]=\"virtualScrollItemSize()\"\n                        class=\"h-52 overflow-auto\"\n                    >\n                        <ng-container\n                            *cdkVirtualFor=\"\n                                let suggestion of enrichedFilteredSuggestions();\n                                let i = $index;\n                                trackBy: trackById\n                            \"\n                        >\n                            <ng-container\n                                [ngTemplateOutlet]=\"suggestionItemTemplate\"\n                                [ngTemplateOutletContext]=\"{ suggestion, i }\"\n                            ></ng-container>\n                        </ng-container>\n                    </cdk-virtual-scroll-viewport>\n                }\n\n                <!-- Normal list -->\n                @if (!virtualScroll() || filteredSuggestions().length <= 10) {\n                    @for (suggestion of enrichedFilteredSuggestions(); track suggestion.id; let i = $index) {\n                        <ng-container\n                            [ngTemplateOutlet]=\"suggestionItemTemplate\"\n                            [ngTemplateOutletContext]=\"{ suggestion, i }\"\n                        ></ng-container>\n                    }\n                }\n\n                @if (showEmptyMessage()) {\n                    <span class=\"p-3 text-grayscale-60\">{{\n                        emptyMessage() ?? 'platform.angular_components.no_records_found' | translate\n                    }}</span>\n                }\n            </ul>\n        </div>\n    </ng-template>\n}\n\n<ng-template\n    #suggestionItemTemplate\n    let-suggestion=\"suggestion\"\n    let-i=\"i\"\n>\n    <li\n        [id]=\"suggestion.id\"\n        class=\"rounded-sm flex cursor-pointer items-center gap-2 px-3 py-2 text-grayscale-70\"\n        [class.bg-grayscale-10]=\"i === focusedIndex()\"\n        [class.bg-grayscale-20]=\"suggestion.isSelected\"\n        [attr.aria-selected]=\"suggestion.isSelected\"\n        role=\"option\"\n        (click)=\"selectSuggestion(suggestion.data)\"\n    >\n        @if (checkmark() && multiple() && suggestion.isSelected) {\n            <i class=\"far fa-check\"></i>\n        }\n        {{ suggestionLabel() ? suggestion.data[suggestionLabel()!] : suggestion.data }}\n    </li>\n</ng-template>\n" }]
        }], ctorParameters: () => [] });

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

export { AutocompleteComponent };
//# sourceMappingURL=seniorsistemas-angular-components-autocomplete.mjs.map
