From aa680c2682a49ac33b05660977e310ab3729ee1f Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 18 Feb 2021 18:01:22 -0800 Subject: [PATCH 1/4] feat(material-experimental/mdc-form-field): separate out text and icon prefixes/suffixes --- src/dev-app/mdc-input/mdc-input-demo.html | 56 +++++++++++++------ .../mdc-form-field/_form-field-theme.scss | 4 +- .../mdc-form-field/directives/prefix.ts | 3 +- .../mdc-form-field/directives/suffix.ts | 3 +- .../mdc-form-field/form-field.html | 14 +++-- .../mdc-form-field/form-field.scss | 5 ++ .../mdc-form-field/form-field.ts | 13 +++-- .../testing/form-field-harness.ts | 4 +- 8 files changed, 70 insertions(+), 32 deletions(-) diff --git a/src/dev-app/mdc-input/mdc-input-demo.html b/src/dev-app/mdc-input/mdc-input-demo.html index 313f13761adf..a091105202f6 100644 --- a/src/dev-app/mdc-input/mdc-input-demo.html +++ b/src/dev-app/mdc-input/mdc-input-demo.html @@ -124,32 +124,50 @@

Text

Amount - - .00 + $ + .00

Text (always outline)

Amount - - .00 + $ + .00

Icons

Amount - calendar_today - mode_edit + calendar_today + mode_edit

Icon buttons

Amount - - + + + + +

Text & Icons

+ + Amount + + $ + .00 + +

@@ -371,20 +389,22 @@

Textarea

Prefixed -
Example: 
+ Example: 
Suffixed - .00 € + .00 €
Both: Email address - email  -  @gmail.com + + email  + +  @gmail.com

@@ -679,8 +699,8 @@

<textarea> with bindable autosize

Amount - - .00 + + .00 @@ -692,9 +712,9 @@

<textarea> with bindable autosize

Amount - - - .00 + + + .00
@@ -724,7 +744,7 @@

Custom control

Phone number - phone + phone Include area code

diff --git a/src/material-experimental/mdc-form-field/_form-field-theme.scss b/src/material-experimental/mdc-form-field/_form-field-theme.scss index b6af728250ba..28ed69fb3887 100644 --- a/src/material-experimental/mdc-form-field/_form-field-theme.scss +++ b/src/material-experimental/mdc-form-field/_form-field-theme.scss @@ -75,8 +75,8 @@ // the correct level. .mat-mdc-input-element, .mat-mdc-form-field label, - .mat-mdc-form-field-prefix, - .mat-mdc-form-field-suffix { + .mat-mdc-form-field-text-prefix, + .mat-mdc-form-field-text-suffix { @include mdc-typography(body1, $query: mdc-helpers.$mat-typography-styles-query); } } diff --git a/src/material-experimental/mdc-form-field/directives/prefix.ts b/src/material-experimental/mdc-form-field/directives/prefix.ts index bc8af2c2a3a1..33cec4845f19 100644 --- a/src/material-experimental/mdc-form-field/directives/prefix.ts +++ b/src/material-experimental/mdc-form-field/directives/prefix.ts @@ -17,7 +17,8 @@ export const MAT_PREFIX = new InjectionToken('MatPrefix'); /** Prefix to be placed in front of the form field. */ @Directive({ - selector: '[matPrefix]', + /** @breaking-change 13.0.0 remove [matPrefix] */ + selector: '[matPrefix], [matIconPrefix], [matTextPrefix]', providers: [{provide: MAT_PREFIX, useExisting: MatPrefix}], }) export class MatPrefix {} diff --git a/src/material-experimental/mdc-form-field/directives/suffix.ts b/src/material-experimental/mdc-form-field/directives/suffix.ts index edc35cbf1838..200e73dbcc67 100644 --- a/src/material-experimental/mdc-form-field/directives/suffix.ts +++ b/src/material-experimental/mdc-form-field/directives/suffix.ts @@ -17,7 +17,8 @@ export const MAT_SUFFIX = new InjectionToken('MatSuffix'); /** Suffix to be placed at the end of the form field. */ @Directive({ - selector: '[matSuffix]', + /** @breaking-change 13.0.0 remove [matSuffix] */ + selector: '[matSuffix], [matIconSuffix], [matTextSuffix]', providers: [{provide: MAT_SUFFIX, useExisting: MatSuffix}], }) export class MatSuffix {} diff --git a/src/material-experimental/mdc-form-field/form-field.html b/src/material-experimental/mdc-form-field/form-field.html index bb2d512011b9..030f5f19450e 100644 --- a/src/material-experimental/mdc-form-field/form-field.html +++ b/src/material-experimental/mdc-form-field/form-field.html @@ -44,8 +44,11 @@ -
- +
+ +
+
+
@@ -56,8 +59,11 @@
-
- +
+ +
+
+
diff --git a/src/material-experimental/mdc-form-field/form-field.scss b/src/material-experimental/mdc-form-field/form-field.scss index dfd33d6e0e59..8cab9b93a80c 100644 --- a/src/material-experimental/mdc-form-field/form-field.scss +++ b/src/material-experimental/mdc-form-field/form-field.scss @@ -52,6 +52,11 @@ width: 100%; } +.mat-mdc-form-field-icon-prefix, +.mat-mdc-form-field-icon-suffix { + align-self: center; +} + // Infix that contains the projected content (usually an input or a textarea). We ensure // that the projected form-field control and content can stretch as needed, but we also // apply a default infix width to make the form-field's look natural. diff --git a/src/material-experimental/mdc-form-field/form-field.ts b/src/material-experimental/mdc-form-field/form-field.ts index 3ef7684f4d1a..8b70cae3c8cf 100644 --- a/src/material-experimental/mdc-form-field/form-field.ts +++ b/src/material-experimental/mdc-form-field/form-field.ts @@ -134,7 +134,8 @@ const FLOATING_LABEL_DEFAULT_DOCKED_TRANSFORM = `translateY(-50%)`; export class MatFormField implements AfterViewInit, OnDestroy, AfterContentChecked, AfterContentInit { @ViewChild('textField') _textField: ElementRef; - @ViewChild('prefixContainer') _prefixContainer: ElementRef; + @ViewChild('iconPrefixContainer') _iconPrefixContainer: ElementRef; + @ViewChild('textPrefixContainer') _textPrefixContainer: ElementRef; @ViewChild(MatFormFieldFloatingLabel) _floatingLabel: MatFormFieldFloatingLabel|undefined; @ViewChild(MatFormFieldNotchedOutline) _notchedOutline: MatFormFieldNotchedOutline|undefined; @ViewChild(MatFormFieldLineRipple) _lineRipple: MatFormFieldLineRipple|undefined; @@ -654,7 +655,7 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck const floatingLabel = this._floatingLabel.element; // If no prefix is displayed, reset the outline label offset from potential // previous label offset updates. - if (!this._prefixContainer) { + if (!(this._iconPrefixContainer || this._textPrefixContainer)) { floatingLabel.style.transform = ''; return; } @@ -664,11 +665,15 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck this._needsOutlineLabelOffsetUpdateOnStable = true; return; } - const prefixContainer = this._prefixContainer.nativeElement as HTMLElement; + const iconPrefixContainer = this._iconPrefixContainer.nativeElement as HTMLElement; + const textPrefixContainer = this._textPrefixContainer.nativeElement as HTMLElement; // If the directionality is RTL, the x-axis transform needs to be inverted. This // is because `transformX` does not change based on the page directionality. const labelHorizontalOffset = - (this._dir.value === 'rtl' ? -1 : 1) * prefixContainer.getBoundingClientRect().width; + (this._dir.value === 'rtl' ? -1 : 1) * ( + iconPrefixContainer.getBoundingClientRect().width + + textPrefixContainer.getBoundingClientRect().width + ); // Update the transform the floating label to account for the prefix container. Note // that we do not want to overwrite the default transform for docked floating labels. diff --git a/src/material-experimental/mdc-form-field/testing/form-field-harness.ts b/src/material-experimental/mdc-form-field/testing/form-field-harness.ts index fb892b7c3043..23f798b5ac7e 100644 --- a/src/material-experimental/mdc-form-field/testing/form-field-harness.ts +++ b/src/material-experimental/mdc-form-field/testing/form-field-harness.ts @@ -37,8 +37,8 @@ export class MatFormFieldHarness extends _MatFormFieldHarnessBase await harness.hasErrors() === hasErrors); } - protected _prefixContainer = this.locatorForOptional('.mat-mdc-form-field-prefix'); - protected _suffixContainer = this.locatorForOptional('.mat-mdc-form-field-suffix'); + protected _prefixContainer = this.locatorForOptional('.mat-mdc-form-field-text-prefix'); + protected _suffixContainer = this.locatorForOptional('.mat-mdc-form-field-text-suffix'); protected _label = this.locatorForOptional('.mdc-floating-label'); protected _errors = this.locatorForAll('.mat-mdc-form-field-error'); protected _hints = this.locatorForAll('.mat-mdc-form-field-hint'); From 162849b9d9a43622403fa683745148423d426120 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 18 Feb 2021 22:46:05 -0800 Subject: [PATCH 2/4] fixup! feat(material-experimental/mdc-form-field): separate out text and icon prefixes/suffixes --- src/material/form-field/testing/shared.spec.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/material/form-field/testing/shared.spec.ts b/src/material/form-field/testing/shared.spec.ts index d6801d879e64..b00a5ef0f1f8 100644 --- a/src/material/form-field/testing/shared.spec.ts +++ b/src/material/form-field/testing/shared.spec.ts @@ -1,8 +1,5 @@ import {ComponentHarness, HarnessLoader, HarnessPredicate, parallel} from '@angular/cdk/testing'; -import { - createFakeEvent, - dispatchFakeEvent, -} from '@angular/cdk/testing/private'; +import {createFakeEvent, dispatchFakeEvent} from '@angular/cdk/testing/private'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {Component, Type} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; @@ -30,6 +27,7 @@ export function runHarnessTests( .compileComponents(); fixture = TestBed.createComponent(FormFieldHarnessTest); + fixture.componentInstance.isMdc = isMdcImplementation; fixture.detectChanges(); loader = TestbedHarnessEnvironment.loader(fixture); }); @@ -243,11 +241,14 @@ export function runHarnessTests( @Component({ template: ` - prefix_text - prefix_text_2 + prefix_text + prefix_text_2 + prefix_text + prefix_text_2 - suffix_text + suffix_text + suffix_text @@ -287,6 +288,7 @@ class FormFieldHarnessTest { shouldLabelFloat: 'always'|'auto' = 'auto'; hasLabel = false; isDisabled = false; + isMdc = false; setupAsyncValidator() { this.requiredControl.setValidators(() => null); From f798e2f9f72bccc5ff1889705b4ebaa92d42d84a Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Fri, 19 Feb 2021 14:56:37 -0800 Subject: [PATCH 3/4] fixup! feat(material-experimental/mdc-form-field): separate out text and icon prefixes/suffixes --- src/material-experimental/mdc-form-field/directives/prefix.ts | 1 - src/material-experimental/mdc-form-field/directives/suffix.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/material-experimental/mdc-form-field/directives/prefix.ts b/src/material-experimental/mdc-form-field/directives/prefix.ts index 33cec4845f19..d44b3cd423e3 100644 --- a/src/material-experimental/mdc-form-field/directives/prefix.ts +++ b/src/material-experimental/mdc-form-field/directives/prefix.ts @@ -17,7 +17,6 @@ export const MAT_PREFIX = new InjectionToken('MatPrefix'); /** Prefix to be placed in front of the form field. */ @Directive({ - /** @breaking-change 13.0.0 remove [matPrefix] */ selector: '[matPrefix], [matIconPrefix], [matTextPrefix]', providers: [{provide: MAT_PREFIX, useExisting: MatPrefix}], }) diff --git a/src/material-experimental/mdc-form-field/directives/suffix.ts b/src/material-experimental/mdc-form-field/directives/suffix.ts index 200e73dbcc67..cca32a9996ca 100644 --- a/src/material-experimental/mdc-form-field/directives/suffix.ts +++ b/src/material-experimental/mdc-form-field/directives/suffix.ts @@ -17,7 +17,6 @@ export const MAT_SUFFIX = new InjectionToken('MatSuffix'); /** Suffix to be placed at the end of the form field. */ @Directive({ - /** @breaking-change 13.0.0 remove [matSuffix] */ selector: '[matSuffix], [matIconSuffix], [matTextSuffix]', providers: [{provide: MAT_SUFFIX, useExisting: MatSuffix}], }) From 0b6589c963183a34d17fac13d692d1e67cb65d8c Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 25 Feb 2021 12:31:08 -0800 Subject: [PATCH 4/4] fixup! feat(material-experimental/mdc-form-field): separate out text and icon prefixes/suffixes --- .../mdc-input/BUILD.bazel | 1 + .../mdc-input/input.spec.ts | 38 ++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/material-experimental/mdc-input/BUILD.bazel b/src/material-experimental/mdc-input/BUILD.bazel index 6fdd1291a26c..dfb6eb12c3ef 100644 --- a/src/material-experimental/mdc-input/BUILD.bazel +++ b/src/material-experimental/mdc-input/BUILD.bazel @@ -53,6 +53,7 @@ ng_test_library( "//src/material-experimental/mdc-core", "//src/material-experimental/mdc-form-field", "//src/material/core", + "//src/material/icon", "@npm//@angular/forms", "@npm//@angular/platform-browser", ], diff --git a/src/material-experimental/mdc-input/input.spec.ts b/src/material-experimental/mdc-input/input.spec.ts index 19749729ee05..298d014b370c 100644 --- a/src/material-experimental/mdc-input/input.spec.ts +++ b/src/material-experimental/mdc-input/input.spec.ts @@ -20,19 +20,20 @@ import { Validators, } from '@angular/forms'; import { + ErrorStateMatcher, + ShowOnDirtyErrorStateMatcher, + ThemePalette, +} from '@angular/material-experimental/mdc-core'; +import { + FloatLabelType, getMatFormFieldDuplicatedHintError, getMatFormFieldMissingControlError, MAT_FORM_FIELD_DEFAULT_OPTIONS, MatFormField, MatFormFieldAppearance, MatFormFieldModule, - FloatLabelType, } from '@angular/material-experimental/mdc-form-field'; -import { - ErrorStateMatcher, - ShowOnDirtyErrorStateMatcher, - ThemePalette, -} from '@angular/material-experimental/mdc-core'; +import {MatIconModule} from '@angular/material/icon'; import {By} from '@angular/platform-browser'; import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; import {MAT_INPUT_VALUE_ACCESSOR, MatInput, MatInputModule} from './index'; @@ -701,13 +702,19 @@ describe('MatMdcInput without forms', () => { const fixture = createComponent(MatInputWithPrefixAndSuffix); fixture.detectChanges(); - const prefixEl = fixture.debugElement.query(By.css('.mat-mdc-form-field-prefix'))!; - const suffixEl = fixture.debugElement.query(By.css('.mat-mdc-form-field-suffix'))!; + const textPrefixEl = fixture.debugElement.query(By.css('.mat-mdc-form-field-text-prefix'))!; + const textSuffixEl = fixture.debugElement.query(By.css('.mat-mdc-form-field-text-suffix'))!; + const iconPrefixEl = fixture.debugElement.query(By.css('.mat-mdc-form-field-icon-prefix'))!; + const iconSuffixEl = fixture.debugElement.query(By.css('.mat-mdc-form-field-icon-suffix'))!; - expect(prefixEl).not.toBeNull(); - expect(suffixEl).not.toBeNull(); - expect(prefixEl.nativeElement.innerText.trim()).toEqual('Prefix'); - expect(suffixEl.nativeElement.innerText.trim()).toEqual('Suffix'); + expect(textPrefixEl).not.toBeNull(); + expect(textSuffixEl).not.toBeNull(); + expect(iconPrefixEl).not.toBeNull(); + expect(iconSuffixEl).not.toBeNull(); + expect(textPrefixEl.nativeElement.innerText.trim()).toEqual('Prefix'); + expect(textSuffixEl.nativeElement.innerText.trim()).toEqual('Suffix'); + expect(iconPrefixEl.nativeElement.innerText.trim()).toEqual('favorite'); + expect(iconSuffixEl.nativeElement.innerText.trim()).toEqual('favorite'); })); it('should update empty class when value changes programmatically and OnPush', fakeAsync(() => { @@ -1285,6 +1292,7 @@ function configureTestingModule(component: Type, options: imports: [ FormsModule, MatFormFieldModule, + MatIconModule, MatInputModule, animations ? BrowserAnimationsModule : NoopAnimationsModule, PlatformModule, @@ -1597,9 +1605,11 @@ class MatInputWithFormGroupErrorMessages { @Component({ template: ` -
Prefix
+ favorite +
Prefix
-
Suffix
+
Suffix
+ favorite
` })