Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 0614eba

Browse files
authored
feat(notched-outline): Change notched outline to use 3 divs (#1581)
As per material-components/material-components-web#4035
1 parent f4a7539 commit 0614eba

File tree

6 files changed

+82
-68
lines changed

6 files changed

+82
-68
lines changed

packages/floating-label/floating-label.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class MdcFloatingLabel implements AfterContentInit, OnDestroy {
2525

2626
@Input() for?: string;
2727

28-
createAdapter() {
28+
private _createAdapter() {
2929
return {
3030
addClass: (className: string) => this._getHostElement().classList.add(className),
3131
removeClass: (className: string) => this._getHostElement().classList.remove(className),
@@ -45,7 +45,7 @@ export class MdcFloatingLabel implements AfterContentInit, OnDestroy {
4545
public elementRef: ElementRef<HTMLElement>) { }
4646

4747
ngAfterContentInit(): void {
48-
this._foundation = new MDCFloatingLabelFoundation(this.createAdapter());
48+
this._foundation = new MDCFloatingLabelFoundation(this._createAdapter());
4949
this._loadListeners();
5050
}
5151

packages/line-ripple/line-ripple.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class MdcLineRipple implements OnInit, OnDestroy {
1919
/** Emits whenever the component is destroyed. */
2020
private _destroy = new Subject<void>();
2121

22-
createAdapter() {
22+
private _createAdapter() {
2323
return {
2424
addClass: (className: string) => this._getHostElement().classList.add(className),
2525
removeClass: (className: string) => this._getHostElement().classList.remove(className),
@@ -33,7 +33,7 @@ export class MdcLineRipple implements OnInit, OnDestroy {
3333
deactivate(): void,
3434
setRippleCenter(xCoordinate: number): void,
3535
handleTransitionEnd(evt: TransitionEvent): void
36-
} = new MDCLineRippleFoundation(this.createAdapter());
36+
} = new MDCLineRippleFoundation(this._createAdapter());
3737

3838
constructor(
3939
private _ngZone: NgZone,

packages/notched-outline/notched-outline-module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { NgModule } from '@angular/core';
22

3+
import { MdcFloatingLabelModule } from '@angular-mdc/web/floating-label';
34
import { MdcNotchedOutline } from './notched-outline';
45

56
@NgModule({
7+
imports: [MdcFloatingLabelModule],
68
exports: [MdcNotchedOutline],
79
declarations: [MdcNotchedOutline]
810
})

packages/notched-outline/notched-outline.ts

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,63 @@ import {
22
ChangeDetectionStrategy,
33
Component,
44
ElementRef,
5+
Input,
56
ViewChild,
67
ViewEncapsulation
78
} from '@angular/core';
8-
import { Platform } from '@angular-mdc/web/common';
9+
10+
import { MdcFloatingLabel } from '@angular-mdc/web/floating-label';
911

1012
import { MDCNotchedOutlineFoundation } from '@material/notched-outline/index';
1113

1214
@Component({
1315
moduleId: module.id,
1416
selector: '[mdcNotchedOutline], mdc-notched-outline',
1517
exportAs: 'mdcNotchedOutline',
18+
host: {
19+
'class': 'mdc-notched-outline',
20+
'[class.mdc-notched-outline--upgraded]': 'label',
21+
'[class.mdc-notched-outline--no-label]': '!label'
22+
},
1623
template: `
17-
<div #notchOutline class="mdc-notched-outline">
18-
<svg
19-
focusable="false">
20-
<path #svgpath class="mdc-notched-outline__path"/>
21-
</svg>
24+
<div class="mdc-notched-outline__leading"></div>
25+
<div #notch class="mdc-notched-outline__notch">
26+
<label mdcFloatingLabel [for]="for">{{label}}</label>
2227
</div>
23-
<div #notchIdle class="mdc-notched-outline__idle"></div>
28+
<div class="mdc-notched-outline__trailing"></div>
2429
`,
2530
changeDetection: ChangeDetectionStrategy.OnPush,
2631
encapsulation: ViewEncapsulation.None
2732
})
2833
export class MdcNotchedOutline {
29-
@ViewChild('notchOutline') _notchOutline!: ElementRef<HTMLElement>;
30-
@ViewChild('svgpath') _svgpath!: ElementRef;
31-
@ViewChild('notchIdle') _notchIdle!: ElementRef<HTMLElement>;
34+
@Input() label?: string;
35+
@Input() for?: string;
36+
@ViewChild('notch') _notchElement!: ElementRef<HTMLElement>;
37+
@ViewChild(MdcFloatingLabel) floatingLabel!: MdcFloatingLabel;
3238

33-
createAdapter() {
39+
private _createAdapter() {
3440
return {
35-
getWidth: () => this._notchOutline.nativeElement.offsetWidth,
36-
getHeight: () => this._notchOutline.nativeElement.offsetHeight,
37-
addClass: (className: string) => this._notchOutline.nativeElement.classList.add(className),
38-
removeClass: (className: string) => this._notchOutline.nativeElement.classList.remove(className),
39-
setOutlinePathAttr: (value: string) => this._svgpath.nativeElement.setAttribute('d', value),
40-
getIdleOutlineStyleValue: (propertyName: string) =>
41-
this._platform.isBrowser ? window.getComputedStyle(this._notchIdle.nativeElement).getPropertyValue(propertyName) : ''
41+
addClass: (className: string) => this.elementRef.nativeElement.classList.add(className),
42+
removeClass: (className: string) =>
43+
this.elementRef.nativeElement.classList.remove(className),
44+
setNotchWidthProperty: (width: number) =>
45+
this._notchElement.nativeElement.style.setProperty('width', width > 0 ? width + 'px' : '0')
4246
};
4347
}
4448

4549
private _foundation: {
46-
notch(notchWidth: number, isRtl: boolean): void,
50+
notch(notchWidth: number): void,
4751
closeNotch(): void
48-
} = new MDCNotchedOutlineFoundation(this.createAdapter());
52+
} = new MDCNotchedOutlineFoundation(this._createAdapter());
4953

50-
constructor(
51-
private _platform: Platform,
52-
public elementRef: ElementRef<HTMLElement>) { }
54+
constructor(public elementRef: ElementRef<HTMLElement>) { }
5355

54-
/** Updates outline selectors and SVG path to open notch. */
55-
notch(notchWidth: number, isRtl: boolean): void {
56-
this._foundation.notch(notchWidth, isRtl);
56+
/** Updates notched outline to open notch in outline path. */
57+
notch(notchWidth: number): void {
58+
this._foundation.notch(notchWidth);
5759
}
5860

59-
/** Updates the outline selectors to close notch and return it to idle state. */
61+
/** Updates the notched outline to close notch in outline path. */
6062
closeNotch(): void {
6163
this._foundation.closeNotch();
6264
}

packages/textfield/text-field.ts

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ let nextUniqueId = 0;
9191
(change)="onChange($event)"
9292
(blur)="onBlur()" />
9393
<ng-content></ng-content>
94-
<label mdcFloatingLabel [for]="id" *ngIf="!this.placeholder">{{label}}</label>
94+
<label mdcFloatingLabel [for]="id" *ngIf="!this.placeholder && !outlined">{{label}}</label>
9595
<mdc-line-ripple *ngIf="!this.outlined && !this.textarea"></mdc-line-ripple>
96-
<mdc-notched-outline *ngIf="outlined"></mdc-notched-outline>
96+
<mdc-notched-outline *ngIf="outlined" [label]="label" [for]="id"></mdc-notched-outline>
9797
`,
9898
providers: [
9999
MdcRipple,
@@ -138,7 +138,6 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
138138
const newValue = toBoolean(value);
139139
if (newValue !== this._outlined) {
140140
this._outlined = toBoolean(newValue);
141-
this._reinitialize();
142141
this.layout();
143142
}
144143
}
@@ -227,9 +226,9 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
227226
@Output() readonly blur = new EventEmitter<any>();
228227

229228
@ViewChild('input') _input!: ElementRef<HTMLInputElement | HTMLTextAreaElement>;
230-
@ViewChild(MdcFloatingLabel) _floatingLabel!: MdcFloatingLabel;
231229
@ViewChild(MdcLineRipple) _lineRipple!: MdcLineRipple;
232230
@ViewChild(MdcNotchedOutline) _notchedOutline!: MdcNotchedOutline;
231+
@ViewChild(MdcFloatingLabel) _floatingLabel!: MdcFloatingLabel;
233232
@ContentChildren(MdcTextFieldIcon, { descendants: true }) _icons!: QueryList<MdcTextFieldIcon>;
234233

235234
/** View -> model callback called when value changes */
@@ -248,9 +247,7 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
248247
addClass: (className: string) => this._getHostElement().classList.add(className),
249248
removeClass: (className: string) => this._getHostElement().classList.remove(className),
250249
hasClass: (className: string) => this._getHostElement().classList.contains(className),
251-
isFocused: () => this._platform.isBrowser ? document.activeElement! === this._getInputElement() : false,
252-
isRtl: () =>
253-
this._platform.isBrowser ? window.getComputedStyle(this._getHostElement()).getPropertyValue('direction') === 'rtl' : false
250+
isFocused: () => this._platform.isBrowser ? document.activeElement! === this._getInputElement() : false
254251
},
255252
this._getInputAdapterMethods(),
256253
this._getLabelAdapterMethods(),
@@ -267,7 +264,7 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
267264
value: this._value,
268265
disabled: this._disabled,
269266
validity: {
270-
valid: this._valid ? this._valid : this._platform.isBrowser ? this._input.nativeElement.validity.valid : true,
267+
valid: this._hasErrorState(),
271268
badInput: this._platform.isBrowser ? this._input.nativeElement.validity.badInput : false
272269
}
273270
};
@@ -277,10 +274,10 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
277274

278275
private _getLabelAdapterMethods() {
279276
return {
280-
shakeLabel: (shouldShake: boolean) => this._floatingLabel.shake(shouldShake),
281-
floatLabel: (shouldFloat: boolean) => this._floatingLabel.float(shouldFloat),
282-
hasLabel: () => this._floatingLabel,
283-
getLabelWidth: () => this._floatingLabel ? this._floatingLabel.getWidth() : 0
277+
shakeLabel: (shouldShake: boolean) => this._getFloatingLabel().shake(shouldShake),
278+
floatLabel: (shouldFloat: boolean) => this._getFloatingLabel().float(shouldFloat),
279+
hasLabel: () => this._hasFloatingLabel(),
280+
getLabelWidth: () => this._hasFloatingLabel() ? this._getFloatingLabel().getWidth() : 0
284281
};
285282
}
286283

@@ -307,7 +304,7 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
307304
private _getOutlineAdapterMethods() {
308305
return {
309306
hasOutline: () => this._notchedOutline,
310-
notchOutline: (labelWidth: number, isRtl: boolean) => this._notchedOutline.notch(labelWidth, isRtl),
307+
notchOutline: (labelWidth: number) => this._notchedOutline.notch(labelWidth),
311308
closeOutline: () => this._notchedOutline.closeNotch()
312309
};
313310
}
@@ -328,18 +325,18 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
328325
readonly shouldFloat: boolean,
329326
notchOutline(openNotch: boolean): void,
330327
setUseNativeValidation(useNativeValidation: boolean): void,
331-
setTransformOrigin(evt: Event): void,
328+
setTransformOrigin(evt: Event | TouchEvent): void,
332329
handleTextFieldInteraction(): void,
333330
activateFocus(): void,
334331
deactivateFocus(): void,
335332
handleValidationAttributeChange(attributesList?: string[]): void
336333
} = new MDCTextFieldFoundation();
337334

338335
constructor(
339-
public _defaultErrorStateMatcher: ErrorStateMatcher,
340336
private _platform: Platform,
341337
private _changeDetectorRef: ChangeDetectorRef,
342338
public elementRef: ElementRef<HTMLElement>,
339+
public _defaultErrorStateMatcher: ErrorStateMatcher,
343340
@Optional() private _parentFormField: MdcFormField,
344341
@Optional() private _ripple: MdcRipple,
345342
@Self() @Optional() public ngControl: NgControl,
@@ -367,10 +364,10 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
367364
}
368365

369366
ngOnDestroy(): void {
370-
this._destroyTextField();
367+
this._destroy();
371368
}
372369

373-
ngDoCheck() {
370+
ngDoCheck(): void {
374371
if (this.ngControl) {
375372
// We need to re-evaluate this on every change detection cycle, because there are some
376373
// error triggers that we can't subscribe to (e.g. parent form submissions). This means
@@ -475,6 +472,22 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
475472
}
476473
}
477474

475+
/** Initializes Text Field's internal state based on the environment state */
476+
private layout(): void {
477+
this._destroy();
478+
this.init();
479+
this._changeDetectorRef.markForCheck();
480+
481+
setTimeout(() => {
482+
if (this._outlined) {
483+
this._foundation.notchOutline(this._foundation.shouldFloat);
484+
}
485+
if (this._hasFloatingLabel()) {
486+
this._getFloatingLabel().float(this._foundation.shouldFloat);
487+
}
488+
});
489+
}
490+
478491
/** Implemented as part of ControlValueAccessor. */
479492
setDisabledState(isDisabled: boolean) {
480493
const newValue = toBoolean(isDisabled);
@@ -486,19 +499,6 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
486499
this._changeDetectorRef.markForCheck();
487500
}
488501

489-
/** Recomputes the outline SVG path for the outline element. */
490-
layout(): void {
491-
setTimeout(() => {
492-
if (this._outlined) {
493-
this._foundation.notchOutline(this._foundation.shouldFloat);
494-
}
495-
496-
if (this._floatingLabel) {
497-
this._floatingLabel.float(this._foundation.shouldFloat);
498-
}
499-
});
500-
}
501-
502502
private _checkCustomValidity(): void {
503503
Promise.resolve().then(() => {
504504
if (this._valid !== undefined) {
@@ -533,7 +533,7 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
533533
}
534534
}
535535

536-
private _destroyTextField(): void {
536+
private _destroy(): void {
537537
if (this._lineRipple) {
538538
this._lineRipple.destroy();
539539
}
@@ -543,12 +543,21 @@ export class MdcTextField extends _MdcTextFieldMixinBase implements AfterViewIni
543543
this._foundation.destroy();
544544
}
545545

546-
private _reinitialize(): void {
547-
if (this._initialized) {
548-
this._destroyTextField();
549-
this.init();
550-
this._changeDetectorRef.markForCheck();
546+
private _hasErrorState(): boolean {
547+
if (this.ngControl) {
548+
return !this.errorState;
551549
}
550+
551+
return this._valid ? this._valid : this._platform.isBrowser ?
552+
this._input.nativeElement.validity.valid : true;
553+
}
554+
555+
private _hasFloatingLabel(): boolean {
556+
return this.label && (this._floatingLabel || this._notchedOutline) ? true : false;
557+
}
558+
559+
private _getFloatingLabel(): MdcFloatingLabel {
560+
return this._floatingLabel || this._notchedOutline.floatingLabel;
552561
}
553562

554563
private _getInputElement(): HTMLInputElement | HTMLTextAreaElement {

packages/textfield/textarea.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { MdcTextField } from './text-field';
1515
'class': 'mdc-text-field',
1616
'[class.mdc-text-field--textarea]': 'true',
1717
'[class.mdc-text-field--dense]': 'dense',
18+
'[class.mdc-text-field--invalid]': 'errorState'
1819
},
1920
template: `
2021
<textarea #input class="mdc-text-field__input"
@@ -33,7 +34,7 @@ import { MdcTextField } from './text-field';
3334
(input)="onInput($event.target.value)"
3435
(change)="onChange($event)"
3536
(blur)="onBlur()"></textarea>
36-
<label mdcFloatingLabel [for]="id">{{label}}</label>
37+
<mdc-notched-outline [label]="label" [for]="id"></mdc-notched-outline>
3738
`,
3839
changeDetection: ChangeDetectionStrategy.OnPush,
3940
encapsulation: ViewEncapsulation.None

0 commit comments

Comments
 (0)