UNPKG

@angular/cdk

Version:

Angular Material Component Development Kit

860 lines 107 kB
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { ChangeDetectorRef, ContentChildren, Directive, ElementRef, forwardRef, inject, Input, Output, QueryList, } from '@angular/core'; import { ActiveDescendantKeyManager } from '@angular/cdk/a11y'; import { A, DOWN_ARROW, END, ENTER, hasModifierKey, HOME, LEFT_ARROW, RIGHT_ARROW, SPACE, UP_ARROW, } from '@angular/cdk/keycodes'; import { coerceArray, coerceBooleanProperty } from '@angular/cdk/coercion'; import { SelectionModel } from '@angular/cdk/collections'; import { defer, merge, Subject } from 'rxjs'; import { filter, map, startWith, switchMap, takeUntil } from 'rxjs/operators'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { Directionality } from '@angular/cdk/bidi'; import * as i0 from "@angular/core"; /** The next id to use for creating unique DOM IDs. */ let nextId = 0; /** * An implementation of SelectionModel that internally always represents the selection as a * multi-selection. This is necessary so that we can recover the full selection if the user * switches the listbox from single-selection to multi-selection after initialization. * * This selection model may report multiple selected values, even if it is in single-selection * mode. It is up to the user (CdkListbox) to check for invalid selections. */ class ListboxSelectionModel extends SelectionModel { constructor(multiple = false, initiallySelectedValues, emitChanges = true, compareWith) { super(true, initiallySelectedValues, emitChanges, compareWith); this.multiple = multiple; } isMultipleSelection() { return this.multiple; } select(...values) { // The super class is always in multi-selection mode, so we need to override the behavior if // this selection model actually belongs to a single-selection listbox. if (this.multiple) { return super.select(...values); } else { return super.setSelection(...values); } } } /** A selectable option in a listbox. */ export class CdkOption { constructor() { this._generatedId = `cdk-option-${nextId++}`; this._disabled = false; /** The option's host element */ this.element = inject(ElementRef).nativeElement; /** The parent listbox this option belongs to. */ this.listbox = inject(CdkListbox); /** Emits when the option is destroyed. */ this.destroyed = new Subject(); /** Emits when the option is clicked. */ this._clicked = new Subject(); } /** The id of the option's host element. */ get id() { return this._id || this._generatedId; } set id(value) { this._id = value; } /** Whether this option is disabled. */ get disabled() { return this.listbox.disabled || this._disabled; } set disabled(value) { this._disabled = coerceBooleanProperty(value); } /** The tabindex of the option when it is enabled. */ get enabledTabIndex() { return this._enabledTabIndex === undefined ? this.listbox.enabledTabIndex : this._enabledTabIndex; } set enabledTabIndex(value) { this._enabledTabIndex = value; } ngOnDestroy() { this.destroyed.next(); this.destroyed.complete(); } /** Whether this option is selected. */ isSelected() { return this.listbox.isSelected(this); } /** Whether this option is active. */ isActive() { return this.listbox.isActive(this); } /** Toggle the selected state of this option. */ toggle() { this.listbox.toggle(this); } /** Select this option if it is not selected. */ select() { this.listbox.select(this); } /** Deselect this option if it is selected. */ deselect() { this.listbox.deselect(this); } /** Focus this option. */ focus() { this.element.focus(); } /** Get the label for this element which is required by the FocusableOption interface. */ getLabel() { return (this.typeaheadLabel ?? this.element.textContent?.trim()) || ''; } /** * No-op implemented as a part of `Highlightable`. * @docs-private */ setActiveStyles() { } /** * No-op implemented as a part of `Highlightable`. * @docs-private */ setInactiveStyles() { } /** Handle focus events on the option. */ _handleFocus() { // Options can wind up getting focused in active descendant mode if the user clicks on them. // In this case, we push focus back to the parent listbox to prevent an extra tab stop when // the user performs a shift+tab. if (this.listbox.useActiveDescendant) { this.listbox._setActiveOption(this); this.listbox.focus(); } } /** Get the tabindex for this option. */ _getTabIndex() { if (this.listbox.useActiveDescendant || this.disabled) { return -1; } return this.isActive() ? this.enabledTabIndex : -1; } } CdkOption.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0-rc.0", ngImport: i0, type: CdkOption, deps: [], target: i0.ɵɵFactoryTarget.Directive }); CdkOption.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.0-rc.0", type: CdkOption, isStandalone: true, selector: "[cdkOption]", inputs: { id: "id", value: ["cdkOption", "value"], typeaheadLabel: ["cdkOptionTypeaheadLabel", "typeaheadLabel"], disabled: ["cdkOptionDisabled", "disabled"], enabledTabIndex: ["tabindex", "enabledTabIndex"] }, host: { attributes: { "role": "option" }, listeners: { "click": "_clicked.next($event)", "focus": "_handleFocus()" }, properties: { "id": "id", "attr.aria-selected": "isSelected()", "attr.tabindex": "_getTabIndex()", "attr.aria-disabled": "disabled", "class.cdk-option-active": "isActive()" }, classAttribute: "cdk-option" }, exportAs: ["cdkOption"], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0-rc.0", ngImport: i0, type: CdkOption, decorators: [{ type: Directive, args: [{ selector: '[cdkOption]', standalone: true, exportAs: 'cdkOption', host: { 'role': 'option', 'class': 'cdk-option', '[id]': 'id', '[attr.aria-selected]': 'isSelected()', '[attr.tabindex]': '_getTabIndex()', '[attr.aria-disabled]': 'disabled', '[class.cdk-option-active]': 'isActive()', '(click)': '_clicked.next($event)', '(focus)': '_handleFocus()', }, }] }], propDecorators: { id: [{ type: Input }], value: [{ type: Input, args: ['cdkOption'] }], typeaheadLabel: [{ type: Input, args: ['cdkOptionTypeaheadLabel'] }], disabled: [{ type: Input, args: ['cdkOptionDisabled'] }], enabledTabIndex: [{ type: Input, args: ['tabindex'] }] } }); export class CdkListbox { constructor() { this._generatedId = `cdk-listbox-${nextId++}`; this._disabled = false; this._useActiveDescendant = false; this._orientation = 'vertical'; this._navigationWrapDisabled = false; this._navigateDisabledOptions = false; /** Emits when the selected value(s) in the listbox change. */ this.valueChange = new Subject(); /** The selection model used by the listbox. */ this.selectionModel = new ListboxSelectionModel(); /** Emits when the listbox is destroyed. */ this.destroyed = new Subject(); /** The host element of the listbox. */ this.element = inject(ElementRef).nativeElement; /** The change detector for this listbox. */ this.changeDetectorRef = inject(ChangeDetectorRef); /** Whether the currently selected value in the selection model is invalid. */ this._invalid = false; /** The last user-triggered option. */ this._lastTriggered = null; /** Callback called when the listbox has been touched */ this._onTouched = () => { }; /** Callback called when the listbox value changes */ this._onChange = () => { }; /** Emits when an option has been clicked. */ this._optionClicked = defer(() => this.options.changes.pipe(startWith(this.options), switchMap(options => merge(...options.map(option => option._clicked.pipe(map(event => ({ option, event })))))))); /** The directionality of the page. */ this._dir = inject(Directionality, { optional: true }); /** A predicate that skips disabled options. */ this._skipDisabledPredicate = (option) => option.disabled; /** A predicate that does not skip any options. */ this._skipNonePredicate = () => false; /** Whether the listbox currently has focus. */ this._hasFocus = false; } /** The id of the option's host element. */ get id() { return this._id || this._generatedId; } set id(value) { this._id = value; } /** The tabindex to use when the listbox is enabled. */ get enabledTabIndex() { return this._enabledTabIndex === undefined ? 0 : this._enabledTabIndex; } set enabledTabIndex(value) { this._enabledTabIndex = value; } /** The value selected in the listbox, represented as an array of option values. */ get value() { return this._invalid ? [] : this.selectionModel.selected; } set value(value) { this._setSelection(value); } /** * Whether the listbox allows multiple options to be selected. If the value switches from `true` * to `false`, and more than one option is selected, all options are deselected. */ get multiple() { return this.selectionModel.multiple; } set multiple(value) { this.selectionModel.multiple = coerceBooleanProperty(value); if (this.options) { this._updateInternalValue(); } } /** Whether the listbox is disabled. */ get disabled() { return this._disabled; } set disabled(value) { this._disabled = coerceBooleanProperty(value); } /** Whether the listbox will use active descendant or will move focus onto the options. */ get useActiveDescendant() { return this._useActiveDescendant; } set useActiveDescendant(shouldUseActiveDescendant) { this._useActiveDescendant = coerceBooleanProperty(shouldUseActiveDescendant); } /** The orientation of the listbox. Only affects keyboard interaction, not visual layout. */ get orientation() { return this._orientation; } set orientation(value) { this._orientation = value === 'horizontal' ? 'horizontal' : 'vertical'; if (value === 'horizontal') { this.listKeyManager?.withHorizontalOrientation(this._dir?.value || 'ltr'); } else { this.listKeyManager?.withVerticalOrientation(); } } /** The function used to compare option values. */ get compareWith() { return this.selectionModel.compareWith; } set compareWith(fn) { this.selectionModel.compareWith = fn; } /** * Whether the keyboard navigation should wrap when the user presses arrow down on the last item * or arrow up on the first item. */ get navigationWrapDisabled() { return this._navigationWrapDisabled; } set navigationWrapDisabled(wrap) { this._navigationWrapDisabled = coerceBooleanProperty(wrap); this.listKeyManager?.withWrap(!this._navigationWrapDisabled); } /** Whether keyboard navigation should skip over disabled items. */ get navigateDisabledOptions() { return this._navigateDisabledOptions; } set navigateDisabledOptions(skip) { this._navigateDisabledOptions = coerceBooleanProperty(skip); this.listKeyManager?.skipPredicate(this._navigateDisabledOptions ? this._skipNonePredicate : this._skipDisabledPredicate); } ngAfterContentInit() { if (typeof ngDevMode === 'undefined' || ngDevMode) { this._verifyNoOptionValueCollisions(); this._verifyOptionValues(); } this._initKeyManager(); // Update the internal value whenever the options or the model value changes. merge(this.selectionModel.changed, this.options.changes) .pipe(startWith(null), takeUntil(this.destroyed)) .subscribe(() => this._updateInternalValue()); this._optionClicked .pipe(filter(({ option }) => !option.disabled), takeUntil(this.destroyed)) .subscribe(({ option, event }) => this._handleOptionClicked(option, event)); } ngOnDestroy() { this.listKeyManager?.destroy(); this.destroyed.next(); this.destroyed.complete(); } /** * Toggle the selected state of the given option. * @param option The option to toggle */ toggle(option) { this.toggleValue(option.value); } /** * Toggle the selected state of the given value. * @param value The value to toggle */ toggleValue(value) { if (this._invalid) { this.selectionModel.clear(false); } this.selectionModel.toggle(value); } /** * Select the given option. * @param option The option to select */ select(option) { this.selectValue(option.value); } /** * Select the given value. * @param value The value to select */ selectValue(value) { if (this._invalid) { this.selectionModel.clear(false); } this.selectionModel.select(value); } /** * Deselect the given option. * @param option The option to deselect */ deselect(option) { this.deselectValue(option.value); } /** * Deselect the given value. * @param value The value to deselect */ deselectValue(value) { if (this._invalid) { this.selectionModel.clear(false); } this.selectionModel.deselect(value); } /** * Set the selected state of all options. * @param isSelected The new selected state to set */ setAllSelected(isSelected) { if (!isSelected) { this.selectionModel.clear(); } else { if (this._invalid) { this.selectionModel.clear(false); } this.selectionModel.select(...this.options.map(option => option.value)); } } /** * Get whether the given option is selected. * @param option The option to get the selected state of */ isSelected(option) { return this.isValueSelected(option.value); } /** * Get whether the given option is active. * @param option The option to get the active state of */ isActive(option) { return !!(this.listKeyManager?.activeItem === option); } /** * Get whether the given value is selected. * @param value The value to get the selected state of */ isValueSelected(value) { if (this._invalid) { return false; } return this.selectionModel.isSelected(value); } /** * Registers a callback to be invoked when the listbox's value changes from user input. * @param fn The callback to register * @docs-private */ registerOnChange(fn) { this._onChange = fn; } /** * Registers a callback to be invoked when the listbox is blurred by the user. * @param fn The callback to register * @docs-private */ registerOnTouched(fn) { this._onTouched = fn; } /** * Sets the listbox's value. * @param value The new value of the listbox * @docs-private */ writeValue(value) { this._setSelection(value); this._verifyOptionValues(); } /** * Sets the disabled state of the listbox. * @param isDisabled The new disabled state * @docs-private */ setDisabledState(isDisabled) { this.disabled = isDisabled; } /** Focus the listbox's host element. */ focus() { this.element.focus(); } /** * Triggers the given option in response to user interaction. * - In single selection mode: selects the option and deselects any other selected option. * - In multi selection mode: toggles the selected state of the option. * @param option The option to trigger */ triggerOption(option) { if (option && !option.disabled) { this._lastTriggered = option; const changed = this.multiple ? this.selectionModel.toggle(option.value) : this.selectionModel.select(option.value); if (changed) { this._onChange(this.value); this.valueChange.next({ value: this.value, listbox: this, option: option, }); } } } /** * Trigger the given range of options in response to user interaction. * Should only be called in multi-selection mode. * @param trigger The option that was triggered * @param from The start index of the options to toggle * @param to The end index of the options to toggle * @param on Whether to toggle the option range on */ triggerRange(trigger, from, to, on) { if (this.disabled || (trigger && trigger.disabled)) { return; } this._lastTriggered = trigger; const isEqual = this.compareWith ?? Object.is; const updateValues = [...this.options] .slice(Math.max(0, Math.min(from, to)), Math.min(this.options.length, Math.max(from, to) + 1)) .filter(option => !option.disabled) .map(option => option.value); const selected = [...this.value]; for (const updateValue of updateValues) { const selectedIndex = selected.findIndex(selectedValue => isEqual(selectedValue, updateValue)); if (on && selectedIndex === -1) { selected.push(updateValue); } else if (!on && selectedIndex !== -1) { selected.splice(selectedIndex, 1); } } let changed = this.selectionModel.setSelection(...selected); if (changed) { this._onChange(this.value); this.valueChange.next({ value: this.value, listbox: this, option: trigger, }); } } /** * Sets the given option as active. * @param option The option to make active */ _setActiveOption(option) { this.listKeyManager.setActiveItem(option); } /** Called when the listbox receives focus. */ _handleFocus() { if (!this.useActiveDescendant) { if (this.selectionModel.selected.length > 0) { this._setNextFocusToSelectedOption(); } else { this.listKeyManager.setNextItemActive(); } this._focusActiveOption(); } } /** Called when the user presses keydown on the listbox. */ _handleKeydown(event) { if (this._disabled) { return; } const { keyCode } = event; const previousActiveIndex = this.listKeyManager.activeItemIndex; const ctrlKeys = ['ctrlKey', 'metaKey']; if (this.multiple && keyCode === A && hasModifierKey(event, ...ctrlKeys)) { // Toggle all options off if they're all selected, otherwise toggle them all on. this.triggerRange(null, 0, this.options.length - 1, this.options.length !== this.value.length); event.preventDefault(); return; } if (this.multiple && (keyCode === SPACE || keyCode === ENTER) && hasModifierKey(event, 'shiftKey')) { if (this.listKeyManager.activeItem && this.listKeyManager.activeItemIndex != null) { this.triggerRange(this.listKeyManager.activeItem, this._getLastTriggeredIndex() ?? this.listKeyManager.activeItemIndex, this.listKeyManager.activeItemIndex, !this.listKeyManager.activeItem.isSelected()); } event.preventDefault(); return; } if (this.multiple && keyCode === HOME && hasModifierKey(event, ...ctrlKeys) && hasModifierKey(event, 'shiftKey')) { const trigger = this.listKeyManager.activeItem; if (trigger) { const from = this.listKeyManager.activeItemIndex; this.listKeyManager.setFirstItemActive(); this.triggerRange(trigger, from, this.listKeyManager.activeItemIndex, !trigger.isSelected()); } event.preventDefault(); return; } if (this.multiple && keyCode === END && hasModifierKey(event, ...ctrlKeys) && hasModifierKey(event, 'shiftKey')) { const trigger = this.listKeyManager.activeItem; if (trigger) { const from = this.listKeyManager.activeItemIndex; this.listKeyManager.setLastItemActive(); this.triggerRange(trigger, from, this.listKeyManager.activeItemIndex, !trigger.isSelected()); } event.preventDefault(); return; } if (keyCode === SPACE || keyCode === ENTER) { this.triggerOption(this.listKeyManager.activeItem); event.preventDefault(); return; } const isNavKey = keyCode === UP_ARROW || keyCode === DOWN_ARROW || keyCode === LEFT_ARROW || keyCode === RIGHT_ARROW || keyCode === HOME || keyCode === END; this.listKeyManager.onKeydown(event); // Will select an option if shift was pressed while navigating to the option if (isNavKey && event.shiftKey && previousActiveIndex !== this.listKeyManager.activeItemIndex) { this.triggerOption(this.listKeyManager.activeItem); } } /** Called when a focus moves into the listbox. */ _handleFocusIn() { // Note that we use a `focusin` handler for this instead of the existing `focus` handler, // because focus won't land on the listbox if `useActiveDescendant` is enabled. this._hasFocus = true; } /** * Called when the focus leaves an element in the listbox. * @param event The focusout event */ _handleFocusOut(event) { const otherElement = event.relatedTarget; if (this.element !== otherElement && !this.element.contains(otherElement)) { this._onTouched(); this._hasFocus = false; this._setNextFocusToSelectedOption(); } } /** Get the id of the active option if active descendant is being used. */ _getAriaActiveDescendant() { return this._useActiveDescendant ? this.listKeyManager?.activeItem?.id : null; } /** Get the tabindex for the listbox. */ _getTabIndex() { if (this.disabled) { return -1; } return this.useActiveDescendant || !this.listKeyManager.activeItem ? this.enabledTabIndex : -1; } /** Initialize the key manager. */ _initKeyManager() { this.listKeyManager = new ActiveDescendantKeyManager(this.options) .withWrap(!this._navigationWrapDisabled) .withTypeAhead() .withHomeAndEnd() .withAllowedModifierKeys(['shiftKey']) .skipPredicate(this._navigateDisabledOptions ? this._skipNonePredicate : this._skipDisabledPredicate); if (this.orientation === 'vertical') { this.listKeyManager.withVerticalOrientation(); } else { this.listKeyManager.withHorizontalOrientation(this._dir?.value || 'ltr'); } if (this.selectionModel.selected.length) { Promise.resolve().then(() => this._setNextFocusToSelectedOption()); } this.listKeyManager.change.subscribe(() => this._focusActiveOption()); } /** Focus the active option. */ _focusActiveOption() { if (!this.useActiveDescendant) { this.listKeyManager.activeItem?.focus(); } this.changeDetectorRef.markForCheck(); } /** * Set the selected values. * @param value The list of new selected values. */ _setSelection(value) { if (this._invalid) { this.selectionModel.clear(false); } this.selectionModel.setSelection(...this._coerceValue(value)); if (!this._hasFocus) { this._setNextFocusToSelectedOption(); } } /** Sets the first selected option as first in the keyboard focus order. */ _setNextFocusToSelectedOption() { // Null check the options since they only get defined after `ngAfterContentInit`. const selected = this.options?.find(option => option.isSelected()); if (selected) { this.listKeyManager.updateActiveItem(selected); } } /** Update the internal value of the listbox based on the selection model. */ _updateInternalValue() { const indexCache = new Map(); this.selectionModel.sort((a, b) => { const aIndex = this._getIndexForValue(indexCache, a); const bIndex = this._getIndexForValue(indexCache, b); return aIndex - bIndex; }); const selected = this.selectionModel.selected; this._invalid = (!this.multiple && selected.length > 1) || !!this._getInvalidOptionValues(selected).length; this.changeDetectorRef.markForCheck(); } /** * Gets the index of the given value in the given list of options. * @param cache The cache of indices found so far * @param value The value to find * @return The index of the value in the options list */ _getIndexForValue(cache, value) { const isEqual = this.compareWith || Object.is; if (!cache.has(value)) { let index = -1; for (let i = 0; i < this.options.length; i++) { if (isEqual(value, this.options.get(i).value)) { index = i; break; } } cache.set(value, index); } return cache.get(value); } /** * Handle the user clicking an option. * @param option The option that was clicked. */ _handleOptionClicked(option, event) { event.preventDefault(); this.listKeyManager.setActiveItem(option); if (event.shiftKey && this.multiple) { this.triggerRange(option, this._getLastTriggeredIndex() ?? this.listKeyManager.activeItemIndex, this.listKeyManager.activeItemIndex, !option.isSelected()); } else { this.triggerOption(option); } } /** Verifies that no two options represent the same value under the compareWith function. */ _verifyNoOptionValueCollisions() { this.options.changes.pipe(startWith(this.options), takeUntil(this.destroyed)).subscribe(() => { const isEqual = this.compareWith ?? Object.is; for (let i = 0; i < this.options.length; i++) { const option = this.options.get(i); let duplicate = null; for (let j = i + 1; j < this.options.length; j++) { const other = this.options.get(j); if (isEqual(option.value, other.value)) { duplicate = other; break; } } if (duplicate) { // TODO(mmalerba): Link to docs about this. if (this.compareWith) { console.warn(`Found multiple CdkOption representing the same value under the given compareWith function`, { option1: option.element, option2: duplicate.element, compareWith: this.compareWith, }); } else { console.warn(`Found multiple CdkOption with the same value`, { option1: option.element, option2: duplicate.element, }); } return; } } }); } /** Verifies that the option values are valid. */ _verifyOptionValues() { if (this.options && (typeof ngDevMode === 'undefined' || ngDevMode)) { const selected = this.selectionModel.selected; const invalidValues = this._getInvalidOptionValues(selected); if (!this.multiple && selected.length > 1) { throw Error('Listbox cannot have more than one selected value in multi-selection mode.'); } if (invalidValues.length) { throw Error('Listbox has selected values that do not match any of its options.'); } } } /** * Coerces a value into an array representing a listbox selection. * @param value The value to coerce * @return An array */ _coerceValue(value) { return value == null ? [] : coerceArray(value); } /** * Get the sublist of values that do not represent valid option values in this listbox. * @param values The list of values * @return The sublist of values that are not valid option values */ _getInvalidOptionValues(values) { const isEqual = this.compareWith || Object.is; const validValues = (this.options || []).map(option => option.value); return values.filter(value => !validValues.some(validValue => isEqual(value, validValue))); } /** Get the index of the last triggered option. */ _getLastTriggeredIndex() { const index = this.options.toArray().indexOf(this._lastTriggered); return index === -1 ? null : index; } } CdkListbox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0-rc.0", ngImport: i0, type: CdkListbox, deps: [], target: i0.ɵɵFactoryTarget.Directive }); CdkListbox.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.0-rc.0", type: CdkListbox, isStandalone: true, selector: "[cdkListbox]", inputs: { id: "id", enabledTabIndex: ["tabindex", "enabledTabIndex"], value: ["cdkListboxValue", "value"], multiple: ["cdkListboxMultiple", "multiple"], disabled: ["cdkListboxDisabled", "disabled"], useActiveDescendant: ["cdkListboxUseActiveDescendant", "useActiveDescendant"], orientation: ["cdkListboxOrientation", "orientation"], compareWith: ["cdkListboxCompareWith", "compareWith"], navigationWrapDisabled: ["cdkListboxNavigationWrapDisabled", "navigationWrapDisabled"], navigateDisabledOptions: ["cdkListboxNavigatesDisabledOptions", "navigateDisabledOptions"] }, outputs: { valueChange: "cdkListboxValueChange" }, host: { attributes: { "role": "listbox" }, listeners: { "focus": "_handleFocus()", "keydown": "_handleKeydown($event)", "focusout": "_handleFocusOut($event)", "focusin": "_handleFocusIn()" }, properties: { "id": "id", "attr.tabindex": "_getTabIndex()", "attr.aria-disabled": "disabled", "attr.aria-multiselectable": "multiple", "attr.aria-activedescendant": "_getAriaActiveDescendant()", "attr.aria-orientation": "orientation" }, classAttribute: "cdk-listbox" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CdkListbox), multi: true, }, ], queries: [{ propertyName: "options", predicate: CdkOption, descendants: true }], exportAs: ["cdkListbox"], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0-rc.0", ngImport: i0, type: CdkListbox, decorators: [{ type: Directive, args: [{ selector: '[cdkListbox]', standalone: true, exportAs: 'cdkListbox', host: { 'role': 'listbox', 'class': 'cdk-listbox', '[id]': 'id', '[attr.tabindex]': '_getTabIndex()', '[attr.aria-disabled]': 'disabled', '[attr.aria-multiselectable]': 'multiple', '[attr.aria-activedescendant]': '_getAriaActiveDescendant()', '[attr.aria-orientation]': 'orientation', '(focus)': '_handleFocus()', '(keydown)': '_handleKeydown($event)', '(focusout)': '_handleFocusOut($event)', '(focusin)': '_handleFocusIn()', }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CdkListbox), multi: true, }, ], }] }], propDecorators: { id: [{ type: Input }], enabledTabIndex: [{ type: Input, args: ['tabindex'] }], value: [{ type: Input, args: ['cdkListboxValue'] }], multiple: [{ type: Input, args: ['cdkListboxMultiple'] }], disabled: [{ type: Input, args: ['cdkListboxDisabled'] }], useActiveDescendant: [{ type: Input, args: ['cdkListboxUseActiveDescendant'] }], orientation: [{ type: Input, args: ['cdkListboxOrientation'] }], compareWith: [{ type: Input, args: ['cdkListboxCompareWith'] }], navigationWrapDisabled: [{ type: Input, args: ['cdkListboxNavigationWrapDisabled'] }], navigateDisabledOptions: [{ type: Input, args: ['cdkListboxNavigatesDisabledOptions'] }], valueChange: [{ type: Output, args: ['cdkListboxValueChange'] }], options: [{ type: ContentChildren, args: [CdkOption, { descendants: true }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdGJveC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jZGsvbGlzdGJveC9saXN0Ym94LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFFTCxpQkFBaUIsRUFDakIsZUFBZSxFQUNmLFNBQVMsRUFDVCxVQUFVLEVBQ1YsVUFBVSxFQUNWLE1BQU0sRUFDTixLQUFLLEVBRUwsTUFBTSxFQUNOLFNBQVMsR0FDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUMsMEJBQTBCLEVBQXNDLE1BQU0sbUJBQW1CLENBQUM7QUFDbEcsT0FBTyxFQUNMLENBQUMsRUFDRCxVQUFVLEVBQ1YsR0FBRyxFQUNILEtBQUssRUFDTCxjQUFjLEVBQ2QsSUFBSSxFQUNKLFVBQVUsRUFDVixXQUFXLEVBQ1gsS0FBSyxFQUNMLFFBQVEsR0FDVCxNQUFNLHVCQUF1QixDQUFDO0FBQy9CLE9BQU8sRUFBZSxXQUFXLEVBQUUscUJBQXFCLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUN2RixPQUFPLEVBQUMsY0FBYyxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDeEQsT0FBTyxFQUFDLEtBQUssRUFBRSxLQUFLLEVBQWMsT0FBTyxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBQ3ZELE9BQU8sRUFBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDNUUsT0FBTyxFQUF1QixpQkFBaUIsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3ZFLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQzs7QUFFakQsc0RBQXNEO0FBQ3RELElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQztBQUVmOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLHFCQUF5QixTQUFRLGNBQWlCO0lBQ3RELFlBQ1MsV0FBVyxLQUFLLEVBQ3ZCLHVCQUE2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