UNPKG

carbon-components-angular

Version:
1,030 lines 99.9 kB
import { Component, ContentChild, Input, Output, HostListener, ViewChild, EventEmitter, HostBinding, TemplateRef } from "@angular/core"; import { AbstractDropdownView } from "carbon-components-angular/dropdown"; import { NG_VALUE_ACCESSOR } from "@angular/forms"; import { filter } from "rxjs/operators"; import { getScrollableParents, hasScrollableParents } from "carbon-components-angular/utils"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/dropdown"; import * as i2 from "carbon-components-angular/i18n"; import * as i3 from "@angular/common"; import * as i4 from "carbon-components-angular/icon"; /** * Get started with importing the module: * * ```typescript * import { ComboBoxModule } from 'carbon-components-angular'; * ``` * * ComboBoxes are similar to dropdowns, except a combobox provides an input field for users to search items and (optionally) add their own. * Multi-select comboboxes also provide "pills" of selected items. * * [See demo](../../?path=/story/components-combobox--basic) */ export class ComboBox { /** * Creates an instance of ComboBox. */ constructor(elementRef, dropdownService, i18n) { this.elementRef = elementRef; this.dropdownService = dropdownService; this.i18n = i18n; this.id = `dropdown-${ComboBox.comboBoxCount++}`; this.labelId = `dropdown-label-${ComboBox.comboBoxCount++}`; /** * List of items to fill the content with. * * **Example:** * ```javascript * items = [ * { * content: "Abacus", * selected: false * }, * { * content: "Byte", * selected: false, * }, * { * content: "Computer", * selected: false * }, * { * content: "Digital", * selected: false * } * ]; * ``` * */ this.items = []; /** * Combo box type (supporting single or multi selection of items). */ this.type = "single"; /** * Combo box render size. */ this.size = "md"; /** * Hide label while keeping it accessible for screen readers */ this.hideLabel = false; /** * set to `true` to place the dropdown view inline with the component */ this.appendInline = null; /** * Set to `true` to show the invalid state. */ this.invalid = false; /** * Set to `true` to show a warning (contents set by warnText) */ this.warn = false; /** * Max length value to limit input characters */ this.maxLength = null; /** * @deprecated since v5 - Use `cdsLayer` directive instead */ this.theme = "dark"; /** * Specify feedback (mode) of the selection. * `top`: selected item jumps to top * `fixed`: selected item stays at its position * `top-after-reopen`: selected item jump to top after reopen dropdown */ this.selectionFeedback = "top-after-reopen"; /** * Specify aria-autocomplete attribute of text input. * "list", is the expected value for a combobox that invokes a drop-down list */ this.autocomplete = "list"; /** * Set to `true` to disable combobox. */ this.disabled = false; /** * Emits a ListItem * * Example: * ```javascript * { * content: "one", * selected: true * } * ``` */ this.selected = new EventEmitter(); /** * Intended to be used to add items to the list. * * Emits an event that includes the current item list, the suggested index for the new item, and a simple ListItem * * Example: * ```javascript * { * items: [{content: "one", selected: true}, {content: "two", selected: true}], * index: 1, * value: { * content: "some user string", * selected: false * } * } * ``` * * * Example: * ```javascript * { * after: 1, * value: "some user string" * } * ``` */ this.submit = new EventEmitter(); /** Emits an empty event when the menu is closed */ this.close = new EventEmitter(); /** Emits the search string from the input */ this.search = new EventEmitter(); /** Emits an event when the clear button is clicked. */ this.clear = new EventEmitter(); this.hostClass = true; this.display = "block"; this.open = false; this.showClearButton = false; /** Selected items for multi-select combo-boxes. */ this.pills = []; /** used to update the displayValue */ this.selectedValue = ""; this.outsideClick = this._outsideClick.bind(this); this.keyboardNav = this._keyboardNav.bind(this); /** * controls whether the `drop-up` class is applied */ this._dropUp = false; this.noop = this._noop.bind(this); this.onTouchedCallback = this._noop; this.propagateChangeCallback = this._noop; this._placeholder = this.i18n.getOverridable("COMBOBOX.PLACEHOLDER"); this._closeMenuAria = this.i18n.getOverridable("COMBOBOX.A11Y.CLOSE_MENU"); this._openMenuAria = this.i18n.getOverridable("COMBOBOX.A11Y.OPEN_MENU"); this._clearSelectionsTitle = this.i18n.getOverridable("COMBOBOX.CLEAR_SELECTIONS"); this._clearSelectionsAria = this.i18n.getOverridable("COMBOBOX.A11Y.CLEAR_SELECTIONS"); this._clearSelectionTitle = this.i18n.getOverridable("COMBOBOX.CLEAR_SELECTED"); this._clearSelectionAria = this.i18n.getOverridable("COMBOBOX.A11Y.CLEAR_SELECTED"); } /** * Text to show when nothing is selected. */ set placeholder(value) { this._placeholder.override(value); } get placeholder() { return this._placeholder.value; } /** * Value to display for accessibility purposes on the combobox control menu when closed */ set openMenuAria(value) { this._openMenuAria.override(value); } get openMenuAria() { return this._openMenuAria.value; } /** * Value to display for accessibility purposes on the combobox control menu when opened */ set closeMenuAria(value) { this._closeMenuAria.override(value); } get closeMenuAria() { return this._closeMenuAria.value; } /** * Value to display on the clear selections icon, when multi is selected */ set clearSelectionsTitle(value) { this._clearSelectionsTitle.override(value); } get clearSelectionsTitle() { return this._clearSelectionsTitle.value; } /** * Value to display for accessibility purposes to clear selections, when multi is selected */ set clearSelectionsAria(value) { this._clearSelectionsAria.override(value); } get clearSelectionsAria() { return this._clearSelectionsAria.value; } /** * Value to display on the clear the selected item icon, when single is selected */ set clearSelectionTitle(value) { this._clearSelectionTitle.override(value); } get clearSelectionTitle() { return this._clearSelectionTitle.value; } /** * Value to display for accessibility purposes on the clear the selected item icon, when single is selected */ set clearSelectionAria(value) { this._clearSelectionAria.override(value); } get clearSelectionAria() { return this._clearSelectionAria.value; } /** * Lifecycle hook. * Updates pills if necessary. * */ ngOnChanges(changes) { if (changes.items) { this.view.items = changes.items.currentValue; this.updateSelected(); // If new items are added into the combobox while there is search input, // repeat the search. Search should only trigger for type 'single' when there is no value selected. if (this.type === "multi" || (this.type === "single" && !this.selectedValue)) { this.onSearch(this.input.nativeElement.value, false); } } } /** * Sets initial state that depends on child components * Subscribes to select events and handles focus/filtering/initial list updates */ ngAfterContentInit() { if (this.view) { this.view.type = this.type; // function to check if the event is organic (isUpdate === false) or programmatic const isUpdate = event => event && event.isUpdate; this.view.select.subscribe(event => { if (Array.isArray(event)) { this.updatePills(); if (!isUpdate(event)) { if (this.itemValueKey && this.view.getSelected()) { const values = this.view.getSelected().map(item => item[this.itemValueKey]); this.propagateChangeCallback(values); // otherwise just pass up the values from `getSelected` } else { this.propagateChangeCallback(this.view.getSelected()); } this.selected.emit(event); } } else { // If type is single, dropdown list will emit an object if (event.item && event.item.selected) { this.showClearButton = true; this.selectedValue = event.item.content; if (!isUpdate(event)) { if (this.itemValueKey) { this.propagateChangeCallback(event.item[this.itemValueKey]); } else { this.propagateChangeCallback(event.item); } } } else { this.selectedValue = ""; if (!isUpdate(event)) { this.propagateChangeCallback(null); } } // not guarding these since the nativeElement has to be loaded // for select to even fire // only focus for "organic" selections if (!isUpdate(event)) { this.elementRef.nativeElement.querySelector("input").focus(); this.view.filterBy(""); this.selected.emit(event.item); } this.closeDropdown(); } }); // update the rest of combobox with any pre-selected items // setTimeout just defers the call to the next check cycle setTimeout(() => { this.updateSelected(); }); this.view.blurIntent.pipe(filter(v => v === "top")).subscribe(() => { this.elementRef.nativeElement.querySelector(".cds--text-input").focus(); }); } } /** * Binds event handlers against the rendered view */ ngAfterViewInit() { // if appendInline is default valued (null) we should: // 1. if there are scrollable parents (not including body) don't append inline // this should also cover the case where the dropdown is in a modal // (where we _do_ want to append to the placeholder) if (this.appendInline === null && hasScrollableParents(this.elementRef.nativeElement)) { this.appendInline = false; // 2. otherwise we should append inline } else if (this.appendInline === null) { this.appendInline = true; } } /** * Removing the `Dropdown` from the body if it is appended to the body. */ ngOnDestroy() { if (!this.appendInline) { this._appendToDropdown(); } } /** * Handles `Escape/Tab` key closing the dropdown, and arrow up/down focus to/from the dropdown list. */ hostkeys(ev) { if (ev.key === "Escape") { this.closeDropdown(); } else if ((ev.key === "ArrowDown") && (!this.dropdownMenu || !this.dropdownMenu.nativeElement.contains(ev.target))) { ev.preventDefault(); this.openDropdown(); setTimeout(() => { this.view.initFocus(); }, 0); } if (this.open && ev.key === "Tab" && (this.dropdownMenu.nativeElement.contains(ev.target) || ev.target === this.input.nativeElement)) { this.closeDropdown(); } if (this.open && ev.key === "Tab" && ev.shiftKey) { this.closeDropdown(); } } /* * no-op method for null event listeners, and other no op calls */ _noop() { } /* * propagates the value provided from ngModel */ writeValue(value) { if (this.type === "single") { if (this.itemValueKey) { // clone the specified item and update its state const newValue = Object.assign({}, this.view.getListItems().find(item => item[this.itemValueKey] === value)); newValue.selected = true; this.view.propagateSelected([newValue]); } else { // all items in propagateSelected must be iterable this.view.propagateSelected([value || ""]); } this.showClearButton = !!(value && this.view.getSelected().length); } else { if (this.itemValueKey) { // clone the items and update their state based on the received value array // this way we don't lose any additional metadata that may be passed in via the `items` Input let newValues = []; for (const v of value) { for (const item of this.view.getListItems()) { if (item[this.itemValueKey] === v) { newValues.push(Object.assign({}, item, { selected: true })); } } } this.view.propagateSelected(newValues); } else { this.view.propagateSelected(value ? value : [""]); } } this.updateSelected(); } onBlur() { this.onTouchedCallback(); } registerOnChange(fn) { this.propagateChangeCallback = fn; } registerOnTouched(fn) { this.onTouchedCallback = fn; } /** * `ControlValueAccessor` method to programmatically disable the combobox. * * ex: `this.formGroup.get("myCoolCombobox").disable();` */ setDisabledState(isDisabled) { this.disabled = isDisabled; } /** * Called by `n-pill-input` when the selected pills have changed. */ updatePills() { this.pills = this.view.getSelected() || []; this.checkForReorder(); } clearSelected(event) { this.items = this.items.map(item => { if (!item.disabled) { item.selected = false; } return item; }); this.view.items = this.items; this.updatePills(); // clearSelected can only fire on type=multi // so we just emit getSelected() (just in case there's any disabled but selected items) const selected = this.view.getSelected(); this.propagateChangeCallback(selected); this.selected.emit(selected); this.clear.emit(event); } /** * Closes the dropdown and emits the close event. */ closeDropdown() { this.open = false; this.checkForReorder(); this.close.emit(); if (!this.appendInline) { this._appendToDropdown(); } document.removeEventListener("click", this.outsideClick, true); } /** * Opens the dropdown. */ openDropdown() { if (this.disabled) { return; } this.open = true; this._dropUp = false; if (!this.appendInline) { this._appendToBody(); } document.addEventListener("click", this.outsideClick, true); // set the dropdown menu to drop up if it is near the bottom of the screen // setTimeout lets us do the calculations after it is visible in the DOM setTimeout(() => { if (this.dropUp === null || this.dropUp === undefined) { this._dropUp = this._shouldDropUp(); } }, 0); } /** * Toggles the dropdown. */ toggleDropdown() { if (this.open) { this.closeDropdown(); } else { this.openDropdown(); } } /** * Sets the list group filter, and manages single select item selection. */ onSearch(searchString, shouldEmitSearch = true) { if (shouldEmitSearch) { this.search.emit(searchString); } this.showClearButton = !!searchString; this.view.filterBy(searchString); if (searchString !== "") { if (!this.open) { this.openDropdown(); } } else { this.selectedValue = ""; if (this.type === "multi" && (this.selectionFeedback === "top" || this.selectionFeedback === "top-after-reopen")) { this.view.reorderSelected(); } } if (this.type === "single") { // deselect if the input doesn't match the content // of any given item const matches = this.view.getListItems().some(item => item.content.toLowerCase().includes(searchString.toLowerCase())); if (!matches) { const selected = this.view.getSelected(); if (!selected || !selected[0]) { this.view.filterBy(searchString); } } } } /** * Intended to be used to add items to the list. */ onSubmit(event) { this.submit.emit({ items: this.view.getListItems(), index: 0, value: { content: event.target.value, selected: false } }); } clearInput(event) { event.stopPropagation(); event.preventDefault(); if (this.disabled) { return; } if (this.type === "single") { // don't want to clear selected or close if multi this.clearSelected(event); this.closeDropdown(); } this.selectedValue = ""; this.input.nativeElement.value = ""; this.showClearButton = false; this.input.nativeElement.focus(); this.onSearch(this.input.nativeElement.value); } isTemplate(value) { return value instanceof TemplateRef; } /** * Handles keyboard events so users are controlling the `Dropdown` instead of unintentionally controlling outside elements. */ _keyboardNav(event) { if ((event.key === "Escape") && this.open) { event.stopImmediatePropagation(); // don't unintentionally close modal if inside of it } if (event.key === "Escape") { event.preventDefault(); this.closeDropdown(); this.input.nativeElement.focus(); } else if (this.open && event.key === "Tab") { // this way focus will start on the next focusable item from the dropdown // not the top of the body! this.input.nativeElement.focus(); this.input.nativeElement.dispatchEvent(new KeyboardEvent("keydown", { bubbles: true, cancelable: true, key: "Tab" })); this.closeDropdown(); } } /** * Creates the `Dropdown` list as an element that is appended to the DOM body. */ _appendToBody() { this.dropdownService.appendToBody(this.listbox.nativeElement, this.dropdownMenu.nativeElement, `${this.elementRef.nativeElement.className}${this.open ? " cds--list-box--expanded" : ""}`); this.dropdownMenu.nativeElement.addEventListener("keydown", this.keyboardNav, true); } /** * Creates the `Dropdown` list appending it to the dropdown parent object instead of the body. */ _appendToDropdown() { this.dropdownService.appendToDropdown(this.elementRef.nativeElement); this.dropdownMenu.nativeElement.removeEventListener("keydown", this.keyboardNav, true); } /** * Detects whether or not the `Dropdown` list is visible within all scrollable parents. * This can be overridden by passing in a value to the `dropUp` input. */ _shouldDropUp() { // check if dropdownMenu exists first. const menu = this.dropdownMenu && this.dropdownMenu.nativeElement.querySelector(".cds--list-box__menu"); // check if menu exists first. const menuRect = menu && menu.getBoundingClientRect(); if (menu && menuRect) { const scrollableParents = getScrollableParents(menu); return scrollableParents.reduce((shouldDropUp, parent) => { const parentRect = parent.getBoundingClientRect(); const isBelowParent = !(menuRect.bottom <= parentRect.bottom); return shouldDropUp || isBelowParent; }, false); } return false; } /** * Handles clicks outside of the `Dropdown` list. */ _outsideClick(event) { if (!this.elementRef.nativeElement.contains(event.target) && // if we're appendToBody the list isn't within the _elementRef, // so we've got to check if our target is possibly in there too. !this.dropdownMenu.nativeElement.contains(event.target)) { this.closeDropdown(); } } updateSelected() { const selected = this.view.getSelected(); if (this.type === "multi") { this.updatePills(); } else if (selected) { const value = selected[0] ? selected[0].content : ""; const changeCallbackValue = selected[0] ? selected[0] : ""; this.selectedValue = value; this.showClearButton = !!value; } } checkForReorder() { const topAfterReopen = !this.open && this.selectionFeedback === "top-after-reopen"; if ((this.type === "multi") && (topAfterReopen || this.selectionFeedback === "top")) { this.view.reorderSelected(true); } } } ComboBox.comboBoxCount = 0; ComboBox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ComboBox, deps: [{ token: i0.ElementRef }, { token: i1.DropdownService }, { token: i2.I18n }], target: i0.ɵɵFactoryTarget.Component }); ComboBox.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: ComboBox, selector: "cds-combo-box, ibm-combo-box", inputs: { placeholder: "placeholder", openMenuAria: "openMenuAria", closeMenuAria: "closeMenuAria", clearSelectionsTitle: "clearSelectionsTitle", clearSelectionsAria: "clearSelectionsAria", clearSelectionTitle: "clearSelectionTitle", clearSelectionAria: "clearSelectionAria", id: "id", labelId: "labelId", items: "items", type: "type", size: "size", itemValueKey: "itemValueKey", label: "label", hideLabel: "hideLabel", helperText: "helperText", appendInline: "appendInline", invalid: "invalid", invalidText: "invalidText", warn: "warn", warnText: "warnText", maxLength: "maxLength", theme: "theme", selectionFeedback: "selectionFeedback", autocomplete: "autocomplete", dropUp: "dropUp", disabled: "disabled" }, outputs: { selected: "selected", submit: "submit", close: "close", search: "search", clear: "clear" }, host: { listeners: { "keydown": "hostkeys($event)" }, properties: { "class.cds--list-box__wrapper": "this.hostClass", "style.display": "this.display" } }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: ComboBox, multi: true } ], queries: [{ propertyName: "view", first: true, predicate: AbstractDropdownView, descendants: true, static: true }], viewQueries: [{ propertyName: "dropdownMenu", first: true, predicate: ["dropdownMenu"], descendants: true }, { propertyName: "input", first: true, predicate: ["input"], descendants: true, static: true }, { propertyName: "listbox", first: true, predicate: ["listbox"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: ` <div class="cds--list-box__wrapper"> <label *ngIf="label" [for]="id" [id]="labelId" class="cds--label" [ngClass]="{ 'cds--label--disabled': disabled, 'cds--visually-hidden': hideLabel }"> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label"></ng-template> </label> <div #listbox [ngClass]="{ 'cds--multi-select cds--multi-select--filterable': type === 'multi', 'cds--list-box--light': theme === 'light', 'cds--list-box--expanded': open, 'cds--list-box--sm': size === 'sm', 'cds--list-box--md': size === 'md', 'cds--list-box--lg': size === 'lg', 'cds--list-box--disabled': disabled, 'cds--combo-box--warning cds--list-box--warning': warn }" class="cds--list-box cds--combo-box" [attr.data-invalid]="(invalid ? true : null)"> <div class="cds--list-box__field" (click)="toggleDropdown()" (blur)="onBlur()"> <div *ngIf="type === 'multi' && pills.length > 0" class="cds--tag cds--tag--filter cds--tag--high-contrast" [ngClass]="{'cds--tag--disabled': disabled}"> <span class="cds--tag__label">{{ pills.length }}</span> <button type="button" (click)="clearSelected($event)" (blur)="onBlur()" (keydown.enter)="clearSelected($event)" class="cds--tag__close-icon" tabindex="0" [title]="clearSelectionsTitle" [disabled]="disabled" [attr.aria-label]="clearSelectionAria"> <svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" role="img" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"> <path d="M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8z"></path> </svg> </button> </div> <input #input type="text" autocomplete="off" role="combobox" [disabled]="disabled" (input)="onSearch($event.target.value)" (blur)="onBlur()" (keydown.enter)="onSubmit($event)" [value]="selectedValue" class="cds--text-input" [ngClass]="{'cds--text-input--empty': !showClearButton}" tabindex="0" [id]="id" [attr.aria-labelledby]="labelId" [attr.aria-expanded]="open" aria-haspopup="listbox" [attr.maxlength]="maxLength" [attr.aria-controls]="open ? view?.listId : null" [attr.aria-autocomplete]="autocomplete" [placeholder]="placeholder"/> <svg *ngIf="invalid" cdsIcon="warning--filled" size="16" class="cds--list-box__invalid-icon"> </svg> <svg *ngIf="!invalid && warn" cdsIcon="warning--alt--filled" size="16" class="cds--list-box__invalid-icon cds--list-box__invalid-icon--warning"> </svg> <div *ngIf="showClearButton" role="button" class="cds--list-box__selection" tabindex="0" [attr.aria-label]="clearSelectionAria" [title]="clearSelectionTitle" (keyup.enter)="clearInput($event)" (click)="clearInput($event)" (blur)="onBlur()"> <svg cdsIcon="close" size="16"></svg> </div> <button type="button" role="button" class="cds--list-box__menu-icon" tabindex="-1" [title]="open ? closeMenuAria : openMenuAria" [attr.aria-label]="open ? closeMenuAria : openMenuAria" [ngClass]="{'cds--list-box__menu-icon--open': open}"> <svg cdsIcon="chevron--down" size="16"></svg> </button> </div> <div #dropdownMenu [ngClass]="{ 'cds--list-box--up': this.dropUp !== null && this.dropUp !== undefined ? dropUp : _dropUp }"> <ng-content *ngIf="open"></ng-content> </div> </div> <div *ngIf="helperText && !invalid && !warn" class="cds--form__helper-text" [ngClass]="{'cds--form__helper-text--disabled': disabled}"> <ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container> <ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template> </div> <div *ngIf="invalid" class="cds--form-requirement"> <ng-container *ngIf="!isTemplate(invalidText)">{{ invalidText }}</ng-container> <ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template> </div> <div *ngIf="!invalid && warn" class="cds--form-requirement"> <ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container> <ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template> </div> </div> `, isInline: true, dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i4.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ComboBox, decorators: [{ type: Component, args: [{ selector: "cds-combo-box, ibm-combo-box", template: ` <div class="cds--list-box__wrapper"> <label *ngIf="label" [for]="id" [id]="labelId" class="cds--label" [ngClass]="{ 'cds--label--disabled': disabled, 'cds--visually-hidden': hideLabel }"> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label"></ng-template> </label> <div #listbox [ngClass]="{ 'cds--multi-select cds--multi-select--filterable': type === 'multi', 'cds--list-box--light': theme === 'light', 'cds--list-box--expanded': open, 'cds--list-box--sm': size === 'sm', 'cds--list-box--md': size === 'md', 'cds--list-box--lg': size === 'lg', 'cds--list-box--disabled': disabled, 'cds--combo-box--warning cds--list-box--warning': warn }" class="cds--list-box cds--combo-box" [attr.data-invalid]="(invalid ? true : null)"> <div class="cds--list-box__field" (click)="toggleDropdown()" (blur)="onBlur()"> <div *ngIf="type === 'multi' && pills.length > 0" class="cds--tag cds--tag--filter cds--tag--high-contrast" [ngClass]="{'cds--tag--disabled': disabled}"> <span class="cds--tag__label">{{ pills.length }}</span> <button type="button" (click)="clearSelected($event)" (blur)="onBlur()" (keydown.enter)="clearSelected($event)" class="cds--tag__close-icon" tabindex="0" [title]="clearSelectionsTitle" [disabled]="disabled" [attr.aria-label]="clearSelectionAria"> <svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" role="img" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"> <path d="M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8z"></path> </svg> </button> </div> <input #input type="text" autocomplete="off" role="combobox" [disabled]="disabled" (input)="onSearch($event.target.value)" (blur)="onBlur()" (keydown.enter)="onSubmit($event)" [value]="selectedValue" class="cds--text-input" [ngClass]="{'cds--text-input--empty': !showClearButton}" tabindex="0" [id]="id" [attr.aria-labelledby]="labelId" [attr.aria-expanded]="open" aria-haspopup="listbox" [attr.maxlength]="maxLength" [attr.aria-controls]="open ? view?.listId : null" [attr.aria-autocomplete]="autocomplete" [placeholder]="placeholder"/> <svg *ngIf="invalid" cdsIcon="warning--filled" size="16" class="cds--list-box__invalid-icon"> </svg> <svg *ngIf="!invalid && warn" cdsIcon="warning--alt--filled" size="16" class="cds--list-box__invalid-icon cds--list-box__invalid-icon--warning"> </svg> <div *ngIf="showClearButton" role="button" class="cds--list-box__selection" tabindex="0" [attr.aria-label]="clearSelectionAria" [title]="clearSelectionTitle" (keyup.enter)="clearInput($event)" (click)="clearInput($event)" (blur)="onBlur()"> <svg cdsIcon="close" size="16"></svg> </div> <button type="button" role="button" class="cds--list-box__menu-icon" tabindex="-1" [title]="open ? closeMenuAria : openMenuAria" [attr.aria-label]="open ? closeMenuAria : openMenuAria" [ngClass]="{'cds--list-box__menu-icon--open': open}"> <svg cdsIcon="chevron--down" size="16"></svg> </button> </div> <div #dropdownMenu [ngClass]="{ 'cds--list-box--up': this.dropUp !== null && this.dropUp !== undefined ? dropUp : _dropUp }"> <ng-content *ngIf="open"></ng-content> </div> </div> <div *ngIf="helperText && !invalid && !warn" class="cds--form__helper-text" [ngClass]="{'cds--form__helper-text--disabled': disabled}"> <ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container> <ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template> </div> <div *ngIf="invalid" class="cds--form-requirement"> <ng-container *ngIf="!isTemplate(invalidText)">{{ invalidText }}</ng-container> <ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template> </div> <div *ngIf="!invalid && warn" class="cds--form-requirement"> <ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container> <ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template> </div> </div> `, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: ComboBox, multi: true } ] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.DropdownService }, { type: i2.I18n }]; }, propDecorators: { placeholder: [{ type: Input }], openMenuAria: [{ type: Input }], closeMenuAria: [{ type: Input }], clearSelectionsTitle: [{ type: Input }], clearSelectionsAria: [{ type: Input }], clearSelectionTitle: [{ type: Input }], clearSelectionAria: [{ type: Input }], id: [{ type: Input }], labelId: [{ type: Input }], items: [{ type: Input }], type: [{ type: Input }], size: [{ type: Input }], itemValueKey: [{ type: Input }], label: [{ type: Input }], hideLabel: [{ type: Input }], helperText: [{ type: Input }], appendInline: [{ type: Input }], invalid: [{ type: Input }], invalidText: [{ type: Input }], warn: [{ type: Input }], warnText: [{ type: Input }], maxLength: [{ type: Input }], theme: [{ type: Input }], selectionFeedback: [{ type: Input }], autocomplete: [{ type: Input }], dropUp: [{ type: Input }], disabled: [{ type: Input }], selected: [{ type: Output }], submit: [{ type: Output }], close: [{ type: Output }], search: [{ type: Output }], clear: [{ type: Output }], view: [{ type: ContentChild, args: [AbstractDropdownView, { static: true }] }], dropdownMenu: [{ type: ViewChild, args: ["dropdownMenu"] }], input: [{ type: ViewChild, args: ["input", { static: true }] }], listbox: [{ type: ViewChild, args: ["listbox", { static: true }] }], hostClass: [{ type: HostBinding, args: ["class.cds--list-box__wrapper"] }], display: [{ type: HostBinding, args: ["style.display"] }], hostkeys: [{ type: HostListener, args: ["keydown", ["$event"]] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tYm9ib3guY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbWJvYm94L2NvbWJvYm94LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUVULFlBQVksRUFDWixLQUFLLEVBQ0wsTUFBTSxFQUNOLFlBQVksRUFFWixTQUFTLEVBQ1QsWUFBWSxFQUdaLFdBQVcsRUFDWCxXQUFXLEVBRVgsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLG9CQUFvQixFQUFtQixNQUFNLG9DQUFvQyxDQUFDO0FBRTNGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QyxPQUFPLEVBQ04sb0JBQW9CLEVBQ3BCLG9CQUFvQixFQUNwQixNQUFNLGlDQUFpQyxDQUFDOzs7Ozs7QUFJekM7Ozs7Ozs7Ozs7O0dBV0c7QUF5SkgsTUFBTSxPQUFPLFFBQVE7SUFxUXBCOztPQUVHO0lBQ0gsWUFDVyxVQUFzQixFQUN0QixlQUFnQyxFQUNoQyxJQUFVO1FBRlYsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQUN0QixvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsU0FBSSxHQUFKLElBQUksQ0FBTTtRQW5NWixPQUFFLEdBQUcsWUFBWSxRQUFRLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQztRQUM1QyxZQUFPLEdBQUcsa0JBQWtCLFFBQVEsQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1FBQ2hFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O1dBeUJHO1FBQ00sVUFBSyxHQUFvQixFQUFFLENBQUM7UUFDckM7O1dBRUc7UUFDTSxTQUFJLEdBQXVCLFFBQVEsQ0FBQztRQUM3Qzs7V0FFRztRQUNNLFNBQUksR0FBdUIsSUFBSSxDQUFDO1FBU3pDOztXQUVHO1FBQ00sY0FBUyxHQUFH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