/*!
 * Copyright 2020-2021 VMware, Inc.
 * SPDX-License-Identifier: BSD-2-Clause
 */
import { Component, ElementRef, EventEmitter, Input, Output, ViewChild, } from '@angular/core';
import { combineLatest } from 'rxjs';
import { DomUtil } from '../utils/dom-util';
import { SubscriptionTracker } from '../common/subscription/subscription-tracker';
import { IdGenerator } from '../utils';
import { AriaActiveDescendantService } from '../lib/directives';
import { DataUi } from './quick-search.dataui';
import * as i0 from "@angular/core";
import * as i1 from "./quick-search.service";
import * as i2 from "@vcd/i18n";
import * as i3 from "../lib/directives";
import * as i4 from "../common/subscription/subscription-tracker";
import * as i5 from "../utils";
import * as i6 from "@angular/common";
import * as i7 from "@clr/angular";
import * as i8 from "@angular/forms";
import * as i9 from "../lib/directives/show-clipped-text.directive";
import * as i10 from "../lib/directives/aria-activedescendant/aria-active-descendant.directive";
import * as i11 from "./drawer/drawer.component";
/**
 * The Quick Search component is inspired by the Spotlight Search in Mac OSX (cmd+space)
 * and the Search Everywhere in IntelliJ (shift+shift)
 *
 * This VCD Quick Search does not provide any search by itself. It is not also a single component
 * but rather a group of objects that work together in order to allow the developer to build a might search experience
 * for the end user.
 *
 * Basically the VCD Quick Search consists of:
 * <ul>
 *     <li>QuickSearchComponent - the visual component that you should include in your template</li>
 *     <li>{@link QuickSearchService}<a href="/compodoc/injectables/QuickSearchService.html">QuickSearchService</a>
 *     - the service that you should register your own providers with</li>
 *     <li>{@link QuickSearchProvider}<a href="/compodoc/interfaces/QuickSearchProvider.html">QuickSearchProvider</a>
 *     - the interface your search provider should implement.
 *     It can return either an array of {@link QuickSearchResults} or a promise for lazy loading of results</li>
 * </ul>
 *
 * QuickSearchComponent:
 *
 *    <vcd-quick-search
 *        [(open)]="quickSearchOpen"
 *        [placeholder]="'Search ...'"
 *    ></vcd-quick-search>
 *
 *
 * {@link QuickSearchService}:
 *
 * This service works along with the component in order to provide search results displayed. Those results are grouped
 * in sections based on the registered provider {@link QuickSearchProvider}.
 *
 * You can provide order of the search providers, hence the order of the displayed sections
 *
 * If there is just one search provider no section title is displayed.
 *
 * In case of multiple search providers the Quick Search can be configured to hide the entire section if it contains no data.
 *
 *
 * For a complete end-to-end running example please take a look at the `Examples` tab of the live-docs
 */
export class QuickSearchComponent {
    constructor(searchService, translationService, ariaActivedescendantService, changeDetectorRef, el, subscriptionTracker, idGenerator) {
        this.searchService = searchService;
        this.translationService = translationService;
        this.ariaActivedescendantService = ariaActivedescendantService;
        this.changeDetectorRef = changeDetectorRef;
        this.el = el;
        this.subscriptionTracker = subscriptionTracker;
        this.idGenerator = idGenerator;
        /**
         * This method along with `open` property provide two-way binding [(open)] for controlling the visibility state
         * of the quick search component
         */
        this.openChange = new EventEmitter(false);
        /**
         * Event dispatched when item has been activated, i.e. its event handler is called.
         * This happens when item is clicked or 'Enter' is pressed when there is a selection.
         */
        this.resultActivated = new EventEmitter();
        this.DataUi = DataUi;
        this.resultsGridId = this.idGenerator.generate();
        this._searchCriteria = '';
        this._open = false;
        this._groupedSearchSections = [];
        this._ungroupedSearchSections = [];
        this._filterValues = new Map();
    }
    /**
     * This property alongside with `openChange` provide two-way binding [(open)] for controlling the visibility state
     * of the quick search component
     */
    set open(open) {
        this.handleOpen(open);
    }
    get open() {
        return this._open;
    }
    get searchCriteria() {
        return this._searchCriteria;
    }
    set searchCriteria(value) {
        this._searchCriteria = value;
        this.doSearch();
    }
    ngOnInit() {
        this.ariaActivedescendantService.activeDescendantObservable.subscribe((id) => {
            this.activeDescendantId = id;
            this.changeDetectorRef.detectChanges();
        });
        this.subscriptionTracker.subscribe(combineLatest([
            this.searchService.groupedSearchSectionChanged,
            this.searchService.ungroupedSearchSectionChanged,
        ]), ([grouped, ungrouped]) => {
            this._groupedSearchSections = grouped;
            this._ungroupedSearchSections = ungrouped;
        });
        this.subscriptionTracker.subscribe(this.searchService.filterValueChanges, (filterValues) => {
            this._filterValues = filterValues;
        });
    }
    itemClicked(item) {
        this.handleItem(item, true);
    }
    onArrowDown(event) {
        event.preventDefault();
        this.selectNext(true);
    }
    onArrowUp(event) {
        event.preventDefault();
        this.selectNext(false);
    }
    onEnterKey(event) {
        if (!this.selectedItem) {
            return;
        }
        event.preventDefault();
        this.handleItem(this.selectedItem, false);
    }
    togglePinned() {
        this.searchService.isPinned = !this.searchService.isPinned;
        // When the pinning of the component changes, the searchInput is re-rendered. Because of this, we need to wait for
        // Angular to re-render the searchInput before focusing it.
        setTimeout(() => {
            this.searchInput.nativeElement.focus();
        });
    }
    /**
     * Searches all the providers given the search term and the active filters.
     *
     * @param force runs the search even if the active filters and search term has not changed.
     */
    doSearch(force) {
        if (!this.open && !force) {
            return;
        }
        this.selectedItem = null;
        this.searchService.doSearch(this.searchCriteria, force, () => {
            if (!this.selectedItem) {
                this.selectFirst(true);
            }
        });
    }
    /**
     * Try to select the first item in the compound search result.
     * @param ensureFirstSectionIsLoaded if true and if the topmost section is still loading then do not select an item
     */
    selectFirst(ensureFirstSectionIsLoaded) {
        for (const section of this.getFlattenedSearchSections()) {
            // The section is still loading. If it was requested to ensure the loading has completed than stop
            // the attempt to select an item or just skip it and examine the next section.
            if (section.isLoading) {
                if (ensureFirstSectionIsLoaded) {
                    return;
                }
                continue;
            }
            this.selectedItem = section.result?.items[0];
            if (this.selectedItem) {
                break;
            }
        }
        this.changeDetectorRef.detectChanges();
    }
    selectNext(down) {
        // If there is no selection then just select the first available item
        if (!this.selectedItem) {
            this.selectFirst(false);
            return;
        }
        this.selectedItem = this.genericSelectNext(down, this.selectedItem, this.getFlattenedSearchSections().reduce((acc, v) => [...acc, ...(v.result?.items || [])], []));
        if (this.selectedItem === null) {
            this.selectFirst(false);
        }
        // Call the change detector otherwise the selection on the screen may not refreshed quickly enough if the
        // user just presses and holds down the arrow key
        this.changeDetectorRef.detectChanges();
    }
    genericSelectNext(down, selected, allResults) {
        let selectedItemIndex = allResults.indexOf(selected);
        // There is a selected item but it is not one of the available ones, so just select the first from the list
        if (selectedItemIndex < 0) {
            selected = null;
            this.selectFirst(false);
            return;
        }
        // Determine the index of the next selection
        if (down) {
            if (selectedItemIndex === allResults.length - 1) {
                selectedItemIndex = 0;
            }
            else {
                selectedItemIndex++;
            }
        }
        else {
            if (selectedItemIndex === 0) {
                selectedItemIndex = allResults.length - 1;
            }
            else {
                selectedItemIndex--;
            }
        }
        selected = allResults[selectedItemIndex];
        // Ensure the selected element is visible
        DomUtil.scrollToElement(this.el, '.selected');
        if (selectedItemIndex === 0) {
            DomUtil.scrollToElement(this.el, '.section-index-0-0 .search-result-section-title');
        }
        return selected;
    }
    /**
     * Handle showing / hiding of the Quick Search.
     * @param open true when opening, false when closing
     */
    handleOpen(open) {
        // Don't do anything if the state has not been changed or if the developer has not explicitly specified the state.
        // This may happen if the template is used with uninitialized variable.
        if (open === this._open || typeof open !== 'boolean') {
            return;
        }
        if (open) {
            setTimeout(() => {
                this.searchInput.nativeElement.focus();
                this.searchInput.nativeElement.select();
            }, 0);
            this.doSearch(true);
        }
        this._open = open;
        this.openChange.emit(this._open);
        this.changeDetectorRef.detectChanges();
    }
    handleItem(item, clicked) {
        const searchSection = this.getFlattenedSearchSections().find((section) => !section.isLoading &&
            section.result?.items.some((resultItem) => resultItem.displayText === item.displayText));
        const resultActivatedEvent = {
            itemDisplayText: item.displayText,
            sectionTitle: searchSection.provider.sectionName,
            eventSource: clicked ? 'MouseEvent' : 'KeyboardEvent',
        };
        item.handler();
        this.resultActivated.emit(resultActivatedEvent);
        if (!this.searchService.isPinned) {
            this.open = false;
        }
    }
    getFlattenedSearchSections() {
        const allSections = [];
        // Takes the nested providers, and turns them to a single deep list of sections.
        this._groupedSearchSections.forEach((section) => allSections.push(...section.subSections));
        return [...this._ungroupedSearchSections, ...allSections];
    }
    getFilterOptionValue(filterId, optionKey) {
        return !!this._filterValues.get(filterId)?.find((option) => option.key === optionKey);
    }
    showParentSectionTitle(parentSection) {
        return parentSection.subSections.some((section) => section.shouldShowText && !section.isLoading);
    }
    groupSectionTrackBy(_index, groupedSection) {
        return groupedSection.headerTitle;
    }
    sectionTrackBy(_index, searchSection) {
        return searchSection.provider.sectionName;
    }
    filterOptionTrackBy(_index, filterOption) {
        return filterOption.key;
    }
    filterTrackBy(_index, filterOption) {
        return filterOption.id;
    }
}
/** @nocollapse */ QuickSearchComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.4", ngImport: i0, type: QuickSearchComponent, deps: [{ token: i1.QuickSearchService }, { token: i2.TranslationService }, { token: i3.AriaActiveDescendantService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i4.SubscriptionTracker }, { token: i5.IdGenerator }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ QuickSearchComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.4", type: QuickSearchComponent, selector: "vcd-quick-search", inputs: { placeholder: "placeholder", helper: "helper", open: "open", accessibilityTitle: "accessibilityTitle" }, outputs: { openChange: "openChange", resultActivated: "resultActivated" }, providers: [
        SubscriptionTracker,
        AriaActiveDescendantService,
        {
            provide: IdGenerator,
            useValue: new IdGenerator('vcd-quick-search'),
        },
    ], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, read: ElementRef }], ngImport: i0, template: "<ng-template #sectionTitle let-searchSection>\n    <div class=\"section-title-wrapper\">\n        <clr-icon *ngIf=\"searchSection.icon\" [attr.shape]=\"searchSection.icon\" size=\"20\"> </clr-icon>\n        <div *ngIf=\"searchSection.hasPartialResult; let partial; else: partial\">\n            {{\n                'vcd.cc.quickSearch.partialResultTitle'\n                    | translate\n                        : {\n                              title: searchSection.provider.sectionName,\n                              lastItem: partial.lastItem,\n                              totalItems: partial.totalItems\n                          }\n            }}\n        </div>\n        <ng-template #partial>\n            {{ searchSection.provider.sectionName }}\n        </ng-template>\n    </div>\n</ng-template>\n\n<ng-template #filtersSection>\n    <div class=\"filter-container\" *ngIf=\"this.searchService.filters.length > 0\">\n        <p>{{ 'vcd.cc.search.filterBy' | translate }}</p>\n        <ng-container *ngFor=\"let filter of this.searchService.filters; trackBy: filterTrackBy\">\n            <clr-dropdown\n                [clrCloseMenuOnItemClick]=\"false\"\n                *ngIf=\"filter.options.length > 1\"\n                (keydown.arrowup)=\"$event.stopPropagation()\"\n                (keydown.arrowdown)=\"$event.stopPropagation()\"\n                (keydown.enter)=\"$event.stopPropagation()\"\n            >\n                <button\n                    class=\"dropdown-toggle btn btn-link\"\n                    type=\"button\"\n                    clrDropdownTrigger\n                    [attr.data-ui]=\"DataUi.filterButton(filter.id)\"\n                    [attr.aria-label]=\"'vcd.cc.search.filterBy.btn.label' | translate: filter.dropdownText\"\n                >\n                    {{ filter.dropdownText }}\n                    <clr-icon shape=\"caret down\"></clr-icon>\n                </button>\n                <clr-dropdown-menu clrPosition=\"bottom\" *clrIfOpen #dropdownMenu>\n                    <li\n                        clrDropdownItem\n                        *ngFor=\"let option of filter.options; trackBy: filterOptionTrackBy\"\n                        (click)=\"searchService.selectFilter(filter.id, [option.key], false)\"\n                    >\n                        <clr-checkbox-wrapper class=\"column-checkbox\">\n                            <input\n                                type=\"checkbox\"\n                                clrCheckbox\n                                (click)=\"$event.stopPropagation()\"\n                                [ngModel]=\"getFilterOptionValue(filter.id, option.key)\"\n                                (ngModelChange)=\"searchService.selectFilter(filter.id, [option.key], false)\"\n                                [attr.data-ui]=\"DataUi.filterDropdownItem\"\n                            />\n                            <label (click)=\"$event.stopPropagation()\">{{ option.display }}</label>\n                        </clr-checkbox-wrapper>\n                    </li>\n                </clr-dropdown-menu>\n            </clr-dropdown>\n        </ng-container>\n    </div>\n    <div>\n        <ng-container *ngFor=\"let filter of this.searchService.filters; trackBy: filterTrackBy\">\n            <span\n                class=\"filter-bubble label\"\n                *ngFor=\"let option of _filterValues.get(filter.id); trackBy: filterOptionTrackBy\"\n            >\n                <span [vcdShowClippedText]=\"{ disabled: !open }\">{{\n                    filter.bubbleI18nKey | translate: { option: option.display }\n                }}</span>\n                <button\n                    type=\"button\"\n                    class=\"btn btn-icon btn-link remove-col-button\"\n                    [attr.aria-label]=\"\n                        'vcd.cc.quickSearch.removeFilter'\n                            | translate\n                                : { selectedFilter: filter.bubbleI18nKey | translate: { option: option.display } }\n                    \"\n                    (click)=\"searchService.selectFilter(filter.id, [option.key], false)\"\n                >\n                    <clr-icon shape=\"close\" class=\"badge badge-info\"> </clr-icon>\n                </button>\n            </span>\n        </ng-container>\n    </div>\n</ng-template>\n\n<ng-template let-searchSection #searchSectionTemplate>\n    <ul class=\"list-unstyled compact\" role=\"none\">\n        <li\n            class=\"search-result-item\"\n            role=\"row\"\n            *ngFor=\"let item of searchSection.result?.items; let i = index\"\n            (click)=\"itemClicked(item)\"\n            [ngClass]=\"item === selectedItem ? 'selected' : ''\"\n            [attr.data-ui]=\"DataUi.searchResultItems\"\n        >\n            <span role=\"gridcell\">\n                <button [vcdAriaActiveDescendant]=\"item === selectedItem\">\n                    {{ item.displayText }}\n                </button>\n            </span>\n        </li>\n        <li>\n            <clr-alert\n                *ngIf=\"searchSection.hasPartialResult\"\n                [clrAlertType]=\"'warning'\"\n                [clrAlertSizeSmall]=\"true\"\n                [clrAlertClosable]=\"false\"\n            >\n                <clr-alert-item [attr.data-ui]=\"DataUi.searchResultAlerts\">\n                    {{ 'vcd.cc.quickSearch.refineQuery' | translate: { max: searchSection.result.items.length } }}\n                </clr-alert-item>\n            </clr-alert>\n        </li>\n    </ul>\n</ng-template>\n\n<ng-template #quickSearchInterior>\n    <div class=\"search-input-container\" data-ui=\"search-input-container\">\n        <div class=\"search-icon-container\">\n            <clr-icon shape=\"search\" size=\"20\" *ngIf=\"!searchService.isLoading\"></clr-icon>\n            <clr-spinner\n                [clrSmall]=\"true\"\n                [clrInline]=\"true\"\n                [attr.data-ui]=\"DataUi.spinner\"\n                *ngIf=\"searchService.isLoading\"\n            ></clr-spinner>\n        </div>\n        <input\n            #searchInput\n            type=\"search\"\n            role=\"searchbox\"\n            class=\"clr-input\"\n            [placeholder]=\"placeholder || ''\"\n            [(ngModel)]=\"searchCriteria\"\n            [attr.data-ui]=\"DataUi.searchInput\"\n            [attr.aria-owns]=\"resultsGridId\"\n            [attr.aria-controls]=\"resultsGridId\"\n            [attr.aria-activedescendant]=\"activeDescendantId\"\n        />\n        <button\n            class=\"btn btn-link pin-button\"\n            [attr.aria-label]=\"'vcd.cc.search.pin.btn.label' | translate: accessibilityTitle\"\n            [attr.aria-pressed]=\"searchService.isPinned\"\n            (click)=\"togglePinned()\"\n        >\n            <clr-icon shape=\"pin\" size=\"20\" [ngClass]=\"this.searchService.isPinned ? 'is-solid' : ''\"> </clr-icon>\n        </button>\n    </div>\n    <clr-control-helper class=\"input-helper\">{{ helper }}</clr-control-helper>\n    <ng-container *ngTemplateOutlet=\"filtersSection\"> </ng-container>\n    <ng-content select=\".top-of-results\"></ng-content>\n    <div class=\"search-result-container\" role=\"grid\" [attr.id]=\"resultsGridId\" *ngIf=\"searchInput.value !== ''\">\n        <div\n            class=\"no-results\"\n            role=\"row\"\n            [attr.data-ui]=\"DataUi.noResults\"\n            *ngIf=\"searchService.hasNoResults && !searchService.isLoading\"\n        >\n            <span role=\"gridcell\" [vcdAriaActiveDescendant]=\"searchService.hasNoResults && !searchService.isLoading\">\n                {{ 'vcd.cc.quickSearch.noResults' | translate }}\n            </span>\n        </div>\n        <div\n            *ngFor=\"let searchSection of _ungroupedSearchSections; let i = index; trackBy: sectionTrackBy\"\n            class=\"search-result-section section-index-0-{{ i + 1 }}\"\n            data-ui=\"search-result-section\"\n        >\n            <div *ngIf=\"!searchSection.isLoading\" role=\"rowgroup\" [attr.aria-labelledby]=\"'ungrouped-search-' + i\">\n                <h5\n                    *ngIf=\"searchSection.shouldShowText\"\n                    class=\"search-result-section-title\"\n                    role=\"presentation\"\n                    [attr.data-ui]=\"DataUi.searchResultSectionTitles\"\n                    [attr.id]=\"'ungrouped-search-' + i\"\n                >\n                    <ng-container *ngTemplateOutlet=\"sectionTitle; context: { $implicit: searchSection }\">\n                    </ng-container>\n                </h5>\n                <ng-container *ngTemplateOutlet=\"searchSectionTemplate; context: { $implicit: searchSection }\">\n                </ng-container>\n            </div>\n        </div>\n        <div *ngFor=\"let parentSearchSection of _groupedSearchSections; let n = index; trackBy: groupSectionTrackBy\">\n            <h5\n                *ngIf=\"showParentSectionTitle(parentSearchSection)\"\n                class=\"search-result-section-title\"\n                [attr.data-ui]=\"DataUi.searchResultSectionTitles\"\n                [attr.id]=\"'grouped-search-result-' + n\"\n                role=\"presentation\"\n            >\n                {{ parentSearchSection.headerTitle }}\n            </h5>\n            <div\n                *ngFor=\"let searchSection of parentSearchSection.subSections; let i = index; trackBy: sectionTrackBy\"\n                class=\"sub-section\"\n                role=\"rowgroup\"\n                [attr.aria-labelledby]=\"'grouped-search-result-' + n + ' ' + 'grouped-search-result-section' + i\"\n            >\n                <div *ngIf=\"!searchSection.isLoading\">\n                    <p\n                        *ngIf=\"searchSection.shouldShowText\"\n                        role=\"presentation\"\n                        class=\"p2 search-result-section-title search-result-section section-index-{{ n }}-{{ i }}\"\n                        [attr.data-ui]=\"DataUi.searchResultSectionTitles\"\n                        [attr.id]=\"'grouped-search-result-section' + i\"\n                    >\n                        <ng-container *ngTemplateOutlet=\"sectionTitle; context: { $implicit: searchSection }\">\n                        </ng-container>\n                    </p>\n                    <ng-container *ngTemplateOutlet=\"searchSectionTemplate; context: { $implicit: searchSection }\">\n                    </ng-container>\n                </div>\n            </div>\n        </div>\n    </div>\n    <ng-content select=\".bottom-of-results\"></ng-content>\n</ng-template>\n\n<ng-template #drawerComponent>\n    <vcd-drawer-component\n        (keydown.arrowup)=\"onArrowUp($event)\"\n        (keydown.arrowdown)=\"onArrowDown($event)\"\n        (keydown.enter)=\"onEnterKey($event)\"\n        class=\"modal-body\"\n    >\n        <ng-container *ngTemplateOutlet=\"quickSearchInterior\"> </ng-container>\n    </vcd-drawer-component>\n</ng-template>\n\n<clr-modal\n    [(clrModalOpen)]=\"open\"\n    [clrModalStaticBackdrop]=\"false\"\n    (keydown.arrowup)=\"onArrowUp($event)\"\n    (keydown.arrowdown)=\"onArrowDown($event)\"\n    (keydown.enter)=\"onEnterKey($event)\"\n    *ngIf=\"!searchService.isPinned; else drawerComponent\"\n>\n    <h1 class=\"modal-title\">{{ accessibilityTitle }}</h1>\n    <div class=\"modal-body\" [attr.data-ui]=\"DataUi.modalBody\">\n        <ng-container *ngTemplateOutlet=\"quickSearchInterior\"> </ng-container>\n    </div>\n</clr-modal>\n", styles: [":host ::ng-deep{height:0}:host ::ng-deep .modal-header{display:none}:host ::ng-deep .modal-backdrop{background:transparent}.dropdown{position:absolute}.modal-body{display:flex;flex-direction:column;height:500px}.modal-body .search-input-container{margin-top:.25rem;display:flex}.modal-body .search-input-container .search-icon-container{margin-top:2px;margin-right:4px}.modal-body .search-input-container .clr-input{flex-grow:1}.modal-body .search-result-container{margin-top:8px;flex:1;overflow:auto}.modal-body .search-result-container .search-result-section{margin-top:8px}.modal-body .search-result-container .search-result-section-title{font-weight:700;margin-top:0}.modal-body .search-result-container .no-results{color:var(--clr-color-neutral-500);font-style:italic}.modal-body .search-result-container .search-result-item{padding-left:8px}.modal-body .search-result-container .search-result-item:hover{background-color:var(--clr-tree-link-hover-color)}.modal-body .search-result-container .search-result-item button{background:none;border:none}.filters-autofill{top:4rem}.selected{background-color:var(--clr-global-selection-color)}.sub-section{padding-left:8px}.measurement-div{flex-shrink:1;visibility:hidden;height:0}.btn.btn-link.pin-button{display:flex;margin:0;min-width:0px}vcd-drawer-component.modal-body{display:inline;height:unset;flex-direction:row}.dropdown-item{color:var(--clr-global-font-color)}:host ::ng-deep .modal-header--accessible{display:none}clr-control-helper.input-helper{margin-left:25px;margin-top:0}.search-icon-container{width:20px;height:20px}.section-title-wrapper{display:flex}.section-title-wrapper clr-icon{margin-right:5px}.filter-container{display:flex}.filter-container clr-dropdown{position:static}.filter-container .filter-text{margin-right:10px}.filter-container p{margin-top:auto;margin-bottom:auto;margin-right:10px}.filter-bubble{padding-left:.4rem;padding-right:.1rem}.filter-bubble .btn-link{margin:0}.filter-bubble clr-icon{color:var(--clr-badge-info-color, white)}button.btn-link.remove-col-button{margin:0;padding-right:5px;padding-left:5px}button.btn-link.remove-col-button clr-icon{margin-right:0}\n"], dependencies: [{ kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i7.ClrAlert, selector: "clr-alert", inputs: ["clrAlertSizeSmall", "clrAlertClosable", "clrAlertAppLevel", "clrCloseButtonAriaLabel", "clrAlertClosed", "clrAlertType", "clrAlertIcon"], outputs: ["clrAlertClosedChange"] }, { kind: "component", type: i7.ClrAlertItem, selector: "clr-alert-item" }, { kind: "directive", type: i7.ClrDatagridItemsTrackBy, selector: "[ngForTrackBy]", inputs: ["ngForTrackBy"] }, { kind: "directive", type: i7.ClrIconCustomTag, selector: "clr-icon" }, { kind: "component", type: i7.ClrModal, selector: "clr-modal", inputs: ["clrModalOpen", "clrModalClosable", "clrModalCloseButtonAriaLabel", "clrModalSize", "clrModalStaticBackdrop", "clrModalSkipAnimation", "clrModalPreventClose", "clrModalLabelledById"], outputs: ["clrModalOpenChange", "clrModalAlternateClose"] }, { kind: "directive", type: i7.ClrModalBody, selector: ".modal-body" }, { kind: "directive", type: i7.ClrIfOpen, selector: "[clrIfOpen]", inputs: ["clrIfOpen"], outputs: ["clrIfOpenChange"] }, { kind: "directive", type: i7.ClrLabel, selector: "label", inputs: ["for"] }, { kind: "component", type: i7.ClrControlHelper, selector: "clr-control-helper" }, { kind: "directive", type: i7.ClrCheckbox, selector: "[clrCheckbox],[clrToggle]" }, { kind: "component", type: i7.ClrCheckboxWrapper, selector: "clr-checkbox-wrapper,clr-toggle-wrapper" }, { kind: "component", type: i7.ClrDropdown, selector: "clr-dropdown", inputs: ["clrCloseMenuOnItemClick"] }, { kind: "component", type: i7.ClrDropdownMenu, selector: "clr-dropdown-menu", inputs: ["clrPosition"] }, { kind: "directive", type: i7.ClrDropdownTrigger, selector: "[clrDropdownTrigger],[clrDropdownToggle]" }, { kind: "directive", type: i7.ClrDropdownItem, selector: "[clrDropdownItem]", inputs: ["clrDisabled", "id"] }, { kind: "component", type: i7.ClrSpinner, selector: "clr-spinner", inputs: ["clrInline", "clrInverse", "clrSmall", "clrMedium"] }, { kind: "directive", type: i8.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: i8.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i9.ShowClippedTextDirective, selector: "[vcdShowClippedText]", inputs: ["vcdShowClippedText"] }, { kind: "directive", type: i10.AriaActiveDescendantDirective, selector: "[vcdAriaActiveDescendant]", inputs: ["vcdAriaActiveDescendant"] }, { kind: "component", type: i11.DrawerComponent, selector: "vcd-drawer-component", inputs: ["topOffset", "headerHeight"] }, { kind: "pipe", type: i2.TranslationPipe, name: "translate" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.4", ngImport: i0, type: QuickSearchComponent, decorators: [{
            type: Component,
            args: [{ selector: 'vcd-quick-search', providers: [
                        SubscriptionTracker,
                        AriaActiveDescendantService,
                        {
                            provide: IdGenerator,
                            useValue: new IdGenerator('vcd-quick-search'),
                        },
                    ], template: "<ng-template #sectionTitle let-searchSection>\n    <div class=\"section-title-wrapper\">\n        <clr-icon *ngIf=\"searchSection.icon\" [attr.shape]=\"searchSection.icon\" size=\"20\"> </clr-icon>\n        <div *ngIf=\"searchSection.hasPartialResult; let partial; else: partial\">\n            {{\n                'vcd.cc.quickSearch.partialResultTitle'\n                    | translate\n                        : {\n                              title: searchSection.provider.sectionName,\n                              lastItem: partial.lastItem,\n                              totalItems: partial.totalItems\n                          }\n            }}\n        </div>\n        <ng-template #partial>\n            {{ searchSection.provider.sectionName }}\n        </ng-template>\n    </div>\n</ng-template>\n\n<ng-template #filtersSection>\n    <div class=\"filter-container\" *ngIf=\"this.searchService.filters.length > 0\">\n        <p>{{ 'vcd.cc.search.filterBy' | translate }}</p>\n        <ng-container *ngFor=\"let filter of this.searchService.filters; trackBy: filterTrackBy\">\n            <clr-dropdown\n                [clrCloseMenuOnItemClick]=\"false\"\n                *ngIf=\"filter.options.length > 1\"\n                (keydown.arrowup)=\"$event.stopPropagation()\"\n                (keydown.arrowdown)=\"$event.stopPropagation()\"\n                (keydown.enter)=\"$event.stopPropagation()\"\n            >\n                <button\n                    class=\"dropdown-toggle btn btn-link\"\n                    type=\"button\"\n                    clrDropdownTrigger\n                    [attr.data-ui]=\"DataUi.filterButton(filter.id)\"\n                    [attr.aria-label]=\"'vcd.cc.search.filterBy.btn.label' | translate: filter.dropdownText\"\n                >\n                    {{ filter.dropdownText }}\n                    <clr-icon shape=\"caret down\"></clr-icon>\n                </button>\n                <clr-dropdown-menu clrPosition=\"bottom\" *clrIfOpen #dropdownMenu>\n                    <li\n                        clrDropdownItem\n                        *ngFor=\"let option of filter.options; trackBy: filterOptionTrackBy\"\n                        (click)=\"searchService.selectFilter(filter.id, [option.key], false)\"\n                    >\n                        <clr-checkbox-wrapper class=\"column-checkbox\">\n                            <input\n                                type=\"checkbox\"\n                                clrCheckbox\n                                (click)=\"$event.stopPropagation()\"\n                                [ngModel]=\"getFilterOptionValue(filter.id, option.key)\"\n                                (ngModelChange)=\"searchService.selectFilter(filter.id, [option.key], false)\"\n                                [attr.data-ui]=\"DataUi.filterDropdownItem\"\n                            />\n                            <label (click)=\"$event.stopPropagation()\">{{ option.display }}</label>\n                        </clr-checkbox-wrapper>\n                    </li>\n                </clr-dropdown-menu>\n            </clr-dropdown>\n        </ng-container>\n    </div>\n    <div>\n        <ng-container *ngFor=\"let filter of this.searchService.filters; trackBy: filterTrackBy\">\n            <span\n                class=\"filter-bubble label\"\n                *ngFor=\"let option of _filterValues.get(filter.id); trackBy: filterOptionTrackBy\"\n            >\n                <span [vcdShowClippedText]=\"{ disabled: !open }\">{{\n                    filter.bubbleI18nKey | translate: { option: option.display }\n                }}</span>\n                <button\n                    type=\"button\"\n                    class=\"btn btn-icon btn-link remove-col-button\"\n                    [attr.aria-label]=\"\n                        'vcd.cc.quickSearch.removeFilter'\n                            | translate\n                                : { selectedFilter: filter.bubbleI18nKey | translate: { option: option.display } }\n                    \"\n                    (click)=\"searchService.selectFilter(filter.id, [option.key], false)\"\n                >\n                    <clr-icon shape=\"close\" class=\"badge badge-info\"> </clr-icon>\n                </button>\n            </span>\n        </ng-container>\n    </div>\n</ng-template>\n\n<ng-template let-searchSection #searchSectionTemplate>\n    <ul class=\"list-unstyled compact\" role=\"none\">\n        <li\n            class=\"search-result-item\"\n            role=\"row\"\n            *ngFor=\"let item of searchSection.result?.items; let i = index\"\n            (click)=\"itemClicked(item)\"\n            [ngClass]=\"item === selectedItem ? 'selected' : ''\"\n            [attr.data-ui]=\"DataUi.searchResultItems\"\n        >\n            <span role=\"gridcell\">\n                <button [vcdAriaActiveDescendant]=\"item === selectedItem\">\n                    {{ item.displayText }}\n                </button>\n            </span>\n        </li>\n        <li>\n            <clr-alert\n                *ngIf=\"searchSection.hasPartialResult\"\n                [clrAlertType]=\"'warning'\"\n                [clrAlertSizeSmall]=\"true\"\n                [clrAlertClosable]=\"false\"\n            >\n                <clr-alert-item [attr.data-ui]=\"DataUi.searchResultAlerts\">\n                    {{ 'vcd.cc.quickSearch.refineQuery' | translate: { max: searchSection.result.items.length } }}\n                </clr-alert-item>\n            </clr-alert>\n        </li>\n    </ul>\n</ng-template>\n\n<ng-template #quickSearchInterior>\n    <div class=\"search-input-container\" data-ui=\"search-input-container\">\n        <div class=\"search-icon-container\">\n            <clr-icon shape=\"search\" size=\"20\" *ngIf=\"!searchService.isLoading\"></clr-icon>\n            <clr-spinner\n                [clrSmall]=\"true\"\n                [clrInline]=\"true\"\n                [attr.data-ui]=\"DataUi.spinner\"\n                *ngIf=\"searchService.isLoading\"\n            ></clr-spinner>\n        </div>\n        <input\n            #searchInput\n            type=\"search\"\n            role=\"searchbox\"\n            class=\"clr-input\"\n            [placeholder]=\"placeholder || ''\"\n            [(ngModel)]=\"searchCriteria\"\n            [attr.data-ui]=\"DataUi.searchInput\"\n            [attr.aria-owns]=\"resultsGridId\"\n            [attr.aria-controls]=\"resultsGridId\"\n            [attr.aria-activedescendant]=\"activeDescendantId\"\n        />\n        <button\n            class=\"btn btn-link pin-button\"\n            [attr.aria-label]=\"'vcd.cc.search.pin.btn.label' | translate: accessibilityTitle\"\n            [attr.aria-pressed]=\"searchService.isPinned\"\n            (click)=\"togglePinned()\"\n        >\n            <clr-icon shape=\"pin\" size=\"20\" [ngClass]=\"this.searchService.isPinned ? 'is-solid' : ''\"> </clr-icon>\n        </button>\n    </div>\n    <clr-control-helper class=\"input-helper\">{{ helper }}</clr-control-helper>\n    <ng-container *ngTemplateOutlet=\"filtersSection\"> </ng-container>\n    <ng-content select=\".top-of-results\"></ng-content>\n    <div class=\"search-result-container\" role=\"grid\" [attr.id]=\"resultsGridId\" *ngIf=\"searchInput.value !== ''\">\n        <div\n            class=\"no-results\"\n            role=\"row\"\n            [attr.data-ui]=\"DataUi.noResults\"\n            *ngIf=\"searchService.hasNoResults && !searchService.isLoading\"\n        >\n            <span role=\"gridcell\" [vcdAriaActiveDescendant]=\"searchService.hasNoResults && !searchService.isLoading\">\n                {{ 'vcd.cc.quickSearch.noResults' | translate }}\n            </span>\n        </div>\n        <div\n            *ngFor=\"let searchSection of _ungroupedSearchSections; let i = index; trackBy: sectionTrackBy\"\n            class=\"search-result-section section-index-0-{{ i + 1 }}\"\n            data-ui=\"search-result-section\"\n        >\n            <div *ngIf=\"!searchSection.isLoading\" role=\"rowgroup\" [attr.aria-labelledby]=\"'ungrouped-search-' + i\">\n                <h5\n                    *ngIf=\"searchSection.shouldShowText\"\n                    class=\"search-result-section-title\"\n                    role=\"presentation\"\n                    [attr.data-ui]=\"DataUi.searchResultSectionTitles\"\n                    [attr.id]=\"'ungrouped-search-' + i\"\n                >\n                    <ng-container *ngTemplateOutlet=\"sectionTitle; context: { $implicit: searchSection }\">\n                    </ng-container>\n                </h5>\n                <ng-container *ngTemplateOutlet=\"searchSectionTemplate; context: { $implicit: searchSection }\">\n                </ng-container>\n            </div>\n        </div>\n        <div *ngFor=\"let parentSearchSection of _groupedSearchSections; let n = index; trackBy: groupSectionTrackBy\">\n            <h5\n                *ngIf=\"showParentSectionTitle(parentSearchSection)\"\n                class=\"search-result-section-title\"\n                [attr.data-ui]=\"DataUi.searchResultSectionTitles\"\n                [attr.id]=\"'grouped-search-result-' + n\"\n                role=\"presentation\"\n            >\n                {{ parentSearchSection.headerTitle }}\n            </h5>\n            <div\n                *ngFor=\"let searchSection of parentSearchSection.subSections; let i = index; trackBy: sectionTrackBy\"\n                class=\"sub-section\"\n                role=\"rowgroup\"\n                [attr.aria-labelledby]=\"'grouped-search-result-' + n + ' ' + 'grouped-search-result-section' + i\"\n            >\n                <div *ngIf=\"!searchSection.isLoading\">\n                    <p\n                        *ngIf=\"searchSection.shouldShowText\"\n                        role=\"presentation\"\n                        class=\"p2 search-result-section-title search-result-section section-index-{{ n }}-{{ i }}\"\n                        [attr.data-ui]=\"DataUi.searchResultSectionTitles\"\n                        [attr.id]=\"'grouped-search-result-section' + i\"\n                    >\n                        <ng-container *ngTemplateOutlet=\"sectionTitle; context: { $implicit: searchSection }\">\n                        </ng-container>\n                    </p>\n                    <ng-container *ngTemplateOutlet=\"searchSectionTemplate; context: { $implicit: searchSection }\">\n                    </ng-container>\n                </div>\n            </div>\n        </div>\n    </div>\n    <ng-content select=\".bottom-of-results\"></ng-content>\n</ng-template>\n\n<ng-template #drawerComponent>\n    <vcd-drawer-component\n        (keydown.arrowup)=\"onArrowUp($event)\"\n        (keydown.arrowdown)=\"onArrowDown($event)\"\n        (keydown.enter)=\"onEnterKey($event)\"\n        class=\"modal-body\"\n    >\n        <ng-container *ngTemplateOutlet=\"quickSearchInterior\"> </ng-container>\n    </vcd-drawer-component>\n</ng-template>\n\n<clr-modal\n    [(clrModalOpen)]=\"open\"\n    [clrModalStaticBackdrop]=\"false\"\n    (keydown.arrowup)=\"onArrowUp($event)\"\n    (keydown.arrowdown)=\"onArrowDown($event)\"\n    (keydown.enter)=\"onEnterKey($event)\"\n    *ngIf=\"!searchService.isPinned; else drawerComponent\"\n>\n    <h1 class=\"modal-title\">{{ accessibilityTitle }}</h1>\n    <div class=\"modal-body\" [attr.data-ui]=\"DataUi.modalBody\">\n        <ng-container *ngTemplateOutlet=\"quickSearchInterior\"> </ng-container>\n    </div>\n</clr-modal>\n", styles: [":host ::ng-deep{height:0}:host ::ng-deep .modal-header{display:none}:host ::ng-deep .modal-backdrop{background:transparent}.dropdown{position:absolute}.modal-body{display:flex;flex-direction:column;height:500px}.modal-body .search-input-container{margin-top:.25rem;display:flex}.modal-body .search-input-container .search-icon-container{margin-top:2px;margin-right:4px}.modal-body .search-input-container .clr-input{flex-grow:1}.modal-body .search-result-container{margin-top:8px;flex:1;overflow:auto}.modal-body .search-result-container .search-result-section{margin-top:8px}.modal-body .search-result-container .search-result-section-title{font-weight:700;margin-top:0}.modal-body .search-result-container .no-results{color:var(--clr-color-neutral-500);font-style:italic}.modal-body .search-result-container .search-result-item{padding-left:8px}.modal-body .search-result-container .search-result-item:hover{background-color:var(--clr-tree-link-hover-color)}.modal-body .search-result-container .search-result-item button{background:none;border:none}.filters-autofill{top:4rem}.selected{background-color:var(--clr-global-selection-color)}.sub-section{padding-left:8px}.measurement-div{flex-shrink:1;visibility:hidden;height:0}.btn.btn-link.pin-button{display:flex;margin:0;min-width:0px}vcd-drawer-component.modal-body{display:inline;height:unset;flex-direction:row}.dropdown-item{color:var(--clr-global-font-color)}:host ::ng-deep .modal-header--accessible{display:none}clr-control-helper.input-helper{margin-left:25px;margin-top:0}.search-icon-container{width:20px;height:20px}.section-title-wrapper{display:flex}.section-title-wrapper clr-icon{margin-right:5px}.filter-container{display:flex}.filter-container clr-dropdown{position:static}.filter-container .filter-text{margin-right:10px}.filter-container p{margin-top:auto;margin-bottom:auto;margin-right:10px}.filter-bubble{padding-left:.4rem;padding-right:.1rem}.filter-bubble .btn-link{margin:0}.filter-bubble clr-icon{color:var(--clr-badge-info-color, white)}button.btn-link.remove-col-button{margin:0;padding-right:5px;padding-left:5px}button.btn-link.remove-col-button clr-icon{margin-right:0}\n"] }]
        }], ctorParameters: function () { return [{ type: i1.QuickSearchService }, { type: i2.TranslationService }, { type: i3.AriaActiveDescendantService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i4.SubscriptionTracker }, { type: i5.IdGenerator }]; }, propDecorators: { placeholder: [{
                type: Input
            }], helper: [{
                type: Input
            }], open: [{
                type: Input
            }], accessibilityTitle: [{
                type: Input
            }], openChange: [{
                type: Output
            }], resultActivated: [{
                type: Output
            }], searchInput: [{
                type: ViewChild,
                args: ['searchInput', { static: false, read: ElementRef }]
            }] } });
//# sourceMappingURL=data:application/json;base64, 