Skip to content

Commit

Permalink
fix(material/autocomplete): switch away from animations module (#30356)
Browse files Browse the repository at this point in the history
Switches the autocomplete away from the animations module. The animations are implemented using CSS instead.
  • Loading branch information
crisbeto authored Jan 21, 2025
1 parent 4fa46bc commit 013fe04
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 55 deletions.
36 changes: 0 additions & 36 deletions src/material/autocomplete/animations.ts

This file was deleted.

8 changes: 1 addition & 7 deletions src/material/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -736,13 +736,7 @@ export class MatAutocompleteTrigger
) {
this._clearPreviousSelectedOption(null);
this._assignOptionValue(null);
// Wait for the animation to finish before clearing the form control value, otherwise
// the options might change while the animation is running which looks glitchy.
if (panel._animationDone) {
panel._animationDone.pipe(take(1)).subscribe(() => this._onChange(null));
} else {
this._onChange(null);
}
this._onChange(null);
}

this.closePanel();
Expand Down
3 changes: 1 addition & 2 deletions src/material/autocomplete/autocomplete.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
[class]="_classList"
[class.mat-mdc-autocomplete-visible]="showPanel"
[class.mat-mdc-autocomplete-hidden]="!showPanel"
[class.mat-autocomplete-panel-animations-enabled]="!_animationsDisabled"
[class.mat-primary]="_color === 'primary'"
[class.mat-accent]="_color === 'accent'"
[class.mat-warn]="_color === 'warn'"
[attr.aria-label]="ariaLabel || null"
[attr.aria-labelledby]="_getPanelAriaLabelledby(formFieldId)"
[@panelAnimation]="isOpen ? 'visible' : 'hidden'"
(@panelAnimation.done)="_animationDone.next($event)"
#panel>
<ng-content></ng-content>
</div>
Expand Down
19 changes: 19 additions & 0 deletions src/material/autocomplete/autocomplete.scss
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,25 @@ div.mat-mdc-autocomplete-panel {
}
}

@keyframes _mat-autocomplete-enter {
from {
opacity: 0;
transform: scaleY(0.8);
}

to {
opacity: 1;
transform: none;
}
}

// Note: the autocomplete intentionally only implements an enter animation.
// The exit animation can look glitchy, because usually selecting an option
// causes the list to change and jump around while it's animating.
.mat-autocomplete-panel-animations-enabled {
animation: _mat-autocomplete-enter 120ms cubic-bezier(0, 0, 0.2, 1);
}

// Prevent the overlay host node from affecting its surrounding layout.
mat-autocomplete {
display: none;
Expand Down
4 changes: 4 additions & 0 deletions src/material/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3849,6 +3849,8 @@ describe('MatAutocomplete', () => {

dispatchFakeEvent(document.querySelector('mat-option')!, 'click');
fixture.detectChanges();
fixture.componentInstance.trigger.openPanel();
fixture.detectChanges();

const selectedOption = document.querySelector('mat-option[aria-selected="true"]');
expect(selectedOption).withContext('Expected an option to be selected.').not.toBeNull();
Expand All @@ -3875,6 +3877,8 @@ describe('MatAutocomplete', () => {

dispatchFakeEvent(document.querySelector('mat-option')!, 'click');
fixture.detectChanges();
fixture.componentInstance.trigger.openPanel();
fixture.detectChanges();

const selectedOption = document.querySelector('mat-option[aria-selected="true"]');
expect(selectedOption).withContext('Expected an option to be selected.').not.toBeNull();
Expand Down
11 changes: 3 additions & 8 deletions src/material/autocomplete/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {
ANIMATION_MODULE_TYPE,
AfterContentInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Expand All @@ -25,7 +26,6 @@ import {
booleanAttribute,
inject,
} from '@angular/core';
import {AnimationEvent} from '@angular/animations';
import {
MAT_OPTGROUP,
MAT_OPTION_PARENT_COMPONENT,
Expand All @@ -35,7 +35,6 @@ import {
} from '@angular/material/core';
import {_IdGenerator, ActiveDescendantKeyManager} from '@angular/cdk/a11y';
import {Platform} from '@angular/cdk/platform';
import {panelAnimation} from './animations';
import {Subscription} from 'rxjs';

/** Event object that is emitted when an autocomplete option is selected. */
Expand Down Expand Up @@ -109,18 +108,15 @@ export function MAT_AUTOCOMPLETE_DEFAULT_OPTIONS_FACTORY(): MatAutocompleteDefau
'class': 'mat-mdc-autocomplete',
},
providers: [{provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatAutocomplete}],
animations: [panelAnimation],
})
export class MatAutocomplete implements AfterContentInit, OnDestroy {
private _changeDetectorRef = inject(ChangeDetectorRef);
private _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
protected _defaults = inject<MatAutocompleteDefaultOptions>(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS);

protected _animationsDisabled =
inject(ANIMATION_MODULE_TYPE, {optional: true}) === 'NoopAnimations';
private _activeOptionChanges = Subscription.EMPTY;

/** Emits when the panel animation is done. Null if the panel doesn't animate. */
_animationDone = new EventEmitter<AnimationEvent>();

/** Manages active item in option list based on key events. */
_keyManager: ActiveDescendantKeyManager<MatOption>;

Expand Down Expand Up @@ -282,7 +278,6 @@ export class MatAutocomplete implements AfterContentInit, OnDestroy {
ngOnDestroy() {
this._keyManager?.destroy();
this._activeOptionChanges.unsubscribe();
this._animationDone.complete();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions tools/public_api_guard/material/autocomplete.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
import { AfterContentInit } from '@angular/core';
import { AfterViewInit } from '@angular/core';
import { AnimationEvent as AnimationEvent_2 } from '@angular/animations';
import { ControlValueAccessor } from '@angular/forms';
import { ElementRef } from '@angular/core';
import { EventEmitter } from '@angular/core';
Expand Down Expand Up @@ -57,7 +56,8 @@ export const MAT_AUTOCOMPLETE_VALUE_ACCESSOR: any;
// @public
export class MatAutocomplete implements AfterContentInit, OnDestroy {
constructor(...args: unknown[]);
_animationDone: EventEmitter<AnimationEvent_2>;
// (undocumented)
protected _animationsDisabled: boolean;
ariaLabel: string;
ariaLabelledby: string;
autoActiveFirstOption: boolean;
Expand Down

0 comments on commit 013fe04

Please sign in to comment.