From ade2cf88da8f25e84064f2d019668dcebb7b4e2e Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Wed, 5 Feb 2020 15:59:12 +0100 Subject: [PATCH] feat(material-experimental/mdc-form-field): support for disabling animations By leveraging the animations feature target, we can add support for disabling animations of the form-field. Unlike in non experimental Material components, the class for toggling the animations is now scoped to the component. This gives more fine-grained control and makes it public. The class doesn't need to be denoted as private, as it can be useful for implementers of custom form-field controls. Also fixes that the line-ripple styles are not included. --- .../mdc-form-field/form-field.scss | 16 +++++++++--- .../mdc-form-field/form-field.ts | 9 ++----- .../mdc-input/input.spec.ts | 26 ++++++++++++++----- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/material-experimental/mdc-form-field/form-field.scss b/src/material-experimental/mdc-form-field/form-field.scss index 0e500b9b9335..61297f0c4633 100644 --- a/src/material-experimental/mdc-form-field/form-field.scss +++ b/src/material-experimental/mdc-form-field/form-field.scss @@ -7,9 +7,10 @@ @import 'mdc-text-field-structure-overrides'; // Base styles for MDC notched-outline, MDC floating label and MDC text-field. -@include mdc-notched-outline-core-styles($query: $mat-base-styles-query); -@include mdc-floating-label-core-styles($query: $mat-base-styles-query); -@include mdc-text-field-core-styles($query: $mat-base-styles-query); +@include mdc-notched-outline-core-styles($query: $mat-base-styles-without-animation-query); +@include mdc-floating-label-core-styles($query: $mat-base-styles-without-animation-query); +@include mdc-text-field-core-styles($query: $mat-base-styles-without-animation-query); +@include mdc-line-ripple-core-styles($query: $mat-base-styles-without-animation-query); // MDC text-field overwrites. @include _mat-mdc-text-field-textarea-overrides(); @@ -52,3 +53,12 @@ min-height: $mdc-text-field-height; box-sizing: border-box; } + +// In order to make it possible for developers to disable animations for form-fields, +// we only activate the animation styles if animations are not explicitly disabled. +.mat-mdc-form-field:not(.mat-form-field-no-animations) { + @include mdc-notched-outline-core-styles($query: animation); + @include mdc-floating-label-core-styles($query: animation); + @include mdc-text-field-core-styles($query: animation); + @include mdc-line-ripple-core-styles($query: animation); +} diff --git a/src/material-experimental/mdc-form-field/form-field.ts b/src/material-experimental/mdc-form-field/form-field.ts index b370d7ad1b66..6fbad4f35b48 100644 --- a/src/material-experimental/mdc-form-field/form-field.ts +++ b/src/material-experimental/mdc-form-field/form-field.ts @@ -93,6 +93,7 @@ const DEFAULT_FLOAT_LABEL: FloatLabelType = 'auto'; '[class.mat-form-field-invalid]': '_control.errorState', '[class.mat-form-field-disabled]': '_control.disabled', '[class.mat-form-field-autofilled]': '_control.autofilled', + '[class.mat-form-field-no-animations]': '_animationMode === "NoopAnimations"', '[class.mat-focused]': '_control.focused', '[class.mat-accent]': 'color == "accent"', '[class.mat-warn]': 'color == "warn"', @@ -103,7 +104,6 @@ const DEFAULT_FLOAT_LABEL: FloatLabelType = 'auto'; '[class.ng-valid]': '_shouldForward("valid")', '[class.ng-invalid]': '_shouldForward("invalid")', '[class.ng-pending]': '_shouldForward("pending")', - '[class._mat-animation-noopable]': '!_animationsEnabled', }, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, @@ -175,9 +175,6 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck // Unique id for the internal form field label. _labelId = `mat-form-field-label-${nextUniqueId++}`; - /** Whether the Angular animations are enabled. */ - _animationsEnabled: boolean; - /** State of the mat-hint and mat-error animations. */ _subscriptAnimationState: string = ''; @@ -260,9 +257,7 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck @Optional() @Inject(MAT_FORM_FIELD_DEFAULT_OPTIONS) private _defaults?: MatFormFieldDefaultOptions, @Optional() @Inject(MAT_LABEL_GLOBAL_OPTIONS) private _labelOptions?: LabelOptions, - @Optional() @Inject(ANIMATION_MODULE_TYPE) _animationMode?: string) { - this._animationsEnabled = _animationMode !== 'NoopAnimations'; - + @Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string) { if (_defaults && _defaults.appearance) { this.appearance = _defaults.appearance; } else if (_defaults && _defaults.hideRequiredMarker) { diff --git a/src/material-experimental/mdc-input/input.spec.ts b/src/material-experimental/mdc-input/input.spec.ts index fa355b0d65b2..2e7ef0b449db 100644 --- a/src/material-experimental/mdc-input/input.spec.ts +++ b/src/material-experimental/mdc-input/input.spec.ts @@ -33,7 +33,7 @@ import { ShowOnDirtyErrorStateMatcher, } from '@angular/material/core'; import {By} from '@angular/platform-browser'; -import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; import {MAT_INPUT_VALUE_ACCESSOR, MatInput, MatInputModule} from './index'; describe('MatMdcInput without forms', () => { @@ -400,6 +400,15 @@ describe('MatMdcInput without forms', () => { expect(selectEl.disabled).toBe(true); })); + it('should add a class to the form-field if animations are disabled', () => { + configureTestingModule(MatInputWithId, {animations: false}); + const fixture = TestBed.createComponent(MatInputWithId); + fixture.detectChanges(); + + const formFieldEl = fixture.nativeElement.querySelector('.mat-mdc-form-field'); + expect(formFieldEl.classList).toContain('mat-form-field-no-animations'); + }); + it('should add a class to the form field if it has a native select', fakeAsync(() => { const fixture = createComponent(MatInputSelect); fixture.detectChanges(); @@ -1139,16 +1148,15 @@ describe('MatFormField default options', () => { }); -function createComponent(component: Type, - providers: Provider[] = [], - imports: any[] = [], - declarations: any[] = []): ComponentFixture { +function configureTestingModule(component: Type, options: + {providers?: Provider[], imports?: any[], declarations?: any[], animations?: boolean} = {}) { + const {providers = [], imports = [], declarations = [], animations = true} = options; TestBed.configureTestingModule({ imports: [ FormsModule, MatFormFieldModule, MatInputModule, - BrowserAnimationsModule, + animations ? BrowserAnimationsModule : NoopAnimationsModule, PlatformModule, ReactiveFormsModule, ...imports @@ -1163,7 +1171,13 @@ function createComponent(component: Type, ...providers ], }).compileComponents(); +} +function createComponent(component: Type, + providers: Provider[] = [], + imports: any[] = [], + declarations: any[] = []): ComponentFixture { + configureTestingModule(component, {providers, imports, declarations}); return TestBed.createComponent(component); }