UNPKG

carbon-components-angular

Version:
903 lines 92.8 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++}`; /** * 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", 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}"> <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}"> <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 }], 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJvcGRvd24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Ryb3Bkb3duL2Ryb3Bkb3duLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUVaLFlBQVksRUFFWixTQUFTLEVBRVQsWUFBWSxFQUVaLFdBQVcsRUFDWCxXQUFXLEVBRVgsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGlCQUFpQixFQUF3QixNQUFNLGdCQUFnQixDQUFDO0FBRXpFLHlFQUF5RTtBQUN6RSxPQUFPLEVBRU4sRUFBRSxFQUNGLFlBQVksRUFDWixNQUFNLE1BQU0sQ0FBQztBQUVkLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBSXRFLE9BQU8sRUFBa0Isb0JBQW9CLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN2RixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQzs7Ozs7OztBQUV2RTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHO0FBNkhILE1BQU0sT0FBTyxRQUFRO0lBbUtwQjs7T0FFRztJQUNILFlBQ1csVUFBc0IsRUFDdEIsSUFBVSxFQUNWLGVBQWdDLEVBQ2hDLGNBQThCO1FBSDlCLGVBQVUsR0FBVixVQUFVLENBQVk7UUFDdEIsU0FBSSxHQUFKLElBQUksQ0FBTTtRQUNWLG9CQUFlLEdBQWYsZUFBZSxDQUFpQjtRQUNoQyxtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUF4S2hDLE9BQUUsR0FBRyxZQUFZLFFBQVEsQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1FBU3JEOztXQUVHO1FBQ00sZ0JBQVcsR0FBRyxFQUFFLENBQUM7UUFDMUI7O1dBRUc7UUFDTSxpQkFBWSxHQUE4QixFQUFFLENBQUM7UUFDdEQ7O1dBRUc7UUFDTSxjQUFTLEdBQVcsSUFBSSxDQUFD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