Skip to content

Commit 0460f27

Browse files
committed
fix(form-field): fixes for outline appearance (#9759)
* use the `AutofillMonitor` in `MatInput` * Make `updateOutlineGap` public so users can call it if needed
1 parent 0981c23 commit 0460f27

8 files changed

+35
-25
lines changed

src/lib/form-field/_form-field-fill-theme.scss

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,6 @@ $mat-form-field-fill-dedupe: 0;
8787
$infix-margin-top);
8888
}
8989

90-
.mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper
91-
.mat-form-field-label {
92-
@include _mat-form-field-fill-label-floating(
93-
$subscript-font-scale, $infix-padding-top + $fill-appearance-label-offset,
94-
$infix-margin-top);
95-
}
96-
9790
// Server-side rendered matInput with a label attribute but label not shown
9891
// (used as a pure CSS stand-in for mat-form-field-should-float).
9992
.mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper

src/lib/form-field/_form-field-legacy-theme.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ $mat-form-field-legacy-dedupe: 0;
8787
$subscript-font-scale, $infix-padding, $infix-margin-top);
8888
}
8989

90+
// @deletion-target 7.0.0 will rely on AutofillMonitor instead.
9091
.mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper
9192
.mat-form-field-label {
9293
@include _mat-form-field-legacy-label-floating(

src/lib/form-field/_form-field-outline-theme.scss

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,6 @@ $mat-form-field-outline-dedupe: 0;
123123
$infix-margin-top);
124124
}
125125

126-
.mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper
127-
.mat-form-field-label {
128-
@include _mat-form-field-outline-label-floating(
129-
$subscript-font-scale, $infix-padding + $outline-appearance-label-offset,
130-
$infix-margin-top);
131-
}
132-
133126
// Server-side rendered matInput with a label attribute but label not shown
134127
// (used as a pure CSS stand-in for mat-form-field-should-float).
135128
.mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper

src/lib/form-field/_form-field-theme.scss

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,6 @@ $mat-form-field-dedupe: 0;
182182
$subscript-font-scale, $infix-padding, $infix-margin-top);
183183
}
184184

185-
.mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper
186-
.mat-form-field-label {
187-
@include _mat-form-field-label-floating(
188-
$subscript-font-scale, $infix-padding, $infix-margin-top);
189-
}
190-
191185
// Server-side rendered matInput with a label attribute but label not shown
192186
// (used as a pure CSS stand-in for mat-form-field-should-float).
193187
.mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper

src/lib/form-field/form-field-control.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ export abstract class MatFormFieldControl<T> {
6262
*/
6363
readonly controlType?: string;
6464

65+
/**
66+
* Whether the input is currently in an autofilled state. If property is not present on the
67+
* control it is assumed to be false.
68+
*/
69+
readonly autofilled?: boolean;
70+
6571
/** Sets the list of element IDs that currently describe this control. */
6672
abstract setDescribedByIds(ids: string[]): void;
6773

src/lib/form-field/form-field.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ $mat-form-field-default-infix-width: 180px !default;
107107
// This is necessary because these browsers do not actually fire any events when a form auto-fill is
108108
// occurring. Once the autofill is committed, a change event happen and the regular mat-form-field
109109
// classes take over to fulfill this behaviour.
110+
// @deletion-target 7.0.0 will rely on AutofillMonitor instead.
110111
.mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper
111112
.mat-form-field-label {
112113
// The form field will be considered empty if it is autofilled, and therefore the label will

src/lib/form-field/form-field.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export type MatFormFieldAppearance = 'legacy' | 'standard' | 'fill' | 'outline';
100100
'[class.mat-form-field-should-float]': '_shouldLabelFloat()',
101101
'[class.mat-form-field-hide-placeholder]': '_hideControlPlaceholder()',
102102
'[class.mat-form-field-disabled]': '_control.disabled',
103+
'[class.mat-form-field-autofilled]': '_control.autofilled',
103104
'[class.mat-focused]': '_control.focused',
104105
'[class.mat-accent]': 'color == "accent"',
105106
'[class.mat-warn]': 'color == "warn"',
@@ -266,7 +267,7 @@ export class MatFormField extends _MatFormFieldMixinBase
266267
});
267268

268269
Promise.resolve().then(() => {
269-
this._updateOutlineGap();
270+
this.updateOutlineGap();
270271
this._changeDetectorRef.detectChanges();
271272
});
272273
}
@@ -413,7 +414,7 @@ export class MatFormField extends _MatFormFieldMixinBase
413414
* Updates the width and position of the gap in the outline. Only relevant for the outline
414415
* appearance.
415416
*/
416-
private _updateOutlineGap() {
417+
updateOutlineGap() {
417418
if (this.appearance === 'outline' && this._label && this._label.nativeElement.children.length) {
418419
const containerStart = this._getStartEnd(
419420
this._connectionContainerRef.nativeElement.getBoundingClientRect());

src/lib/input/input.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@ import {
1414
ElementRef,
1515
Inject,
1616
Input,
17+
NgZone,
1718
OnChanges,
1819
OnDestroy,
1920
Optional,
2021
Self,
2122
} from '@angular/core';
2223
import {FormGroupDirective, NgControl, NgForm} from '@angular/forms';
23-
import {ErrorStateMatcher, mixinErrorState, CanUpdateErrorState} from '@angular/material/core';
24+
import {CanUpdateErrorState, ErrorStateMatcher, mixinErrorState} from '@angular/material/core';
2425
import {MatFormFieldControl} from '@angular/material/form-field';
2526
import {Subject} from 'rxjs/Subject';
27+
import {AutofillMonitor} from './autofill';
2628
import {getMatInputUnsupportedTypeError} from './input-errors';
2729
import {MAT_INPUT_VALUE_ACCESSOR} from './input-value-accessor';
2830

@@ -58,6 +60,9 @@ export const _MatInputMixinBase = mixinErrorState(MatInputBase);
5860
selector: `input[matInput], textarea[matInput]`,
5961
exportAs: 'matInput',
6062
host: {
63+
/**
64+
* @deletion-target 7.0.0 remove .mat-form-field-autofill-control in favor of AutofillMonitor.
65+
*/
6166
'class': 'mat-input-element mat-form-field-autofill-control',
6267
'[class.mat-input-server]': '_isServer',
6368
// Native input properties that are overwritten by Angular inputs need to be synced with
@@ -105,6 +110,12 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
105110
*/
106111
controlType: string = 'mat-input';
107112

113+
/**
114+
* Implemented as part of MatFormFieldControl.
115+
* @docs-private
116+
*/
117+
autofilled = false;
118+
108119
/**
109120
* Implemented as part of MatFormFieldControl.
110121
* @docs-private
@@ -206,7 +217,9 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
206217
@Optional() _parentForm: NgForm,
207218
@Optional() _parentFormGroup: FormGroupDirective,
208219
_defaultErrorStateMatcher: ErrorStateMatcher,
209-
@Optional() @Self() @Inject(MAT_INPUT_VALUE_ACCESSOR) inputValueAccessor: any) {
220+
@Optional() @Self() @Inject(MAT_INPUT_VALUE_ACCESSOR) inputValueAccessor: any,
221+
private _autofillMonitor: AutofillMonitor,
222+
ngZone: NgZone) {
210223
super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl);
211224
// If no input value accessor was explicitly specified, use the element as the input value
212225
// accessor.
@@ -233,6 +246,12 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
233246
});
234247
}
235248

249+
this._autofillMonitor.monitor(this._elementRef.nativeElement)
250+
.subscribe(event => ngZone.run(() => {
251+
this.autofilled = event.isAutofilled;
252+
this.stateChanges.next();
253+
}));
254+
236255
this._isServer = !this._platform.isBrowser;
237256
}
238257

@@ -242,6 +261,7 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
242261

243262
ngOnDestroy() {
244263
this.stateChanges.complete();
264+
this._autofillMonitor.stopMonitoring(this._elementRef.nativeElement);
245265
}
246266

247267
ngDoCheck() {
@@ -324,7 +344,8 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
324344
* @docs-private
325345
*/
326346
get empty(): boolean {
327-
return !this._isNeverEmpty() && !this._elementRef.nativeElement.value && !this._isBadInput();
347+
return !this._isNeverEmpty() && !this._elementRef.nativeElement.value && !this._isBadInput() &&
348+
!this.autofilled;
328349
}
329350

330351
/**

0 commit comments

Comments
 (0)