UNPKG

carbon-components-angular

Version:
915 lines 93.4 kB
import { Component, Input, Output, EventEmitter, ContentChild, ViewChild, HostListener, HostBinding, TemplateRef } from "@angular/core"; import { NG_VALUE_ACCESSOR } from "@angular/forms"; // Observable import is required here so typescript can compile correctly import { of, Subscription } from "rxjs"; import { AbstractDropdownView } from "./abstract-dropdown-view.class"; import { getScrollableParents } from "carbon-components-angular/utils"; import { hasScrollableParents } from "carbon-components-angular/utils"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/i18n"; import * as i2 from "./dropdown.service"; import * as i3 from "carbon-components-angular/utils"; import * as i4 from "@angular/common"; import * as i5 from "carbon-components-angular/icon"; /** * Drop-down lists enable users to select one or more items from a list. * * #### Opening behavior/List DOM placement * By default the dropdown will try to figure out the best placement for the dropdown list. * * If it's not contained within any scrolling elements, it will open inline, if it _is_ * contained within a scrolling container it will try to open in the body, or an `cds-placeholder`. * * To control this behavior you can use the `appendInline` input: * - `[appendInline]="null"` is the default (auto detection) * - `[appendInline]="false"` will always append to the body/`cds-placeholder` * - `[appendInline]="true"` will always append inline (next to the dropdown button) * * Get started with importing the module: * * ```typescript * import { DropdownModule } from 'carbon-components-angular'; * ``` * * [See demo](../../?path=/story/components-dropdown--basic) */ export class Dropdown { /** * Creates an instance of Dropdown. */ constructor(elementRef, i18n, dropdownService, elementService) { this.elementRef = elementRef; this.i18n = i18n; this.dropdownService = dropdownService; this.elementService = elementService; this.id = `dropdown-${Dropdown.dropdownCount++}`; /** * Hide label while keeping it accessible for screen readers */ this.hideLabel = false; /** * Value displayed if no item is selected. */ this.placeholder = ""; /** * The selected value from the `Dropdown`. Can be a string or template. */ this.displayValue = ""; /** * Sets the optional clear button tooltip text. */ this.clearText = this.i18n.get().DROPDOWN.CLEAR; /** * Size to render the dropdown field. */ this.size = "md"; /** * Defines whether or not the `Dropdown` supports selecting multiple items as opposed to single * item selection. */ this.type = "single"; /** * @deprecated since v5 - Use `cdsLayer` directive instead * `light` or `dark` dropdown theme */ this.theme = "dark"; /** * Set to `true` to disable the dropdown. */ this.disabled = false; /** * Set to `true` for a loading dropdown. */ this.skeleton = false; /** * Set to `true` for an inline dropdown. */ this.inline = false; /** * Set to `true` for a dropdown without arrow key activation. */ this.disableArrowKeys = false; /** * Set to `true` for invalid state. */ this.invalid = false; /** * Set to `true` to show a warning (contents set by warningText) */ this.warn = false; /** * set to `true` to place the dropdown view inline with the component */ this.appendInline = null; /** * Specify feedback (mode) of the selection. * `top`: selected item jumps to top * `fixed`: selected item stays at it's position * `top-after-reopen`: selected item jump to top after reopen dropdown */ this.selectionFeedback = "top-after-reopen"; /** * Accessible label for the button that opens the dropdown list. * Defaults to the `DROPDOWN.OPEN` value from the i18n service. */ this.menuButtonLabel = this.i18n.get().DROPDOWN.OPEN; /** * Provides the label for the "# selected" text. * Defaults to the `DROPDOWN.SELECTED` value from the i18n service. */ this.selectedLabel = this.i18n.get().DROPDOWN.SELECTED; /** * Emits selection events. */ this.selected = new EventEmitter(); /** * Emits event notifying to other classes that the `Dropdown` has been closed (collapsed). */ this.onClose = new EventEmitter(); /** * Emits event notifying to other classes that the `Dropdown` has been closed (collapsed). */ this.close = new EventEmitter(); this.hostClass = true; /** * Set to `true` if the dropdown is closed (not expanded). */ this.menuIsClosed = true; /** * controls whether the `drop-up` class is applied */ this._dropUp = false; // .bind creates a new function, so we declare the methods below // but .bind them up here this.noop = this._noop.bind(this); this.outsideClick = this._outsideClick.bind(this); this.outsideKey = this._outsideKey.bind(this); this.keyboardNav = this._keyboardNav.bind(this); this.visibilitySubscription = new Subscription(); this.onTouchedCallback = this._noop; // primarily used to capture and propagate input to `writeValue` before the content is available this._writtenValue = []; /** * function passed in by `registerOnChange` */ this.propagateChange = (_) => { }; } get writtenValue() { return this._writtenValue; } set writtenValue(val) { if (val && val.length === 0) { this.clearSelected(); } this._writtenValue = val; } /** * Updates the `type` property in the `@ContentChild`. * The `type` property specifies whether the `Dropdown` allows single selection or multi selection. */ ngOnInit() { if (this.view) { this.view.type = this.type; } } /** * Initializes classes and subscribes to events for single or multi selection. */ ngAfterContentInit() { if (!this.view) { return; } if ((this.writtenValue && this.writtenValue.length) || typeof this.writtenValue === "number") { this.writeValue(this.writtenValue); } this.view.type = this.type; this.view.size = this.size; // function to check if the event is organic (isUpdate === false) or programmatic const isUpdate = event => event && event.isUpdate; this.view.select.subscribe(event => { if (this.type === "single" && !isUpdate(event) && !Array.isArray(event)) { this.closeMenu(); if (event.item && event.item.selected) { if (this.itemValueKey) { this.propagateChange(event.item[this.itemValueKey]); } else { this.propagateChange(event.item); } } else { this.propagateChange(null); } } if (this.type === "multi" && !isUpdate(event)) { // if we have a `value` selector and selected items map them appropriately if (this.itemValueKey && this.view.getSelected()) { const values = this.view.getSelected().map(item => item[this.itemValueKey]); this.propagateChange(values); // otherwise just pass up the values from `getSelected` } else { this.propagateChange(this.view.getSelected()); } } // only emit selected for "organic" selections if (!isUpdate(event)) { this.checkForReorder(); this.selected.emit(event); } }); } 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; } this.checkForReorder(); } /** * Removing the `Dropdown` from the body if it is appended to the body. */ ngOnDestroy() { if (!this.appendInline) { this._appendToDropdown(); } } /** * Propagates the injected `value`. */ writeValue(value) { // cache the written value so we can use it in `AfterContentInit` this.writtenValue = value; this.view.onItemsReady(() => { // propagate null/falsey as an array (deselect everything) if (!value) { this.view.propagateSelected([value]); } else 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 { // pass the singular value as an array of ListItem this.view.propagateSelected([value]); } } 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 { // we can safely assume we're passing an array of `ListItem`s this.view.propagateSelected(value); } } this.checkForReorder(); }); } onBlur() { this.onTouchedCallback(); } registerOnChange(fn) { this.propagateChange = fn; } /** * Registering the function injected to control the touch use of the `Dropdown`. */ registerOnTouched(fn) { this.onTouchedCallback = fn; } /** * `ControlValueAccessor` method to programmatically disable the dropdown. * * ex: `this.formGroup.get("myDropdown").disable();` * * @param isDisabled `true` to disable the input */ setDisabledState(isDisabled) { this.disabled = isDisabled; } /** * Adds keyboard functionality for navigation, selection and closing of the `Dropdown`. */ onKeyDown(event) { if ((event.key === "Escape") && !this.menuIsClosed) { event.stopImmediatePropagation(); // don't unintentionally close other widgets that listen for Escape } if (event.key === "Escape") { event.preventDefault(); this.closeMenu(); this.dropdownButton.nativeElement.focus(); } else if (this.menuIsClosed && (event.key === " " || event.key === "ArrowDown" || event.key === "ArrowUp")) { if (this.disableArrowKeys && (event.key === "ArrowDown" || event.key === "ArrowUp")) { return; } event.preventDefault(); this.openMenu(); } if (!this.menuIsClosed && event.key === "Tab" && this.dropdownMenu.nativeElement.contains(event.target)) { this.closeMenu(); } if (!this.menuIsClosed && event.key === "Tab" && event.shiftKey) { this.closeMenu(); } if (this.type === "multi") { return; } if (this.menuIsClosed) { this.closedDropdownNavigation(event); } } closedDropdownNavigation(event) { if (event.key === "ArrowDown") { event.preventDefault(); this.view.getCurrentItem().selected = false; let item = this.view.getNextItem(); if (item) { item.selected = true; } } else if (event.key === "ArrowUp") { event.preventDefault(); this.view.getCurrentItem().selected = false; let item = this.view.getPrevItem(); if (item) { item.selected = true; } } } /** * Returns the display value if there is a selection and displayValue is set, * if there is just a selection the ListItem content property will be returned, * otherwise the placeholder will be returned. */ getDisplayStringValue() { if (!this.view || this.skeleton) { return; } let selected = this.view.getSelected(); if (selected.length && (!this.displayValue || !this.isRenderString())) { if (this.type === "multi") { return of(this.placeholder); } else { return of(selected[0].content); } } else if (selected.length && this.isRenderString()) { return of(this.displayValue); } return of(this.placeholder); } isRenderString() { return typeof this.displayValue === "string"; } getRenderTemplateContext() { if (!this.view) { return; } let selected = this.view.getSelected(); if (this.type === "multi") { return { items: selected }; } else if (selected && selected.length > 0) { return { item: selected[0] }; // this is to be compatible with the dropdown-list template } else { return {}; } } getSelectedCount() { if (this.view.getSelected()) { return this.view.getSelected().length; } } clearSelected() { if (this.disabled || this.getSelectedCount() === 0) { return; } for (const item of this.view.getListItems()) { item.selected = false; } this.selected.emit([]); this.propagateChange([]); } /** * Returns `true` if there is a value selected. */ valueSelected() { if (this.view.getSelected()) { return true; } return false; } _noop() { } /** * Handles clicks outside of the `Dropdown`. */ _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.closeMenu(); } } _outsideKey(event) { if (!this.menuIsClosed && event.key === "Tab" && this.dropdownMenu.nativeElement.contains(event.target)) { this.closeMenu(); } } /** * Handles keyboard events so users are controlling the `Dropdown` instead of unintentionally controlling outside elements. */ _keyboardNav(event) { if (event.key === "Escape" && !this.menuIsClosed) { event.stopImmediatePropagation(); // don't unintentionally close modal if inside of it } if (event.key === "Escape") { event.preventDefault(); this.closeMenu(); this.dropdownButton.nativeElement.focus(); } else if (!this.menuIsClosed && event.key === "Tab") { // this way focus will start on the next focusable item from the dropdown // not the top of the body! this.dropdownButton.nativeElement.focus(); this.dropdownButton.nativeElement.dispatchEvent(new KeyboardEvent("keydown", { bubbles: true, cancelable: true, key: "Tab" })); this.closeMenu(); } } /** * 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); } /** * Creates the `Dropdown` list as an element that is appended to the DOM body. */ _appendToBody() { const lightClass = this.theme === "light" ? " cds--list-box--light" : ""; const expandedClass = !this.menuIsClosed ? " cds--list-box--expanded" : ""; this.dropdownService.appendToBody(this.dropdownButton.nativeElement, this.dropdownMenu.nativeElement, `${this.elementRef.nativeElement.className}${lightClass}${expandedClass}`); this.dropdownMenu.nativeElement.addEventListener("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; } /** * Expands the dropdown menu in the view. */ openMenu() { // prevents the dropdown from opening when list of items is empty if (this.view.getListItems().length === 0) { return; } this._dropUp = false; this.menuIsClosed = false; // move the dropdown list to the body if we're not appending inline // and position it relative to the dropdown wrapper if (!this.appendInline) { const target = this.dropdownButton.nativeElement; const parent = this.elementRef.nativeElement; this.visibilitySubscription = this.elementService .visibility(target, parent) .subscribe(value => { if (!value.visible) { this.closeMenu(); } }); this._appendToBody(); } // set the dropdown menu to drop up if it's near the bottom of the screen // setTimeout lets us measure after it's visible in the DOM setTimeout(() => { if (this.dropUp === null || this.dropUp === undefined) { this._dropUp = this._shouldDropUp(); } }, 0); // we bind noop to document.body.firstElementChild to allow safari to fire events // from document. Then we unbind everything later to keep things light. document.body.firstElementChild.addEventListener("click", this.noop, true); document.body.firstElementChild.addEventListener("keydown", this.noop, true); document.addEventListener("click", this.outsideClick, true); document.addEventListener("keydown", this.outsideKey, true); setTimeout(() => this.view.initFocus(), 0); } /** * Collapsing the dropdown menu and removing unnecessary `EventListeners`. */ closeMenu() { // return early if the menu is already closed if (this.menuIsClosed) { return; } this.menuIsClosed = true; this.checkForReorder(); this.onClose.emit(); this.close.emit(); // focus the trigger button when we close ... this.dropdownButton.nativeElement.focus(); // remove the conditional once this api is settled and part of abstract-dropdown-view.class if (this.view["disableScroll"]) { this.view["disableScroll"](); } // move the list back in the component on close if (!this.appendInline) { this.visibilitySubscription.unsubscribe(); this._appendToDropdown(); } document.body.firstElementChild.removeEventListener("click", this.noop, true); document.body.firstElementChild.removeEventListener("keydown", this.noop, true); document.removeEventListener("click", this.outsideClick, true); document.removeEventListener("keydown", this.outsideKey, true); } /** * Controls toggling menu states between open/expanded and closed/collapsed. */ toggleMenu() { if (this.menuIsClosed) { this.openMenu(); } else { this.closeMenu(); } } isTemplate(value) { return value instanceof TemplateRef; } /** * Controls when it's needed to apply the selection feedback */ checkForReorder() { const topAfterReopen = this.menuIsClosed && this.selectionFeedback === "top-after-reopen"; if ((this.type === "multi") && (topAfterReopen || this.selectionFeedback === "top")) { this.view.reorderSelected(); } } } Dropdown.dropdownCount = 0; Dropdown.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Dropdown, deps: [{ token: i0.ElementRef }, { token: i1.I18n }, { token: i2.DropdownService }, { token: i3.ElementService }], target: i0.ɵɵFactoryTarget.Component }); Dropdown.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Dropdown, selector: "cds-dropdown, ibm-dropdown", inputs: { id: "id", label: "label", hideLabel: "hideLabel", helperText: "helperText", placeholder: "placeholder", displayValue: "displayValue", clearText: "clearText", size: "size", type: "type", theme: "theme", disabled: "disabled", skeleton: "skeleton", inline: "inline", disableArrowKeys: "disableArrowKeys", invalid: "invalid", invalidText: "invalidText", warn: "warn", warnText: "warnText", appendInline: "appendInline", scrollableContainer: "scrollableContainer", itemValueKey: "itemValueKey", selectionFeedback: "selectionFeedback", menuButtonLabel: "menuButtonLabel", selectedLabel: "selectedLabel", dropUp: "dropUp" }, outputs: { selected: "selected", onClose: "onClose", close: "close" }, host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "class.cds--dropdown__wrapper": "this.hostClass" } }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: Dropdown, multi: true } ], queries: [{ propertyName: "view", first: true, predicate: AbstractDropdownView, descendants: true, static: true }], viewQueries: [{ propertyName: "dropdownButton", first: true, predicate: ["dropdownButton"], descendants: true, static: true }, { propertyName: "dropdownMenu", first: true, predicate: ["dropdownMenu"], descendants: true, static: true }], ngImport: i0, template: ` <label *ngIf="label && !skeleton" [for]="id" 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 class="cds--list-box" [ngClass]="{ 'cds--dropdown': type !== 'multi', 'cds--multiselect': type === 'multi', 'cds--multi-select--selected': type === 'multi' && getSelectedCount() > 0, 'cds--dropdown--light': theme === 'light', 'cds--list-box--light': theme === 'light', 'cds--list-box--inline': inline, 'cds--skeleton': skeleton, 'cds--dropdown--disabled cds--list-box--disabled': disabled, 'cds--dropdown--invalid': invalid, 'cds--dropdown--warning cds--list-box--warning': warn, 'cds--dropdown--sm cds--list-box--sm': size === 'sm', 'cds--dropdown--md cds--list-box--md': size === 'md', 'cds--dropdown--lg cds--list-box--lg': size === 'lg', 'cds--list-box--expanded': !menuIsClosed }"> <button #dropdownButton [id]="id" type="button" class="cds--list-box__field" [ngClass]="{'a': !menuIsClosed}" [attr.aria-expanded]="!menuIsClosed" [attr.aria-disabled]="disabled" aria-haspopup="listbox" (click)="disabled ? $event.stopPropagation() : toggleMenu()" (blur)="onBlur()" [attr.disabled]="disabled ? true : null"> <div (click)="clearSelected()" (keydown.enter)="clearSelected()" *ngIf="type === 'multi' && getSelectedCount() > 0" class="cds--list-box__selection cds--tag--filter cds--list-box__selection--multi" tabindex="0" [title]="clearText"> {{getSelectedCount()}} <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> </div> <span *ngIf="isRenderString()" class="cds--list-box__label">{{getDisplayStringValue() | async}}</span> <ng-template *ngIf="!isRenderString()" [ngTemplateOutletContext]="getRenderTemplateContext()" [ngTemplateOutlet]="displayValue"> </ng-template> <svg *ngIf="invalid" class="cds--dropdown__invalid-icon" cdsIcon="warning--filled" size="16"> </svg> <svg *ngIf="!invalid && warn" cdsIcon="warning--alt--filled" size="16" class="cds--list-box__invalid-icon cds--list-box__invalid-icon--warning"> </svg> <span class="cds--list-box__menu-icon"> <svg *ngIf="!skeleton" cdsIcon="chevron--down" size="16" [attr.aria-label]="menuButtonLabel" [ngClass]="{'cds--list-box__menu-icon--open': !menuIsClosed }"> </svg> </span> </button> <div #dropdownMenu [ngClass]="{ 'cds--list-box--up': this.dropUp !== null && this.dropUp !== undefined ? dropUp : _dropUp }"> <ng-content *ngIf="!menuIsClosed"></ng-content> </div> </div> <div *ngIf="helperText && !invalid && !warn && !skeleton" 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> `, isInline: true, dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i5.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Dropdown, decorators: [{ type: Component, args: [{ selector: "cds-dropdown, ibm-dropdown", template: ` <label *ngIf="label && !skeleton" [for]="id" 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 class="cds--list-box" [ngClass]="{ 'cds--dropdown': type !== 'multi', 'cds--multiselect': type === 'multi', 'cds--multi-select--selected': type === 'multi' && getSelectedCount() > 0, 'cds--dropdown--light': theme === 'light', 'cds--list-box--light': theme === 'light', 'cds--list-box--inline': inline, 'cds--skeleton': skeleton, 'cds--dropdown--disabled cds--list-box--disabled': disabled, 'cds--dropdown--invalid': invalid, 'cds--dropdown--warning cds--list-box--warning': warn, 'cds--dropdown--sm cds--list-box--sm': size === 'sm', 'cds--dropdown--md cds--list-box--md': size === 'md', 'cds--dropdown--lg cds--list-box--lg': size === 'lg', 'cds--list-box--expanded': !menuIsClosed }"> <button #dropdownButton [id]="id" type="button" class="cds--list-box__field" [ngClass]="{'a': !menuIsClosed}" [attr.aria-expanded]="!menuIsClosed" [attr.aria-disabled]="disabled" aria-haspopup="listbox" (click)="disabled ? $event.stopPropagation() : toggleMenu()" (blur)="onBlur()" [attr.disabled]="disabled ? true : null"> <div (click)="clearSelected()" (keydown.enter)="clearSelected()" *ngIf="type === 'multi' && getSelectedCount() > 0" class="cds--list-box__selection cds--tag--filter cds--list-box__selection--multi" tabindex="0" [title]="clearText"> {{getSelectedCount()}} <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> </div> <span *ngIf="isRenderString()" class="cds--list-box__label">{{getDisplayStringValue() | async}}</span> <ng-template *ngIf="!isRenderString()" [ngTemplateOutletContext]="getRenderTemplateContext()" [ngTemplateOutlet]="displayValue"> </ng-template> <svg *ngIf="invalid" class="cds--dropdown__invalid-icon" cdsIcon="warning--filled" size="16"> </svg> <svg *ngIf="!invalid && warn" cdsIcon="warning--alt--filled" size="16" class="cds--list-box__invalid-icon cds--list-box__invalid-icon--warning"> </svg> <span class="cds--list-box__menu-icon"> <svg *ngIf="!skeleton" cdsIcon="chevron--down" size="16" [attr.aria-label]="menuButtonLabel" [ngClass]="{'cds--list-box__menu-icon--open': !menuIsClosed }"> </svg> </span> </button> <div #dropdownMenu [ngClass]="{ 'cds--list-box--up': this.dropUp !== null && this.dropUp !== undefined ? dropUp : _dropUp }"> <ng-content *ngIf="!menuIsClosed"></ng-content> </div> </div> <div *ngIf="helperText && !invalid && !warn && !skeleton" 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> `, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: Dropdown, multi: true } ] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.I18n }, { type: i2.DropdownService }, { type: i3.ElementService }]; }, propDecorators: { id: [{ type: Input }], label: [{ type: Input }], hideLabel: [{ type: Input }], helperText: [{ type: Input }], placeholder: [{ type: Input }], displayValue: [{ type: Input }], clearText: [{ type: Input }], size: [{ type: Input }], type: [{ type: Input }], theme: [{ type: Input }], disabled: [{ type: Input }], skeleton: [{ type: Input }], inline: [{ type: Input }], disableArrowKeys: [{ type: Input }], invalid: [{ type: Input }], invalidText: [{ type: Input }], warn: [{ type: Input }], warnText: [{ type: Input }], appendInline: [{ type: Input }], scrollableContainer: [{ type: Input }], itemValueKey: [{ type: Input }], selectionFeedback: [{ type: Input }], menuButtonLabel: [{ type: Input }], selectedLabel: [{ type: Input }], dropUp: [{ type: Input }], selected: [{ type: Output }], onClose: [{ type: Output }], close: [{ type: Output }], view: [{ type: ContentChild, args: [AbstractDropdownView, { static: true }] }], dropdownButton: [{ type: ViewChild, args: ["dropdownButton", { static: true }] }], dropdownMenu: [{ type: ViewChild, args: ["dropdownMenu", { static: true }] }], hostClass: [{ type: HostBinding, args: ["class.cds--dropdown__wrapper"] }], onKeyDown: [{ type: HostListener, args: ["keydown", ["$event"]] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJvcGRvd24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Ryb3Bkb3duL2Ryb3Bkb3duLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUVaLFlBQVksRUFFWixTQUFTLEVBRVQsWUFBWSxFQUVaLFdBQVcsRUFDWCxXQUFXLEVBRVgsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGlCQUFpQixFQUF3QixNQUFNLGdCQUFnQixDQUFDO0FBRXpFLHlFQUF5RTtBQUN6RSxPQUFPLEVBRU4sRUFBRSxFQUNGLFlBQVksRUFDWixNQUFNLE1BQU0sQ0FBQztBQUVkLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBSXRFLE9BQU8sRUFBa0Isb0JBQW9CLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN2RixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQzs7Ozs7OztBQUV2RTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHO0FBZ0lILE1BQU0sT0FBTyxRQUFRO0lBdUtwQjs7T0FFRztJQUNILFlBQ1csVUFBc0IsRUFDdEIsSUFBVSxFQUNWLGVBQWdDLEVBQ2hDLGNBQThCO1FBSDlCLGVBQVUsR0FBVixVQUFVLENBQVk7UUFDdEIsU0FBSSxHQUFKLElBQUksQ0FBTTtRQUNWLG9CQUFlLEdBQWYsZUFBZSxDQUFpQjtRQUNoQyxtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUE1S2hDLE9BQUUsR0FBRyxZQUFZLFFBQVEsQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1FBS3JEOztXQUVHO1FBQ00sY0FBUyxHQUFHLEtBQUssQ0FBQztRQUszQjs7V0FFRztRQUNNLGdCQUFXLEdBQUcsRUFBRSxDQUFDO1FBQzFCOztXQUVHO1FBQ00saUJBQVksR0FBOEIsRUFBRSxDQUFD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