UNPKG

@angular/material

Version:
1,069 lines (1,063 loc) 40.1 kB
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.0", ngImport: i0, type: MatAutocomplete, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.0.0", 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.0", 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.0", ngImport: i0, type: MatAutocompleteOrigin, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.0", type: MatAutocompleteOrigin, isStandalone: true, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", 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.0", ngImport: i0, type: MatAutocompleteTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.0.0", 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.0", 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.0", ngImport: i0, type: MatAutocompleteModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.0", 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.0", ngImport: i0, type: MatAutocompleteModule, imports: [OverlayModule, MatOptionModule, CdkScrollableModule, MatOptionModule, BidiModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", 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