@angular/material
Version:
Angular Material
1,069 lines (1,063 loc) • 40.1 kB
JavaScript
import { MAT_OPTION_PARENT_COMPONENT, MatOption, MAT_OPTGROUP, MatOptionSelectionChange, _countGroupLabelsBeforeOption, _getOptionScrollPosition } from './_option-chunk.mjs';
export { MatOptgroup } from './_option-chunk.mjs';
import * as i0 from '@angular/core';
import { InjectionToken, inject, ChangeDetectorRef, ElementRef, EventEmitter, booleanAttribute, TemplateRef, Component, ViewEncapsulation, ChangeDetectionStrategy, ViewChild, ContentChildren, Input, Output, Directive, forwardRef, Injector, EnvironmentInjector, ViewContainerRef, NgZone, Renderer2, afterNextRender, NgModule } from '@angular/core';
import { Directionality, BidiModule } from '@angular/cdk/bidi';
import { ViewportRuler, CdkScrollableModule } from '@angular/cdk/scrolling';
import { createRepositionScrollStrategy, createOverlayRef, OverlayConfig, createFlexibleConnectedPositionStrategy, OverlayModule } from '@angular/cdk/overlay';
import { _IdGenerator, ActiveDescendantKeyManager, removeAriaReferencedId, addAriaReferencedId } from '@angular/cdk/a11y';
import { Platform, _getFocusedElementPierceShadowDom, _getEventTarget } from '@angular/cdk/platform';
import { Subscription, Subject, merge, of, defer, Observable } from 'rxjs';
import { _animationsDisabled } from './_animation-chunk.mjs';
import { hasModifierKey, ESCAPE, ENTER, TAB, UP_ARROW, DOWN_ARROW } from '@angular/cdk/keycodes';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { TemplatePortal } from '@angular/cdk/portal';
import { coerceArray } from '@angular/cdk/coercion';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { filter, map, startWith, switchMap, tap, delay, take } from 'rxjs/operators';
import { MAT_FORM_FIELD } from './_form-field-chunk.mjs';
import { MatOptionModule } from './_option-module-chunk.mjs';
import './_ripple-chunk.mjs';
import '@angular/cdk/private';
import './_pseudo-checkbox-chunk.mjs';
import './_structural-styles-chunk.mjs';
import '@angular/common';
import '@angular/cdk/observers/private';
import './_ripple-module-chunk.mjs';
import './_pseudo-checkbox-module-chunk.mjs';
class MatAutocompleteSelectedEvent {
source;
option;
constructor(source, option) {
this.source = source;
this.option = option;
}
}
const MAT_AUTOCOMPLETE_DEFAULT_OPTIONS = new InjectionToken('mat-autocomplete-default-options', {
providedIn: 'root',
factory: () => ({
autoActiveFirstOption: false,
autoSelectActiveOption: false,
hideSingleSelectionIndicator: false,
requireSelection: false,
hasBackdrop: false
})
});
class MatAutocomplete {
_changeDetectorRef = inject(ChangeDetectorRef);
_elementRef = inject(ElementRef);
_defaults = inject(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS);
_animationsDisabled = _animationsDisabled();
_activeOptionChanges = Subscription.EMPTY;
_keyManager;
showPanel = false;
get isOpen() {
return this._isOpen && this.showPanel;
}
_isOpen = false;
_latestOpeningTrigger;
_setColor(value) {
this._color = value;
this._changeDetectorRef.markForCheck();
}
_color;
template;
panel;
options;
optionGroups;
ariaLabel;
ariaLabelledby;
displayWith = null;
autoActiveFirstOption;
autoSelectActiveOption;
requireSelection;
panelWidth;
disableRipple;
optionSelected = new EventEmitter();
opened = new EventEmitter();
closed = new EventEmitter();
optionActivated = new EventEmitter();
set classList(value) {
this._classList = value;
this._elementRef.nativeElement.className = '';
}
_classList;
get hideSingleSelectionIndicator() {
return this._hideSingleSelectionIndicator;
}
set hideSingleSelectionIndicator(value) {
this._hideSingleSelectionIndicator = value;
this._syncParentProperties();
}
_hideSingleSelectionIndicator;
_syncParentProperties() {
if (this.options) {
for (const option of this.options) {
option._changeDetectorRef.markForCheck();
}
}
}
id = inject(_IdGenerator).getId('mat-autocomplete-');
inertGroups;
constructor() {
const platform = inject(Platform);
this.inertGroups = platform?.SAFARI || false;
this.autoActiveFirstOption = !!this._defaults.autoActiveFirstOption;
this.autoSelectActiveOption = !!this._defaults.autoSelectActiveOption;
this.requireSelection = !!this._defaults.requireSelection;
this._hideSingleSelectionIndicator = this._defaults.hideSingleSelectionIndicator ?? false;
}
ngAfterContentInit() {
this._keyManager = new ActiveDescendantKeyManager(this.options).withWrap().skipPredicate(this._skipPredicate);
this._activeOptionChanges = this._keyManager.change.subscribe(index => {
if (this.isOpen) {
this.optionActivated.emit({
source: this,
option: this.options.toArray()[index] || null
});
}
});
this._setVisibility();
}
ngOnDestroy() {
this._keyManager?.destroy();
this._activeOptionChanges.unsubscribe();
}
_setScrollTop(scrollTop) {
if (this.panel) {
this.panel.nativeElement.scrollTop = scrollTop;
}
}
_getScrollTop() {
return this.panel ? this.panel.nativeElement.scrollTop : 0;
}
_setVisibility() {
this.showPanel = !!this.options?.length;
this._changeDetectorRef.markForCheck();
}
_emitSelectEvent(option) {
const event = new MatAutocompleteSelectedEvent(this, option);
this.optionSelected.emit(event);
}
_getPanelAriaLabelledby(labelId) {
if (this.ariaLabel) {
return null;
}
const labelExpression = labelId ? labelId + ' ' : '';
return this.ariaLabelledby ? labelExpression + this.ariaLabelledby : labelId;
}
_skipPredicate() {
return false;
}
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocomplete,
deps: [],
target: i0.ɵɵFactoryTarget.Component
});
static ɵcmp = i0.ɵɵngDeclareComponent({
minVersion: "16.1.0",
version: "21.0.3",
type: MatAutocomplete,
isStandalone: true,
selector: "mat-autocomplete",
inputs: {
ariaLabel: ["aria-label", "ariaLabel"],
ariaLabelledby: ["aria-labelledby", "ariaLabelledby"],
displayWith: "displayWith",
autoActiveFirstOption: ["autoActiveFirstOption", "autoActiveFirstOption", booleanAttribute],
autoSelectActiveOption: ["autoSelectActiveOption", "autoSelectActiveOption", booleanAttribute],
requireSelection: ["requireSelection", "requireSelection", booleanAttribute],
panelWidth: "panelWidth",
disableRipple: ["disableRipple", "disableRipple", booleanAttribute],
classList: ["class", "classList"],
hideSingleSelectionIndicator: ["hideSingleSelectionIndicator", "hideSingleSelectionIndicator", booleanAttribute]
},
outputs: {
optionSelected: "optionSelected",
opened: "opened",
closed: "closed",
optionActivated: "optionActivated"
},
host: {
classAttribute: "mat-mdc-autocomplete"
},
providers: [{
provide: MAT_OPTION_PARENT_COMPONENT,
useExisting: MatAutocomplete
}],
queries: [{
propertyName: "options",
predicate: MatOption,
descendants: true
}, {
propertyName: "optionGroups",
predicate: MAT_OPTGROUP,
descendants: true
}],
viewQueries: [{
propertyName: "template",
first: true,
predicate: TemplateRef,
descendants: true,
static: true
}, {
propertyName: "panel",
first: true,
predicate: ["panel"],
descendants: true
}],
exportAs: ["matAutocomplete"],
ngImport: i0,
template: "<ng-template let-formFieldId=\"id\">\n <div\n class=\"mat-mdc-autocomplete-panel mdc-menu-surface mdc-menu-surface--open\"\n role=\"listbox\"\n [id]=\"id\"\n [class]=\"_classList\"\n [class.mat-mdc-autocomplete-visible]=\"showPanel\"\n [class.mat-mdc-autocomplete-hidden]=\"!showPanel\"\n [class.mat-autocomplete-panel-animations-enabled]=\"!_animationsDisabled\"\n [class.mat-primary]=\"_color === 'primary'\"\n [class.mat-accent]=\"_color === 'accent'\"\n [class.mat-warn]=\"_color === 'warn'\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"_getPanelAriaLabelledby(formFieldId)\"\n #panel>\n <ng-content></ng-content>\n </div>\n</ng-template>\n",
styles: ["div.mat-mdc-autocomplete-panel{width:100%;max-height:256px;visibility:hidden;transform-origin:center top;overflow:auto;padding:8px 0;box-sizing:border-box;position:relative;border-radius:var(--mat-autocomplete-container-shape, var(--mat-sys-corner-extra-small));box-shadow:var(--mat-autocomplete-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));background-color:var(--mat-autocomplete-background-color, var(--mat-sys-surface-container))}@media(forced-colors: active){div.mat-mdc-autocomplete-panel{outline:solid 1px}}.cdk-overlay-pane:not(.mat-mdc-autocomplete-panel-above) div.mat-mdc-autocomplete-panel{border-top-left-radius:0;border-top-right-radius:0}.mat-mdc-autocomplete-panel-above div.mat-mdc-autocomplete-panel{border-bottom-left-radius:0;border-bottom-right-radius:0;transform-origin:center bottom}div.mat-mdc-autocomplete-panel.mat-mdc-autocomplete-visible{visibility:visible}div.mat-mdc-autocomplete-panel.mat-mdc-autocomplete-hidden,.cdk-overlay-pane:has(>.mat-mdc-autocomplete-hidden){visibility:hidden;pointer-events:none}@keyframes _mat-autocomplete-enter{from{opacity:0;transform:scaleY(0.8)}to{opacity:1;transform:none}}.mat-autocomplete-panel-animations-enabled{animation:_mat-autocomplete-enter 120ms cubic-bezier(0, 0, 0.2, 1)}mat-autocomplete{display:none}\n"],
changeDetection: i0.ChangeDetectionStrategy.OnPush,
encapsulation: i0.ViewEncapsulation.None
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocomplete,
decorators: [{
type: Component,
args: [{
selector: 'mat-autocomplete',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs: 'matAutocomplete',
host: {
'class': 'mat-mdc-autocomplete'
},
providers: [{
provide: MAT_OPTION_PARENT_COMPONENT,
useExisting: MatAutocomplete
}],
template: "<ng-template let-formFieldId=\"id\">\n <div\n class=\"mat-mdc-autocomplete-panel mdc-menu-surface mdc-menu-surface--open\"\n role=\"listbox\"\n [id]=\"id\"\n [class]=\"_classList\"\n [class.mat-mdc-autocomplete-visible]=\"showPanel\"\n [class.mat-mdc-autocomplete-hidden]=\"!showPanel\"\n [class.mat-autocomplete-panel-animations-enabled]=\"!_animationsDisabled\"\n [class.mat-primary]=\"_color === 'primary'\"\n [class.mat-accent]=\"_color === 'accent'\"\n [class.mat-warn]=\"_color === 'warn'\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"_getPanelAriaLabelledby(formFieldId)\"\n #panel>\n <ng-content></ng-content>\n </div>\n</ng-template>\n",
styles: ["div.mat-mdc-autocomplete-panel{width:100%;max-height:256px;visibility:hidden;transform-origin:center top;overflow:auto;padding:8px 0;box-sizing:border-box;position:relative;border-radius:var(--mat-autocomplete-container-shape, var(--mat-sys-corner-extra-small));box-shadow:var(--mat-autocomplete-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));background-color:var(--mat-autocomplete-background-color, var(--mat-sys-surface-container))}@media(forced-colors: active){div.mat-mdc-autocomplete-panel{outline:solid 1px}}.cdk-overlay-pane:not(.mat-mdc-autocomplete-panel-above) div.mat-mdc-autocomplete-panel{border-top-left-radius:0;border-top-right-radius:0}.mat-mdc-autocomplete-panel-above div.mat-mdc-autocomplete-panel{border-bottom-left-radius:0;border-bottom-right-radius:0;transform-origin:center bottom}div.mat-mdc-autocomplete-panel.mat-mdc-autocomplete-visible{visibility:visible}div.mat-mdc-autocomplete-panel.mat-mdc-autocomplete-hidden,.cdk-overlay-pane:has(>.mat-mdc-autocomplete-hidden){visibility:hidden;pointer-events:none}@keyframes _mat-autocomplete-enter{from{opacity:0;transform:scaleY(0.8)}to{opacity:1;transform:none}}.mat-autocomplete-panel-animations-enabled{animation:_mat-autocomplete-enter 120ms cubic-bezier(0, 0, 0.2, 1)}mat-autocomplete{display:none}\n"]
}]
}],
ctorParameters: () => [],
propDecorators: {
template: [{
type: ViewChild,
args: [TemplateRef, {
static: true
}]
}],
panel: [{
type: ViewChild,
args: ['panel']
}],
options: [{
type: ContentChildren,
args: [MatOption, {
descendants: true
}]
}],
optionGroups: [{
type: ContentChildren,
args: [MAT_OPTGROUP, {
descendants: true
}]
}],
ariaLabel: [{
type: Input,
args: ['aria-label']
}],
ariaLabelledby: [{
type: Input,
args: ['aria-labelledby']
}],
displayWith: [{
type: Input
}],
autoActiveFirstOption: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}],
autoSelectActiveOption: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}],
requireSelection: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}],
panelWidth: [{
type: Input
}],
disableRipple: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}],
optionSelected: [{
type: Output
}],
opened: [{
type: Output
}],
closed: [{
type: Output
}],
optionActivated: [{
type: Output
}],
classList: [{
type: Input,
args: ['class']
}],
hideSingleSelectionIndicator: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}]
}
});
class MatAutocompleteOrigin {
elementRef = inject(ElementRef);
constructor() {}
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocompleteOrigin,
deps: [],
target: i0.ɵɵFactoryTarget.Directive
});
static ɵdir = i0.ɵɵngDeclareDirective({
minVersion: "14.0.0",
version: "21.0.3",
type: MatAutocompleteOrigin,
isStandalone: true,
selector: "[matAutocompleteOrigin]",
exportAs: ["matAutocompleteOrigin"],
ngImport: i0
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocompleteOrigin,
decorators: [{
type: Directive,
args: [{
selector: '[matAutocompleteOrigin]',
exportAs: 'matAutocompleteOrigin'
}]
}],
ctorParameters: () => []
});
const MAT_AUTOCOMPLETE_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MatAutocompleteTrigger),
multi: true
};
function getMatAutocompleteMissingPanelError() {
return Error('Attempting to open an undefined instance of `mat-autocomplete`. ' + 'Make sure that the id passed to the `matAutocomplete` is correct and that ' + "you're attempting to open it after the ngAfterContentInit hook.");
}
const MAT_AUTOCOMPLETE_SCROLL_STRATEGY = new InjectionToken('mat-autocomplete-scroll-strategy', {
providedIn: 'root',
factory: () => {
const injector = inject(Injector);
return () => createRepositionScrollStrategy(injector);
}
});
class MatAutocompleteTrigger {
_environmentInjector = inject(EnvironmentInjector);
_element = inject(ElementRef);
_injector = inject(Injector);
_viewContainerRef = inject(ViewContainerRef);
_zone = inject(NgZone);
_changeDetectorRef = inject(ChangeDetectorRef);
_dir = inject(Directionality, {
optional: true
});
_formField = inject(MAT_FORM_FIELD, {
optional: true,
host: true
});
_viewportRuler = inject(ViewportRuler);
_scrollStrategy = inject(MAT_AUTOCOMPLETE_SCROLL_STRATEGY);
_renderer = inject(Renderer2);
_animationsDisabled = _animationsDisabled();
_defaults = inject(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, {
optional: true
});
_overlayRef;
_portal;
_componentDestroyed = false;
_initialized = new Subject();
_keydownSubscription;
_outsideClickSubscription;
_cleanupWindowBlur;
_previousValue;
_valueOnAttach;
_valueOnLastKeydown;
_positionStrategy;
_manuallyFloatingLabel = false;
_closingActionsSubscription;
_viewportSubscription = Subscription.EMPTY;
_breakpointObserver = inject(BreakpointObserver);
_handsetLandscapeSubscription = Subscription.EMPTY;
_canOpenOnNextFocus = true;
_valueBeforeAutoSelection;
_pendingAutoselectedOption;
_closeKeyEventStream = new Subject();
_overlayPanelClass = coerceArray(this._defaults?.overlayPanelClass || []);
_windowBlurHandler = () => {
this._canOpenOnNextFocus = this.panelOpen || !this._hasFocus();
};
_onChange = () => {};
_onTouched = () => {};
autocomplete;
position = 'auto';
connectedTo;
autocompleteAttribute = 'off';
autocompleteDisabled;
constructor() {}
_aboveClass = 'mat-mdc-autocomplete-panel-above';
ngAfterViewInit() {
this._initialized.next();
this._initialized.complete();
this._cleanupWindowBlur = this._renderer.listen('window', 'blur', this._windowBlurHandler);
}
ngOnChanges(changes) {
if (changes['position'] && this._positionStrategy) {
this._setStrategyPositions(this._positionStrategy);
if (this.panelOpen) {
this._overlayRef.updatePosition();
}
}
}
ngOnDestroy() {
this._cleanupWindowBlur?.();
this._handsetLandscapeSubscription.unsubscribe();
this._viewportSubscription.unsubscribe();
this._componentDestroyed = true;
this._destroyPanel();
this._closeKeyEventStream.complete();
this._clearFromModal();
}
get panelOpen() {
return this._overlayAttached && this.autocomplete.showPanel;
}
_overlayAttached = false;
openPanel() {
this._openPanelInternal();
}
closePanel() {
this._resetLabel();
if (!this._overlayAttached) {
return;
}
if (this.panelOpen) {
this._zone.run(() => {
this.autocomplete.closed.emit();
});
}
if (this.autocomplete._latestOpeningTrigger === this) {
this.autocomplete._isOpen = false;
this.autocomplete._latestOpeningTrigger = null;
}
this._overlayAttached = false;
this._pendingAutoselectedOption = null;
if (this._overlayRef && this._overlayRef.hasAttached()) {
this._overlayRef.detach();
this._closingActionsSubscription.unsubscribe();
}
this._updatePanelState();
if (!this._componentDestroyed) {
this._changeDetectorRef.detectChanges();
}
if (this._trackedModal) {
removeAriaReferencedId(this._trackedModal, 'aria-owns', this.autocomplete.id);
}
}
updatePosition() {
if (this._overlayAttached) {
this._overlayRef.updatePosition();
}
}
get panelClosingActions() {
return merge(this.optionSelections, this.autocomplete._keyManager.tabOut.pipe(filter(() => this._overlayAttached)), this._closeKeyEventStream, this._getOutsideClickStream(), this._overlayRef ? this._overlayRef.detachments().pipe(filter(() => this._overlayAttached)) : of()).pipe(map(event => event instanceof MatOptionSelectionChange ? event : null));
}
optionSelections = defer(() => {
const options = this.autocomplete ? this.autocomplete.options : null;
if (options) {
return options.changes.pipe(startWith(options), switchMap(() => merge(...options.map(option => option.onSelectionChange))));
}
return this._initialized.pipe(switchMap(() => this.optionSelections));
});
get activeOption() {
if (this.autocomplete && this.autocomplete._keyManager) {
return this.autocomplete._keyManager.activeItem;
}
return null;
}
_getOutsideClickStream() {
return new Observable(observer => {
const listener = event => {
const clickTarget = _getEventTarget(event);
const formField = this._formField ? this._formField.getConnectedOverlayOrigin().nativeElement : null;
const customOrigin = this.connectedTo ? this.connectedTo.elementRef.nativeElement : null;
if (this._overlayAttached && clickTarget !== this._element.nativeElement && !this._hasFocus() && (!formField || !formField.contains(clickTarget)) && (!customOrigin || !customOrigin.contains(clickTarget)) && !!this._overlayRef && !this._overlayRef.overlayElement.contains(clickTarget)) {
observer.next(event);
}
};
const cleanups = [this._renderer.listen('document', 'click', listener), this._renderer.listen('document', 'auxclick', listener), this._renderer.listen('document', 'touchend', listener)];
return () => {
cleanups.forEach(current => current());
};
});
}
writeValue(value) {
Promise.resolve(null).then(() => this._assignOptionValue(value));
}
registerOnChange(fn) {
this._onChange = fn;
}
registerOnTouched(fn) {
this._onTouched = fn;
}
setDisabledState(isDisabled) {
this._element.nativeElement.disabled = isDisabled;
}
_handleKeydown(e) {
const event = e;
const keyCode = event.keyCode;
const hasModifier = hasModifierKey(event);
if (keyCode === ESCAPE && !hasModifier) {
event.preventDefault();
}
this._valueOnLastKeydown = this._element.nativeElement.value;
if (this.activeOption && keyCode === ENTER && this.panelOpen && !hasModifier) {
this.activeOption._selectViaInteraction();
this._resetActiveItem();
event.preventDefault();
} else if (this.autocomplete) {
const prevActiveItem = this.autocomplete._keyManager.activeItem;
const isArrowKey = keyCode === UP_ARROW || keyCode === DOWN_ARROW;
if (keyCode === TAB || isArrowKey && !hasModifier && this.panelOpen) {
this.autocomplete._keyManager.onKeydown(event);
} else if (isArrowKey && this._canOpen()) {
this._openPanelInternal(this._valueOnLastKeydown);
}
if (isArrowKey || this.autocomplete._keyManager.activeItem !== prevActiveItem) {
this._scrollToOption(this.autocomplete._keyManager.activeItemIndex || 0);
if (this.autocomplete.autoSelectActiveOption && this.activeOption) {
if (!this._pendingAutoselectedOption) {
this._valueBeforeAutoSelection = this._valueOnLastKeydown;
}
this._pendingAutoselectedOption = this.activeOption;
this._assignOptionValue(this.activeOption.value);
}
}
}
}
_handleInput(event) {
let target = event.target;
let value = target.value;
if (target.type === 'number') {
value = value == '' ? null : parseFloat(value);
}
if (this._previousValue !== value) {
this._previousValue = value;
this._pendingAutoselectedOption = null;
if (!this.autocomplete || !this.autocomplete.requireSelection) {
this._onChange(value);
}
if (!value) {
this._clearPreviousSelectedOption(null, false);
} else if (this.panelOpen && !this.autocomplete.requireSelection) {
const selectedOption = this.autocomplete.options?.find(option => option.selected);
if (selectedOption) {
const display = this._getDisplayValue(selectedOption.value);
if (value !== display) {
selectedOption.deselect(false);
}
}
}
if (this._canOpen() && this._hasFocus()) {
const valueOnAttach = this._valueOnLastKeydown ?? this._element.nativeElement.value;
this._valueOnLastKeydown = null;
this._openPanelInternal(valueOnAttach);
}
}
}
_handleFocus() {
if (!this._canOpenOnNextFocus) {
this._canOpenOnNextFocus = true;
} else if (this._canOpen()) {
this._previousValue = this._element.nativeElement.value;
this._attachOverlay(this._previousValue);
this._floatLabel(true);
}
}
_handleClick() {
if (this._canOpen() && !this.panelOpen) {
this._openPanelInternal();
}
}
_hasFocus() {
return _getFocusedElementPierceShadowDom() === this._element.nativeElement;
}
_floatLabel(shouldAnimate = false) {
if (this._formField && this._formField.floatLabel === 'auto') {
if (shouldAnimate) {
this._formField._animateAndLockLabel();
} else {
this._formField.floatLabel = 'always';
}
this._manuallyFloatingLabel = true;
}
}
_resetLabel() {
if (this._manuallyFloatingLabel) {
if (this._formField) {
this._formField.floatLabel = 'auto';
}
this._manuallyFloatingLabel = false;
}
}
_subscribeToClosingActions() {
const initialRender = new Observable(subscriber => {
afterNextRender(() => {
subscriber.next();
}, {
injector: this._environmentInjector
});
});
const optionChanges = this.autocomplete.options?.changes.pipe(tap(() => this._positionStrategy.reapplyLastPosition()), delay(0)) ?? of();
return merge(initialRender, optionChanges).pipe(switchMap(() => this._zone.run(() => {
const wasOpen = this.panelOpen;
this._resetActiveItem();
this._updatePanelState();
this._changeDetectorRef.detectChanges();
if (this.panelOpen) {
this._overlayRef.updatePosition();
}
if (wasOpen !== this.panelOpen) {
if (this.panelOpen) {
this._emitOpened();
} else {
this.autocomplete.closed.emit();
}
}
return this.panelClosingActions;
})), take(1)).subscribe(event => this._setValueAndClose(event));
}
_emitOpened() {
this.autocomplete.opened.emit();
}
_destroyPanel() {
if (this._overlayRef) {
this.closePanel();
this._overlayRef.dispose();
this._overlayRef = null;
}
}
_getDisplayValue(value) {
const autocomplete = this.autocomplete;
return autocomplete && autocomplete.displayWith ? autocomplete.displayWith(value) : value;
}
_assignOptionValue(value) {
const toDisplay = this._getDisplayValue(value);
if (value == null) {
this._clearPreviousSelectedOption(null, false);
}
this._updateNativeInputValue(toDisplay != null ? toDisplay : '');
}
_updateNativeInputValue(value) {
if (this._formField) {
this._formField._control.value = value;
} else {
this._element.nativeElement.value = value;
}
this._previousValue = value;
}
_setValueAndClose(event) {
const panel = this.autocomplete;
const toSelect = event ? event.source : this._pendingAutoselectedOption;
if (toSelect) {
this._clearPreviousSelectedOption(toSelect);
this._assignOptionValue(toSelect.value);
this._onChange(toSelect.value);
panel._emitSelectEvent(toSelect);
this._element.nativeElement.focus();
} else if (panel.requireSelection && this._element.nativeElement.value !== this._valueOnAttach) {
this._clearPreviousSelectedOption(null);
this._assignOptionValue(null);
this._onChange(null);
}
this.closePanel();
}
_clearPreviousSelectedOption(skip, emitEvent) {
this.autocomplete?.options?.forEach(option => {
if (option !== skip && option.selected) {
option.deselect(emitEvent);
}
});
}
_openPanelInternal(valueOnAttach = this._element.nativeElement.value) {
this._attachOverlay(valueOnAttach);
this._floatLabel();
if (this._trackedModal) {
const panelId = this.autocomplete.id;
addAriaReferencedId(this._trackedModal, 'aria-owns', panelId);
}
}
_attachOverlay(valueOnAttach) {
if (!this.autocomplete) {
if (typeof ngDevMode === 'undefined' || ngDevMode) {
throw getMatAutocompleteMissingPanelError();
} else {
return;
}
}
let overlayRef = this._overlayRef;
if (!overlayRef) {
this._portal = new TemplatePortal(this.autocomplete.template, this._viewContainerRef, {
id: this._formField?.getLabelId()
});
overlayRef = createOverlayRef(this._injector, this._getOverlayConfig());
this._overlayRef = overlayRef;
this._viewportSubscription = this._viewportRuler.change().subscribe(() => {
if (this.panelOpen && overlayRef) {
overlayRef.updateSize({
width: this._getPanelWidth()
});
}
});
this._handsetLandscapeSubscription = this._breakpointObserver.observe(Breakpoints.HandsetLandscape).subscribe(result => {
const isHandsetLandscape = result.matches;
if (isHandsetLandscape) {
this._positionStrategy.withFlexibleDimensions(true).withGrowAfterOpen(true).withViewportMargin(8);
} else {
this._positionStrategy.withFlexibleDimensions(false).withGrowAfterOpen(false).withViewportMargin(0);
}
});
} else {
this._positionStrategy.setOrigin(this._getConnectedElement());
overlayRef.updateSize({
width: this._getPanelWidth()
});
}
if (overlayRef && !overlayRef.hasAttached()) {
overlayRef.attach(this._portal);
this._valueOnAttach = valueOnAttach;
this._valueOnLastKeydown = null;
this._closingActionsSubscription = this._subscribeToClosingActions();
}
const wasOpen = this.panelOpen;
this.autocomplete._isOpen = this._overlayAttached = true;
this.autocomplete._latestOpeningTrigger = this;
this.autocomplete._setColor(this._formField?.color);
this._updatePanelState();
this._applyModalPanelOwnership();
if (this.panelOpen && wasOpen !== this.panelOpen) {
this._emitOpened();
}
}
_handlePanelKeydown = event => {
if (event.keyCode === ESCAPE && !hasModifierKey(event) || event.keyCode === UP_ARROW && hasModifierKey(event, 'altKey')) {
if (this._pendingAutoselectedOption) {
this._updateNativeInputValue(this._valueBeforeAutoSelection ?? '');
this._pendingAutoselectedOption = null;
}
this._closeKeyEventStream.next();
this._resetActiveItem();
event.stopPropagation();
event.preventDefault();
}
};
_updatePanelState() {
this.autocomplete._setVisibility();
if (this.panelOpen) {
const overlayRef = this._overlayRef;
if (!this._keydownSubscription) {
this._keydownSubscription = overlayRef.keydownEvents().subscribe(this._handlePanelKeydown);
}
if (!this._outsideClickSubscription) {
this._outsideClickSubscription = overlayRef.outsidePointerEvents().subscribe();
}
} else {
this._keydownSubscription?.unsubscribe();
this._outsideClickSubscription?.unsubscribe();
this._keydownSubscription = this._outsideClickSubscription = null;
}
}
_getOverlayConfig() {
return new OverlayConfig({
positionStrategy: this._getOverlayPosition(),
scrollStrategy: this._scrollStrategy(),
width: this._getPanelWidth(),
direction: this._dir ?? undefined,
hasBackdrop: this._defaults?.hasBackdrop,
backdropClass: this._defaults?.backdropClass || 'cdk-overlay-transparent-backdrop',
panelClass: this._overlayPanelClass,
disableAnimations: this._animationsDisabled
});
}
_getOverlayPosition() {
const strategy = createFlexibleConnectedPositionStrategy(this._injector, this._getConnectedElement()).withFlexibleDimensions(false).withPush(false).withPopoverLocation('inline');
this._setStrategyPositions(strategy);
this._positionStrategy = strategy;
return strategy;
}
_setStrategyPositions(positionStrategy) {
const belowPositions = [{
originX: 'start',
originY: 'bottom',
overlayX: 'start',
overlayY: 'top'
}, {
originX: 'end',
originY: 'bottom',
overlayX: 'end',
overlayY: 'top'
}];
const panelClass = this._aboveClass;
const abovePositions = [{
originX: 'start',
originY: 'top',
overlayX: 'start',
overlayY: 'bottom',
panelClass
}, {
originX: 'end',
originY: 'top',
overlayX: 'end',
overlayY: 'bottom',
panelClass
}];
let positions;
if (this.position === 'above') {
positions = abovePositions;
} else if (this.position === 'below') {
positions = belowPositions;
} else {
positions = [...belowPositions, ...abovePositions];
}
positionStrategy.withPositions(positions);
}
_getConnectedElement() {
if (this.connectedTo) {
return this.connectedTo.elementRef;
}
return this._formField ? this._formField.getConnectedOverlayOrigin() : this._element;
}
_getPanelWidth() {
return this.autocomplete.panelWidth || this._getHostWidth();
}
_getHostWidth() {
return this._getConnectedElement().nativeElement.getBoundingClientRect().width;
}
_resetActiveItem() {
const autocomplete = this.autocomplete;
if (autocomplete.autoActiveFirstOption) {
let firstEnabledOptionIndex = -1;
for (let index = 0; index < autocomplete.options.length; index++) {
const option = autocomplete.options.get(index);
if (!option.disabled) {
firstEnabledOptionIndex = index;
break;
}
}
autocomplete._keyManager.setActiveItem(firstEnabledOptionIndex);
} else {
autocomplete._keyManager.setActiveItem(-1);
}
}
_canOpen() {
const element = this._element.nativeElement;
return !element.readOnly && !element.disabled && !this.autocompleteDisabled;
}
_scrollToOption(index) {
const autocomplete = this.autocomplete;
const labelCount = _countGroupLabelsBeforeOption(index, autocomplete.options, autocomplete.optionGroups);
if (index === 0 && labelCount === 1) {
autocomplete._setScrollTop(0);
} else if (autocomplete.panel) {
const option = autocomplete.options.toArray()[index];
if (option) {
const element = option._getHostElement();
const newScrollPosition = _getOptionScrollPosition(element.offsetTop, element.offsetHeight, autocomplete._getScrollTop(), autocomplete.panel.nativeElement.offsetHeight);
autocomplete._setScrollTop(newScrollPosition);
}
}
}
_trackedModal = null;
_applyModalPanelOwnership() {
const modal = this._element.nativeElement.closest('body > .cdk-overlay-container [aria-modal="true"]');
if (!modal) {
return;
}
const panelId = this.autocomplete.id;
if (this._trackedModal) {
removeAriaReferencedId(this._trackedModal, 'aria-owns', panelId);
}
addAriaReferencedId(modal, 'aria-owns', panelId);
this._trackedModal = modal;
}
_clearFromModal() {
if (this._trackedModal) {
const panelId = this.autocomplete.id;
removeAriaReferencedId(this._trackedModal, 'aria-owns', panelId);
this._trackedModal = null;
}
}
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocompleteTrigger,
deps: [],
target: i0.ɵɵFactoryTarget.Directive
});
static ɵdir = i0.ɵɵngDeclareDirective({
minVersion: "16.1.0",
version: "21.0.3",
type: MatAutocompleteTrigger,
isStandalone: true,
selector: "input[matAutocomplete], textarea[matAutocomplete]",
inputs: {
autocomplete: ["matAutocomplete", "autocomplete"],
position: ["matAutocompletePosition", "position"],
connectedTo: ["matAutocompleteConnectedTo", "connectedTo"],
autocompleteAttribute: ["autocomplete", "autocompleteAttribute"],
autocompleteDisabled: ["matAutocompleteDisabled", "autocompleteDisabled", booleanAttribute]
},
host: {
listeners: {
"focusin": "_handleFocus()",
"blur": "_onTouched()",
"input": "_handleInput($event)",
"keydown": "_handleKeydown($event)",
"click": "_handleClick()"
},
properties: {
"attr.autocomplete": "autocompleteAttribute",
"attr.role": "autocompleteDisabled ? null : \"combobox\"",
"attr.aria-autocomplete": "autocompleteDisabled ? null : \"list\"",
"attr.aria-activedescendant": "(panelOpen && activeOption) ? activeOption.id : null",
"attr.aria-expanded": "autocompleteDisabled ? null : panelOpen.toString()",
"attr.aria-controls": "(autocompleteDisabled || !panelOpen) ? null : autocomplete?.id",
"attr.aria-haspopup": "autocompleteDisabled ? null : \"listbox\""
},
classAttribute: "mat-mdc-autocomplete-trigger"
},
providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR],
exportAs: ["matAutocompleteTrigger"],
usesOnChanges: true,
ngImport: i0
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocompleteTrigger,
decorators: [{
type: Directive,
args: [{
selector: `input[matAutocomplete], textarea[matAutocomplete]`,
host: {
'class': 'mat-mdc-autocomplete-trigger',
'[attr.autocomplete]': 'autocompleteAttribute',
'[attr.role]': 'autocompleteDisabled ? null : "combobox"',
'[attr.aria-autocomplete]': 'autocompleteDisabled ? null : "list"',
'[attr.aria-activedescendant]': '(panelOpen && activeOption) ? activeOption.id : null',
'[attr.aria-expanded]': 'autocompleteDisabled ? null : panelOpen.toString()',
'[attr.aria-controls]': '(autocompleteDisabled || !panelOpen) ? null : autocomplete?.id',
'[attr.aria-haspopup]': 'autocompleteDisabled ? null : "listbox"',
'(focusin)': '_handleFocus()',
'(blur)': '_onTouched()',
'(input)': '_handleInput($event)',
'(keydown)': '_handleKeydown($event)',
'(click)': '_handleClick()'
},
exportAs: 'matAutocompleteTrigger',
providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR]
}]
}],
ctorParameters: () => [],
propDecorators: {
autocomplete: [{
type: Input,
args: ['matAutocomplete']
}],
position: [{
type: Input,
args: ['matAutocompletePosition']
}],
connectedTo: [{
type: Input,
args: ['matAutocompleteConnectedTo']
}],
autocompleteAttribute: [{
type: Input,
args: ['autocomplete']
}],
autocompleteDisabled: [{
type: Input,
args: [{
alias: 'matAutocompleteDisabled',
transform: booleanAttribute
}]
}]
}
});
class MatAutocompleteModule {
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocompleteModule,
deps: [],
target: i0.ɵɵFactoryTarget.NgModule
});
static ɵmod = i0.ɵɵngDeclareNgModule({
minVersion: "14.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocompleteModule,
imports: [OverlayModule, MatOptionModule, MatAutocomplete, MatAutocompleteTrigger, MatAutocompleteOrigin],
exports: [CdkScrollableModule, MatAutocomplete, MatOptionModule, BidiModule, MatAutocompleteTrigger, MatAutocompleteOrigin]
});
static ɵinj = i0.ɵɵngDeclareInjector({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocompleteModule,
imports: [OverlayModule, MatOptionModule, CdkScrollableModule, MatOptionModule, BidiModule]
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.3",
ngImport: i0,
type: MatAutocompleteModule,
decorators: [{
type: NgModule,
args: [{
imports: [OverlayModule, MatOptionModule, MatAutocomplete, MatAutocompleteTrigger, MatAutocompleteOrigin],
exports: [CdkScrollableModule, MatAutocomplete, MatOptionModule, BidiModule, MatAutocompleteTrigger, MatAutocompleteOrigin]
}]
}]
});
export { MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, MAT_AUTOCOMPLETE_SCROLL_STRATEGY, MAT_AUTOCOMPLETE_VALUE_ACCESSOR, MatAutocomplete, MatAutocompleteModule, MatAutocompleteOrigin, MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatOption, getMatAutocompleteMissingPanelError };
//# sourceMappingURL=autocomplete.mjs.map