UNPKG

@ux-aspects/ux-aspects

Version:

Open source user interface framework for building modern, responsive, mobile big data applications

486 lines 78.3 kB
import { coerceArray } from '@angular/cdk/coercion'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, inject, Input, Output, ViewChild, } from '@angular/core'; import { BehaviorSubject, combineLatest, Subject } from 'rxjs'; import { distinctUntilChanged, takeUntil } from 'rxjs/operators'; import { InfiniteScrollDirective, } from '../../directives/infinite-scroll/index'; import { PopoverOrientationService, } from '../../services/popover-orientation/popover-orientation.service'; import { TypeaheadOptionEvent } from './typeahead-event'; import { TypeaheadService } from './typeahead.service'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "../../directives/infinite-scroll/infinite-scroll.directive"; import * as i3 from "../../directives/infinite-scroll/infinite-scroll-loading.directive"; import * as i4 from "../../directives/safe-inner-html/safe-inner-html.directive"; import * as i5 from "./typeahead-options-list.component"; let uniqueId = 0; export class TypeaheadComponent { /** Specify if the typeahead is open */ get open() { return this._service.open$.getValue(); } set open(value) { this._service.open$.next(value); } /** Specify which options are disabled */ set disabledOptions(options) { this._disabledOptions = coerceArray(options); } get disabledOptions() { return this._disabledOptions; } /** Specify the max height of the dropdown */ get maxHeight() { return this._maxHeight; } set maxHeight(maxHeight) { this._maxHeight = maxHeight; if (this.maxHeight.endsWith('px')) { this._popoverOrientationListener.maxHeight = Number(this.maxHeight.slice(0, -2)); } } /** Specify the currently active item */ set active(item) { this.activeKey = this.getKey(item); } get highlighted() { const value = this.highlighted$.getValue(); return value ? value.value : null; } constructor() { this.typeaheadElement = inject(ElementRef); this.popoverOrientation = inject(PopoverOrientationService); this._changeDetector = inject(ChangeDetectorRef); this._service = inject(TypeaheadService); /** Define a unique id for the typeahead */ this.id = `ux-typeahead-${++uniqueId}`; this._disabledOptions = []; /** Specify the drop direction */ this.dropDirection = 'down'; /** Specify the aria multi selectable attribute value */ this.multiselectable = false; /** Specify if the dropdown should appear when the filter appears */ this.openOnFilterChange = true; /** Specify the page size */ this.pageSize = 20; /** Specify if we should select the first item by default */ this.selectFirst = true; /** Specify if we should select an item on enter key press */ this.selectOnEnter = false; /** Specify the loading state */ this.loading = false; /** Maximum number of displayed recently selected options. */ this.recentOptionsMaxCount = 5; /** Emit when the open state changes */ this.openChange = new EventEmitter(); /** Emit when an option is selected */ this.optionSelected = new EventEmitter(); /** Emit whenever a highlighted item changes */ this.highlightedChange = new EventEmitter(); /** Emit the highlighted element when it changes */ this.highlightedElementChange = new EventEmitter(); /** Emits when recently selected options change.*/ this.recentOptionsChange = new EventEmitter(); this.activeKey = null; this.clicking = false; this.hasBeenOpened = false; this.highlighted$ = new BehaviorSubject(null); this.visibleOptions$ = new BehaviorSubject([]); this.visibleRecentOptions$ = new BehaviorSubject([]); this.allVisibleOptions = []; this._onDestroy = new Subject(); this._maxHeight = '250px'; this.optionApi = { getKey: this.getKey.bind(this), getDisplay: this.getDisplay.bind(this), getDisplayHtml: this.getDisplayHtml.bind(this), getDisabled: this.isDisabled.bind(this), }; this.loadOptionsCallback = (pageNum, pageSize, filter) => { if (typeof this.options === 'function') { // Invoke the callback which may return an array or a promise. const arrayOrPromise = this.options(pageNum, pageSize, filter); // Map the results to an array of TypeaheadVisibleOption. return Promise.resolve(arrayOrPromise).then(newOptions => { if (!Array.isArray(newOptions)) { return newOptions; } return this.getVisibleOptions(newOptions, ''); }); } return null; }; this._service.open$ .pipe(distinctUntilChanged(), takeUntil(this._onDestroy)) .subscribe(isOpen => { this.openChange.emit(isOpen); if (isOpen) { this.hasBeenOpened = true; this.initOptions(); } }); this._popoverOrientationListener = this.popoverOrientation.createPopoverOrientationListener(this.typeaheadElement.nativeElement, this.typeaheadElement.nativeElement.parentElement); this._popoverOrientationListener.orientation$ .pipe(takeUntil(this._onDestroy)) .subscribe(direction => { if (this.dropDirection === 'auto') { this.dropUp = direction === 0 /* PopoverOrientation.Up */; } }); this.highlighted$.pipe(takeUntil(this._onDestroy)).subscribe(next => { this.highlightedChange.emit(next ? next.value : null); }); combineLatest([this.visibleOptions$, this.visibleRecentOptions$]) .pipe(takeUntil(this._onDestroy)) .subscribe(([visibleOptions, visibleRecentOptions]) => { this.allVisibleOptions = [...visibleRecentOptions, ...visibleOptions]; }); combineLatest([this._service.open$, this._service.highlightedElement$, this.visibleOptions$]) .pipe(takeUntil(this._onDestroy)) .subscribe(([open, highlightedElement, visibleOptions]) => { this.highlightedElementChange.emit(open && visibleOptions.length > 0 ? highlightedElement : null); }); } ngOnChanges(changes) { // Open the dropdown if the filter value updates if (changes.filter) { if (this.openOnFilterChange && changes.filter.currentValue && changes.filter.currentValue.length > 0) { // if the dropdown item was just selected, and we set the filter value to match the // selected value then open will have also just been set to `false`, in which case we do // not want to set open to `true` if (changes.open && changes.open.previousValue === true && changes.open.currentValue === false) { return; } // show the dropdown this.open = true; } } // Cut off recentOptions at recentOptionsMaxCount if (changes.recentOptions || changes.recentOptionsMaxCount) { this._recentOptions = this.recentOptions ? this.recentOptions.slice(0, this.recentOptionsMaxCount) : undefined; if (changes.recentOptionsMaxCount) { // Avoid ExpressionChangedAfterChecked error setTimeout(() => { this.recentOptionsChange.emit(this._recentOptions); }); } } if (changes.dropDirection) { if (changes.dropDirection.currentValue === 'auto') { this.dropUp = this._popoverOrientationListener.orientation$.getValue() === 0 /* PopoverOrientation.Up */; } else { this.dropUp = changes.dropDirection.currentValue === 'up'; } } if (changes.options && changes.options.firstChange === false) { this.infiniteScroll.reset(false); this.infiniteScroll.reload(); } // Re-filter visibleOptions this.updateOptions(); } ngOnDestroy() { this._onDestroy.next(); this._onDestroy.complete(); this._popoverOrientationListener.destroy(); } mousedownHandler(event, target) { this.clicking = true; /** * Chrome Bug Workaround: (https://bugs.chromium.org/p/chromium/issues/detail?id=6759) * In Chrome, if the typeahead is within a tabbable element, e.g. it has a parent with * `tabindex="0"` like our side panel has, then clicking on a scrollbar will remove * focus from the input element. * * To avoid this we can determine if the mousedown event occurred within the scrollbar * region of the typeahead and if so preventDefault which will stop the input * from losing focus */ if (event.clientX >= target.clientWidth || event.clientY >= target.clientHeight) { event.preventDefault(); } } mouseupHandler() { this.clicking = false; } optionMousedownHandler(event) { // Workaround to prevent focus changing when an option is clicked event.preventDefault(); } optionClickHandler(_event, option) { this.select(option, 'mouse'); } /** * Returns the unique key value of the given option. */ getKey(option) { if (typeof this.key === 'function') { return this.key(option); } // eslint-disable-next-line no-prototype-builtins if (typeof this.key === 'string' && option && option.hasOwnProperty(this.key)) { return option[this.key]; } return this.getDisplay(option); } /** * Returns the display value of the given option. */ getDisplay(option) { if (typeof this.display === 'function') { return this.display(option); } // eslint-disable-next-line no-prototype-builtins if (typeof this.display === 'string' && option && option.hasOwnProperty(this.display)) { return option[this.display]; } if (typeof option === 'string') { return option; } } /** * Returns the display value of the given option with HTML markup added to highlight the part which matches the current filter value. * @param option */ getDisplayHtml(option) { const displayText = this.getDisplay(option); // getDisplay may return undefined in certain cases if (!displayText) { return ''; } let displayHtml = displayText .replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;'); if (this.filter) { const length = this.filter.length; const matchIndex = displayText.toLowerCase().indexOf(this.filter.toLowerCase()); if (matchIndex >= 0) { const highlight = `<span class="ux-filter-match">${displayText.substr(matchIndex, length)}</span>`; displayHtml = displayText.substr(0, matchIndex) + highlight + displayText.substr(matchIndex + length); } } return displayHtml; } /** * Returns true if the infinite scroll component should load */ isInfiniteScroll() { return typeof this.options === 'function'; } /** * Selects the given option, emitting the optionSelected event and closing the dropdown. */ select(option, origin) { if (!this.isDisabled(option.value)) { this.optionSelected.emit(new TypeaheadOptionEvent(option.value, origin)); this.highlighted$.next(null); this.open = false; this.addToRecentOptions(option.value); } } addToRecentOptions(value) { if (this._recentOptions) { this._recentOptions = [ value, ...this._recentOptions.filter(recentOption => recentOption !== value), ].slice(0, this.recentOptionsMaxCount); this.recentOptionsChange.emit(this._recentOptions); } } /** * Returns true if the given option is part of the disabledOptions array. */ isDisabled(option) { return Array.isArray(this.disabledOptions) ? this.disabledOptions.some(selectedOption => this.getKey(selectedOption) === this.getKey(option)) : false; } /** * Set the given option as the current highlighted option, available in the highlightedOption parameter. */ highlight(option) { if (!this.isDisabled(option.value)) { this.highlighted$.next(option); this._changeDetector.detectChanges(); } } /** * Increment or decrement the highlighted option in the list. Disabled options are skipped. * @param d Value to be added to the index of the highlighted option, i.e. -1 to move backwards, +1 to move forwards. */ moveHighlight(d) { const highlightIndex = this.indexOfVisibleOption(this.highlighted$.getValue()); let newIndex = highlightIndex; let disabled = true; let inBounds = true; do { newIndex = newIndex + d; inBounds = newIndex >= 0 && newIndex < this.allVisibleOptions.length; disabled = inBounds && this.isDisabled(this.allVisibleOptions[newIndex].value); } while (inBounds && disabled); if (!disabled && inBounds) { this.highlight(this.allVisibleOptions[newIndex]); } return this.highlighted; } selectHighlighted() { if (this.highlighted$.getValue()) { this.select(this.highlighted$.getValue(), 'keyboard'); } } /** * Set up the options before the dropdown is displayed. */ initOptions() { // Clear previous highlight this.highlighted$.next(null); if (this.selectFirst) { // This will highlight the first non-disabled option. this.moveHighlight(1); } } /** * Display the first item as highlighted when there are several pages */ onLoadedHighlight(event) { if (this.selectFirst && this.options && event.pageNumber === 0) { // This will highlight the first non-disabled option. this.moveHighlight(1); } } /** * Update the visibleOptions and visibleRecentOptions arrays with the current filter. */ updateOptions() { const normalisedInput = (this.filter || '').toLowerCase(); // Create new visibleOptions only if `options` is not a function if (typeof this.options === 'object') { this.visibleOptions$.next(this.getVisibleOptions(this.options, normalisedInput)); } this.visibleRecentOptions$.next(this.getVisibleOptions(this._recentOptions, normalisedInput, true)); this.initOptions(); this._changeDetector.detectChanges(); } /** * Convert a set of raw options into a filtered list of `TypeaheadVisibleOption` objects. * @param options Set of raw options * @param filter The filter expression * @param isRecentOptions Whether `options` is a set of recent options */ getVisibleOptions(options, filter = '', isRecentOptions = false) { if (options) { return options .filter(option => this.getDisplay(option).toLowerCase().indexOf(filter) >= 0) .map(value => ({ value, key: this.getKey(value), isRecentOption: isRecentOptions, })); } return []; } /** * Return the index of the given option in the allVisibleOptions array. * Returns -1 if the option is not currently visible. */ indexOfVisibleOption(option) { if (option) { return this.allVisibleOptions.findIndex(el => { return el.key === option.key && el.isRecentOption === option.isRecentOption; }); } return -1; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TypeaheadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: TypeaheadComponent, selector: "ux-typeahead", inputs: { id: "id", options: "options", filter: "filter", open: "open", display: "display", key: "key", disabledOptions: "disabledOptions", dropDirection: "dropDirection", maxHeight: "maxHeight", multiselectable: "multiselectable", ariaLabel: "ariaLabel", openOnFilterChange: "openOnFilterChange", pageSize: "pageSize", selectFirst: "selectFirst", selectOnEnter: "selectOnEnter", loading: "loading", loadingTemplate: "loadingTemplate", optionTemplate: "optionTemplate", noOptionsTemplate: "noOptionsTemplate", active: "active", recentOptions: "recentOptions", recentOptionsMaxCount: "recentOptionsMaxCount", recentOptionsHeadingTemplate: "recentOptionsHeadingTemplate", optionsHeadingTemplate: "optionsHeadingTemplate" }, outputs: { openChange: "openChange", optionSelected: "optionSelected", highlightedChange: "highlightedChange", highlightedElementChange: "highlightedElementChange", recentOptionsChange: "recentOptionsChange" }, host: { listeners: { "mousedown": "mousedownHandler($event,$event.target)", "mouseup": "mouseupHandler()" }, properties: { "class.open": "open", "style.maxHeight": "maxHeight", "attr.id": "this.id", "class.drop-up": "this.dropUp" } }, providers: [TypeaheadService, PopoverOrientationService], viewQueries: [{ propertyName: "infiniteScroll", first: true, predicate: InfiniteScrollDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"ux-typeahead-options\"\n [uxInfiniteScroll]=\"loadOptionsCallback\"\n [collection]=\"visibleOptions$ | async\"\n (collectionChange)=\"visibleOptions$.next($event)\"\n [enabled]=\"hasBeenOpened && isInfiniteScroll()\"\n [filter]=\"filter\"\n [loadOnScroll]=\"true\"\n [pageSize]=\"pageSize\"\n [scrollElement]=\"typeaheadElement\"\n (loading)=\"loading = true\"\n (loaded)=\"loading = false; onLoadedHighlight($event)\"\n >\n @if ((visibleRecentOptions$ | async).length > 0) {\n <div>\n <ng-container [ngTemplateOutlet]=\"recentOptionsHeadingTemplate\"></ng-container>\n </div>\n }\n\n <!-- Recent options -->\n @if ((visibleRecentOptions$ | async).length > 0) {\n <ux-typeahead-options-list\n class=\"ux-typeahead-recent-options\"\n [id]=\"id\"\n [options]=\"visibleRecentOptions$ | async\"\n [highlighted]=\"highlighted$ | async\"\n [activeKey]=\"activeKey\"\n [disabledOptions]=\"_disabledOptions\"\n [isMultiselectable]=\"multiselectable\"\n [optionTemplate]=\"optionTemplate || defaultOptionTemplate\"\n [optionApi]=\"optionApi\"\n [typeaheadElement]=\"typeaheadElement\"\n (optionMouseover)=\"highlight($event.option)\"\n (optionMousedown)=\"optionMousedownHandler($event.event)\"\n (optionClick)=\"optionClickHandler($event.event, $event.option)\"\n >\n </ux-typeahead-options-list>\n }\n\n <ng-container [ngTemplateOutlet]=\"optionsHeadingTemplate\"></ng-container>\n\n <!-- All options -->\n @if ((visibleOptions$ | async).length > 0) {\n <ux-typeahead-options-list\n class=\"ux-typeahead-all-options\"\n [id]=\"id\"\n [ariaLabel]=\"ariaLabel\"\n [startIndex]=\"(visibleRecentOptions$ | async).length\"\n [options]=\"visibleOptions$ | async\"\n [highlighted]=\"highlighted$ | async\"\n [activeKey]=\"activeKey\"\n [disabledOptions]=\"_disabledOptions\"\n [isMultiselectable]=\"multiselectable\"\n [optionTemplate]=\"optionTemplate || defaultOptionTemplate\"\n [optionApi]=\"optionApi\"\n [typeaheadElement]=\"typeaheadElement\"\n (optionMouseover)=\"highlight($event.option)\"\n (optionMousedown)=\"optionMousedownHandler($event.event)\"\n (optionClick)=\"optionClickHandler($event.event, $event.option)\"\n >\n </ux-typeahead-options-list>\n }\n\n <div *uxInfiniteScrollLoading>\n <ng-container [ngTemplateOutlet]=\"loadingTemplate || defaultLoadingTemplate\"></ng-container>\n </div>\n\n @if (isInfiniteScroll() === false && (visibleOptions$ | async).length === 0 && loading) {\n <div>\n <ng-container [ngTemplateOutlet]=\"loadingTemplate || defaultLoadingTemplate\"></ng-container>\n </div>\n }\n</div>\n@if ((visibleOptions$ | async).length === 0 && !loading) {\n <div>\n <ng-container [ngTemplateOutlet]=\"noOptionsTemplate || defaultNoOptionsTemplate\"> </ng-container>\n </div>\n}\n\n<ng-template #defaultLoadingTemplate>\n <div class=\"ux-typeahead-loading\">\n <div class=\"spinner spinner-accent spinner-bounce-middle\"></div>\n <div>Loading...</div>\n </div>\n</ng-template>\n\n<ng-template #defaultOptionTemplate let-option=\"option\" let-api=\"api\">\n <span class=\"ux-typeahead-option\" [uxSafeInnerHtml]=\"api.getDisplayHtml(option)\"></span>\n</ng-template>\n\n<ng-template #defaultNoOptionsTemplate>\n <span class=\"ux-typeahead-no-options\">No results</span>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.InfiniteScrollDirective, selector: "[uxInfiniteScroll]", inputs: ["uxInfiniteScroll", "collection", "scrollElement", "enabled", "filter", "loadOnInit", "loadOnScroll", "pageSize"], outputs: ["collectionChange", "loading", "loaded", "loadError"], exportAs: ["uxInfiniteScroll"] }, { kind: "directive", type: i3.InfiniteScrollLoadingDirective, selector: "[uxInfiniteScrollLoading]", inputs: ["uxInfiniteScrollLoading"] }, { kind: "directive", type: i4.SafeInnerHtmlDirective, selector: "[uxSafeInnerHtml]", inputs: ["uxSafeInnerHtml"] }, { kind: "component", type: i5.TypeaheadOptionsListComponent, selector: "ux-typeahead-options-list", inputs: ["id", "startIndex", "options", "highlighted", "activeKey", "disabledOptions", "isMultiselectable", "optionTemplate", "optionApi", "typeaheadElement", "ariaLabel"], outputs: ["optionMouseover", "optionMousedown", "optionClick"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TypeaheadComponent, decorators: [{ type: Component, args: [{ selector: 'ux-typeahead', providers: [TypeaheadService, PopoverOrientationService], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.open]': 'open', '[style.maxHeight]': 'maxHeight', }, template: "<div\n class=\"ux-typeahead-options\"\n [uxInfiniteScroll]=\"loadOptionsCallback\"\n [collection]=\"visibleOptions$ | async\"\n (collectionChange)=\"visibleOptions$.next($event)\"\n [enabled]=\"hasBeenOpened && isInfiniteScroll()\"\n [filter]=\"filter\"\n [loadOnScroll]=\"true\"\n [pageSize]=\"pageSize\"\n [scrollElement]=\"typeaheadElement\"\n (loading)=\"loading = true\"\n (loaded)=\"loading = false; onLoadedHighlight($event)\"\n >\n @if ((visibleRecentOptions$ | async).length > 0) {\n <div>\n <ng-container [ngTemplateOutlet]=\"recentOptionsHeadingTemplate\"></ng-container>\n </div>\n }\n\n <!-- Recent options -->\n @if ((visibleRecentOptions$ | async).length > 0) {\n <ux-typeahead-options-list\n class=\"ux-typeahead-recent-options\"\n [id]=\"id\"\n [options]=\"visibleRecentOptions$ | async\"\n [highlighted]=\"highlighted$ | async\"\n [activeKey]=\"activeKey\"\n [disabledOptions]=\"_disabledOptions\"\n [isMultiselectable]=\"multiselectable\"\n [optionTemplate]=\"optionTemplate || defaultOptionTemplate\"\n [optionApi]=\"optionApi\"\n [typeaheadElement]=\"typeaheadElement\"\n (optionMouseover)=\"highlight($event.option)\"\n (optionMousedown)=\"optionMousedownHandler($event.event)\"\n (optionClick)=\"optionClickHandler($event.event, $event.option)\"\n >\n </ux-typeahead-options-list>\n }\n\n <ng-container [ngTemplateOutlet]=\"optionsHeadingTemplate\"></ng-container>\n\n <!-- All options -->\n @if ((visibleOptions$ | async).length > 0) {\n <ux-typeahead-options-list\n class=\"ux-typeahead-all-options\"\n [id]=\"id\"\n [ariaLabel]=\"ariaLabel\"\n [startIndex]=\"(visibleRecentOptions$ | async).length\"\n [options]=\"visibleOptions$ | async\"\n [highlighted]=\"highlighted$ | async\"\n [activeKey]=\"activeKey\"\n [disabledOptions]=\"_disabledOptions\"\n [isMultiselectable]=\"multiselectable\"\n [optionTemplate]=\"optionTemplate || defaultOptionTemplate\"\n [optionApi]=\"optionApi\"\n [typeaheadElement]=\"typeaheadElement\"\n (optionMouseover)=\"highlight($event.option)\"\n (optionMousedown)=\"optionMousedownHandler($event.event)\"\n (optionClick)=\"optionClickHandler($event.event, $event.option)\"\n >\n </ux-typeahead-options-list>\n }\n\n <div *uxInfiniteScrollLoading>\n <ng-container [ngTemplateOutlet]=\"loadingTemplate || defaultLoadingTemplate\"></ng-container>\n </div>\n\n @if (isInfiniteScroll() === false && (visibleOptions$ | async).length === 0 && loading) {\n <div>\n <ng-container [ngTemplateOutlet]=\"loadingTemplate || defaultLoadingTemplate\"></ng-container>\n </div>\n }\n</div>\n@if ((visibleOptions$ | async).length === 0 && !loading) {\n <div>\n <ng-container [ngTemplateOutlet]=\"noOptionsTemplate || defaultNoOptionsTemplate\"> </ng-container>\n </div>\n}\n\n<ng-template #defaultLoadingTemplate>\n <div class=\"ux-typeahead-loading\">\n <div class=\"spinner spinner-accent spinner-bounce-middle\"></div>\n <div>Loading...</div>\n </div>\n</ng-template>\n\n<ng-template #defaultOptionTemplate let-option=\"option\" let-api=\"api\">\n <span class=\"ux-typeahead-option\" [uxSafeInnerHtml]=\"api.getDisplayHtml(option)\"></span>\n</ng-template>\n\n<ng-template #defaultNoOptionsTemplate>\n <span class=\"ux-typeahead-no-options\">No results</span>\n</ng-template>\n" }] }], ctorParameters: () => [], propDecorators: { infiniteScroll: [{ type: ViewChild, args: [InfiniteScrollDirective] }], id: [{ type: Input }, { type: HostBinding, args: ['attr.id'] }], options: [{ type: Input }], filter: [{ type: Input }], open: [{ type: Input }], display: [{ type: Input }], key: [{ type: Input }], disabledOptions: [{ type: Input }], dropDirection: [{ type: Input }], maxHeight: [{ type: Input }], multiselectable: [{ type: Input }], ariaLabel: [{ type: Input }], openOnFilterChange: [{ type: Input }], pageSize: [{ type: Input }], selectFirst: [{ type: Input }], selectOnEnter: [{ type: Input }], loading: [{ type: Input }], loadingTemplate: [{ type: Input }], optionTemplate: [{ type: Input }], noOptionsTemplate: [{ type: Input }], active: [{ type: Input }], recentOptions: [{ type: Input }], recentOptionsMaxCount: [{ type: Input }], recentOptionsHeadingTemplate: [{ type: Input }], optionsHeadingTemplate: [{ type: Input }], openChange: [{ type: Output }], optionSelected: [{ type: Output }], highlightedChange: [{ type: Output }], highlightedElementChange: [{ type: Output }], recentOptionsChange: [{ type: Output }], dropUp: [{ type: HostBinding, args: ['class.drop-up'] }], mousedownHandler: [{ type: HostListener, args: ['mousedown', ['$event', '$event.target']] }], mouseupHandler: [{ type: HostListener, args: ['mouseup'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWFoZWFkLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3R5cGVhaGVhZC90eXBlYWhlYWQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdHlwZWFoZWFkL3R5cGVhaGVhZC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDcEQsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osV0FBVyxFQUNYLFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUdMLE1BQU0sRUFHTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQy9ELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNqRSxPQUFPLEVBQ0wsdUJBQXVCLEdBR3hCLE1BQU0sd0NBQXdDLENBQUM7QUFDaEQsT0FBTyxFQUdMLHlCQUF5QixHQUMxQixNQUFNLGdFQUFnRSxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBSXpELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7Ozs7O0FBRXZELElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQztBQWFqQixNQUFNLE9BQU8sa0JBQWtCO0lBb0I3Qix1Q0FBdUM7SUFDdkMsSUFDSSxJQUFJO1FBQ04sT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUN4QyxDQUFDO0lBQ0QsSUFBSSxJQUFJLENBQUMsS0FBYztRQUNy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QkFHdEIsT0FBTztzQkFBZixLQUFLO2dCQUdHLE1BQU07c0JBQWQsS0FBSztnQkFJRixJQUFJO3NCQURQLEtBQUs7Z0JBU0csT0FBTztzQkFBZixLQUFLO2dCQUdHLEdBQUc7c0JBQVgsS0FBSztnQkFHTyxlQUFlO3NCQUEzQixLQUFLO2dCQVdHLGFBQWE7c0JBQXJCLEtBQUs7Z0JBSUYsU0FBUztzQkFEWixLQUFLO2dCQWNOLGVBQWU7c0JBRGQsS0FBSztnQkFLTixTQUFTO3NCQURSLEtBQUs7Z0JBSUcsa0JBQWtCO3NCQUExQixLQUFLO2dCQUdHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBR0csV0FBVztzQkFBbkIsS0FBSztnQkFHRyxhQUFhO3NCQUFyQixLQUFLO2dCQUdHLE9BQU87c0JBQWYsS0FBSztnQkFHRyxlQUFlO3NCQUF2QixLQUFLO2dCQUdHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBR0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUdPLE1BQU07c0JBQWxCLEtBQUs7Z0JBUUcsYUFBYTtzQkFBckIsS0FBSztnQkFHRyxxQkFBcUI7c0JBQTdCLEtBQUs7Z0JBRUcsNEJBQTRCO3NCQUFwQyxLQUFLO2dCQUVHLHNCQUFzQjtzQkFBOUIsS0FBSztnQkFHSSxVQUFVO3NCQUFuQixNQUFNO2dCQUdHLGNBQWM7c0JBQXZCLE1BQU07Z0JBR0csaUJBQWlCO3NCQUExQixNQUFNO2dCQUdHLHdCQUF3QjtzQkFBakMsTUFBTTtnQkFHRyxtQkFBbUI7c0JBQTVCLE1BQU07Z0JBMEJQLE1BQU07c0JBREwsV0FBVzt1QkFBQyxlQUFlO2dCQXNJNUIsZ0JBQWdCO3NCQURmLFlBQVk7dUJBQUMsV0FBVyxFQUFFLENBQUMsUUFBUSxFQUFFLGVBQWUsQ0FBQztnQkFvQnRELGNBQWM7c0JBRGIsWUFBWTt1QkFBQyxTQUFTIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRm9jdXNPcmlnaW4gfSBmcm9tICdAYW5ndWxhci9jZGsvYTExeSc7XHJcbmltcG9ydCB7IGNvZXJjZUFycmF5IH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2NvZXJjaW9uJztcclxuaW1wb3J0IHtcclxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcclxuICBDaGFuZ2VEZXRlY3RvclJlZixcclxuICBDb21wb25lbnQsXHJcbiAgRWxlbWVudFJlZixcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgSG9zdEJpbmRpbmcsXHJcbiAgSG9zdExpc3RlbmVyLFxyXG4gIGluamVjdCxcclxuICBJbnB1dCxcclxuICBPbkNoYW5nZXMsXHJcbiAgT25EZXN0cm95LFxyXG4gIE91dHB1dCxcclxuICBTaW1wbGVDaGFuZ2VzLFxyXG4gIFRlbXBsYXRlUmVmLFxyXG4gIFZpZXdDaGlsZCxcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IGRpc3RpbmN0VW50aWxDaGFuZ2VkLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XHJcbmltcG9ydCB7XHJcbiAgSW5maW5pdGVTY3JvbGxEaXJlY3RpdmUsXHJcbiAgSW5maW5pdGVTY3JvbGxMb2FkZWRFdmVudCxcclxuICBJbmZpbml0ZVNjcm9sbExvYWRGdW5jdGlvbixcclxufSBmcm9tICcuLi8uLi9kaXJlY3RpdmVzL2luZmluaXRlLXNjcm9sbC9pbmRleCc7XHJcbmltcG9ydCB7XHJcbiAgUG9wb3Zlck9yaWVudGF0aW9uLFxyXG4gIFBvcG92ZXJPcmllbnRhdGlvbkxpc3RlbmVyLFxyXG4gIFBvcG92ZXJPcmllbnRhdGlvblNlcnZpY2UsXHJcbn0gZnJvbSAnLi4vLi4vc2VydmljZXMvcG9wb3Zlci1vcmllbnRhdGlvbi9wb3BvdmVyLW9yaWVudGF0aW9uLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBUeXBlYWhlYWRPcHRpb25FdmVudCB9IGZyb20gJy4vdHlwZWFoZWFkLWV2ZW50JztcclxuaW1wb3J0IHsgVHlwZWFoZWFkT3B0aW9uQXBpIH0gZnJvbSAnLi90eXBlYWhlYWQtb3B0aW9uLWFwaSc7XHJcbmltcG9ydCB7IFR5cGVhaGVhZE9wdGlvbkNvbnRleHQgfSBmcm9tICcuL3R5cGVhaGVhZC1vcHRpb24tY29udGV4dCc7XHJcbmltcG9ydCB7IFR5cGVhaGVhZFZpc2libGVPcHRpb24gfSBmcm9tICcuL3R5cGVhaGVhZC12aXNpYmxlLW9wdGlvbic7XHJcbmltcG9ydCB7IFR5cGVhaGVhZFNlcnZpY2UgfSBmcm9tICcuL3R5cGVhaGVhZC5zZXJ2aWNlJztcclxuXHJcbmxldCB1bmlxdWVJZCA9IDA7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ3V4LXR5cGVhaGVhZCcsXHJcbiAgdGVtcGxhdGVVcmw6ICd0eXBlYWhlYWQuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHByb3ZpZGVyczogW1R5cGVhaGVhZFNlcnZpY2UsIFBvcG92ZXJPcmllbnRhdGlvblNlcnZpY2VdLFxyXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxyXG4gIGhvc3Q6IHtcclxuICAgICdbY2xhc3Mub3Blbl0nOiAnb3BlbicsXHJcbiAgICAnW3N0eWxlLm1heEhlaWdodF0nOiAnbWF4SGVpZ2h0JyxcclxuICB9LFxyXG59KVxyXG4gXHJcbmV4cG9ydCBjbGFzcyBUeXBlYWhlYWRDb21wb25lbnQ8VCA9IGFueT4gaW1wbGVtZW50cyBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XHJcbiAgcmVhZG9ubHkgdHlwZWFoZWFkRWxlbWVudCA9IGluamVjdChFbGVtZW50UmVmKTtcclxuXHJcbiAgcmVhZG9ubHkgcG9wb3Zlck9yaWVudGF0aW9uID0gaW5qZWN0KFBvcG92ZXJPcmllbnRhdGlvblNlcnZpY2UpO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IF9jaGFuZ2VEZXRlY3RvciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgX3NlcnZpY2UgPSBpbmplY3QoVHlwZWFoZWFkU2VydmljZSk7XHJcblxyXG4gIEBWaWV3Q2hpbGQoSW5maW5pdGVTY3JvbGxEaXJlY3RpdmUpIGluZmluaXRlU2Nyb2xsOiBJbmZpbml0ZVNjcm9sbERpcmVjdGl2ZTtcclxuXHJcbiAgLyoqIERlZmluZSBhIHVuaXF1ZSBpZCBmb3IgdGhlIHR5cGVhaGVhZCAqL1xyXG4gIEBJbnB1dCgpIEBIb3N0Qmlu