@@ -37,11 +37,6 @@ import {
37
37
MatFormFieldControl ,
38
38
} from '@angular/material/form-field' ;
39
39
import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations' ;
40
- import {
41
- MDCTextFieldAdapter ,
42
- MDCTextFieldFoundation ,
43
- numbers as mdcTextFieldNumbers ,
44
- } from '@material/textfield' ;
45
40
import { merge , Subject } from 'rxjs' ;
46
41
import { takeUntil } from 'rxjs/operators' ;
47
42
import { MAT_ERROR , MatError } from './directives/error' ;
@@ -119,6 +114,9 @@ const FLOATING_LABEL_DEFAULT_DOCKED_TRANSFORM = `translateY(-50%)`;
119
114
*/
120
115
const WRAPPER_HORIZONTAL_PADDING = 16 ;
121
116
117
+ /** Amount by which to scale the label when the form field is focused. */
118
+ const LABEL_SCALE = 0.75 ;
119
+
122
120
/** Container for form controls that applies Material Design styling and behavior. */
123
121
@Component ( {
124
122
selector : 'mat-form-field' ,
@@ -278,90 +276,7 @@ export class MatFormField
278
276
private _destroyed = new Subject < void > ( ) ;
279
277
private _isFocused : boolean | null = null ;
280
278
private _explicitFormFieldControl : MatFormFieldControl < any > ;
281
- private _foundation : MDCTextFieldFoundation ;
282
279
private _needsOutlineLabelOffsetUpdateOnStable = false ;
283
- private _adapter : MDCTextFieldAdapter = {
284
- addClass : className => this . _textField . nativeElement . classList . add ( className ) ,
285
- removeClass : className => this . _textField . nativeElement . classList . remove ( className ) ,
286
- hasClass : className => this . _textField . nativeElement . classList . contains ( className ) ,
287
-
288
- hasLabel : ( ) => this . _hasFloatingLabel ( ) ,
289
- isFocused : ( ) => this . _control . focused ,
290
- hasOutline : ( ) => this . _hasOutline ( ) ,
291
-
292
- // MDC text-field will call this method on focus, blur and value change. It expects us
293
- // to update the floating label state accordingly. Though we make this a noop because we
294
- // want to react to floating label state changes through change detection. Relying on this
295
- // adapter method would mean that the label would not update if the custom form field control
296
- // sets "shouldLabelFloat" to true, or if the "floatLabel" input binding changes to "always".
297
- floatLabel : ( ) => { } ,
298
-
299
- // Label shaking is not supported yet. It will require a new API for form field
300
- // controls to trigger the shaking. This can be a feature in the future.
301
- // TODO(devversion): explore options on how to integrate label shaking.
302
- shakeLabel : ( ) => { } ,
303
-
304
- // MDC by default updates the notched-outline whenever the text-field receives focus, or
305
- // is being blurred. It also computes the label width every time the notch is opened or
306
- // closed. This works fine in the standard MDC text-field, but not in Angular where the
307
- // floating label could change through interpolation. We want to be able to update the
308
- // notched outline whenever the label content changes. Additionally, relying on focus or
309
- // blur to open and close the notch does not work for us since abstract form field controls
310
- // have the ability to control the floating label state (i.e. `shouldLabelFloat`), and we
311
- // want to update the notch whenever the `_shouldLabelFloat()` value changes.
312
- getLabelWidth : ( ) => 0 ,
313
-
314
- // We don't use `setLabelRequired` as it relies on a mutation observer for determining
315
- // when the `required` state changes. This is not reliable and flexible enough for
316
- // our form field, as we support custom controls and detect the required state through
317
- // a public property in the abstract form control.
318
- setLabelRequired : ( ) => { } ,
319
- notchOutline : ( ) => { } ,
320
- closeOutline : ( ) => { } ,
321
-
322
- activateLineRipple : ( ) => this . _lineRipple && this . _lineRipple . activate ( ) ,
323
- deactivateLineRipple : ( ) => this . _lineRipple && this . _lineRipple . deactivate ( ) ,
324
-
325
- // The foundation tries to register events on the input. This is not matching
326
- // our concept of abstract form field controls. We handle each event manually
327
- // in "stateChanges" based on the form field control state. The following events
328
- // need to be handled: focus, blur. We do not handle the "input" event since
329
- // that one is only needed for the text-field character count, which we do
330
- // not implement as part of the form field, but should be implemented manually
331
- // by consumers using template bindings.
332
- registerInputInteractionHandler : ( ) => { } ,
333
- deregisterInputInteractionHandler : ( ) => { } ,
334
-
335
- // We do not have a reference to the native input since we work with abstract form field
336
- // controls. MDC needs a reference to the native input optionally to handle character
337
- // counting and value updating. These are both things we do not handle from within the
338
- // form field, so we can just return null.
339
- getNativeInput : ( ) => null ,
340
-
341
- // This method will never be called since we do not have the ability to add event listeners
342
- // to the native input. This is because the form control is not necessarily an input, and
343
- // the form field deals with abstract form controls of any type.
344
- setLineRippleTransformOrigin : ( ) => { } ,
345
-
346
- // The foundation tries to register click and keyboard events on the form field to figure out
347
- // if the input value changes through user interaction. Based on that, the foundation tries
348
- // to focus the input. Since we do not handle the input value as part of the form field, nor
349
- // it's guaranteed to be an input (see adapter methods above), this is a noop.
350
- deregisterTextFieldInteractionHandler : ( ) => { } ,
351
- registerTextFieldInteractionHandler : ( ) => { } ,
352
-
353
- // The foundation tries to setup a "MutationObserver" in order to watch for attributes
354
- // like "maxlength" or "pattern" to change. The foundation will update the validity state
355
- // based on that. We do not need this logic since we handle the validity through the
356
- // abstract form control instance.
357
- deregisterValidationAttributeChangeHandler : ( ) => { } ,
358
- registerValidationAttributeChangeHandler : ( ) => null as any ,
359
-
360
- // Used by foundation to dynamically remove aria-describedby when the hint text
361
- // is shown only on invalid state, which should not be applicable here.
362
- setInputAttr : ( ) => undefined ,
363
- removeInputAttr : ( ) => undefined ,
364
- } ;
365
280
366
281
constructor (
367
282
private _elementRef : ElementRef ,
@@ -387,24 +302,6 @@ export class MatFormField
387
302
}
388
303
389
304
ngAfterViewInit ( ) {
390
- this . _foundation = new MDCTextFieldFoundation ( this . _adapter ) ;
391
-
392
- // MDC uses the "shouldFloat" getter to know whether the label is currently floating. This
393
- // does not match our implementation of when the label floats because we support more cases.
394
- // For example, consumers can set "@Input floatLabel" to always, or the custom form field
395
- // control can set "MatFormFieldControl#shouldLabelFloat" to true. To ensure that MDC knows
396
- // when the label is floating, we overwrite the property to be based on the method we use to
397
- // determine the current state of the floating label.
398
- Object . defineProperty ( this . _foundation , 'shouldFloat' , {
399
- get : ( ) => this . _shouldLabelFloat ( ) ,
400
- } ) ;
401
-
402
- // By default, the foundation determines the validity of the text-field from the
403
- // specified native input. Since we don't pass a native input to the foundation because
404
- // abstract form controls are not necessarily consisting of an input, we handle the
405
- // text-field validity through the abstract form field control state.
406
- this . _foundation . isValid = ( ) => ! this . _control . errorState ;
407
-
408
305
// Initial focus state sync. This happens rarely, but we want to account for
409
306
// it in case the form field control has "focused" set to true on init.
410
307
this . _updateFocusState ( ) ;
@@ -445,7 +342,6 @@ export class MatFormField
445
342
}
446
343
447
344
ngOnDestroy ( ) {
448
- this . _foundation ?. destroy ( ) ;
449
345
this . _destroyed . next ( ) ;
450
346
this . _destroyed . complete ( ) ;
451
347
}
@@ -562,11 +458,16 @@ export class MatFormField
562
458
// we handle the focus by checking if the abstract form field control focused state changes.
563
459
if ( this . _control . focused && ! this . _isFocused ) {
564
460
this . _isFocused = true ;
565
- this . _foundation . activateFocus ( ) ;
461
+ this . _lineRipple ?. activate ( ) ;
566
462
} else if ( ! this . _control . focused && ( this . _isFocused || this . _isFocused === null ) ) {
567
463
this . _isFocused = false ;
568
- this . _foundation . deactivateFocus ( ) ;
464
+ this . _lineRipple ?. deactivate ( ) ;
569
465
}
466
+
467
+ this . _textField ?. nativeElement . classList . toggle (
468
+ 'mdc-text-field--focused' ,
469
+ this . _control . focused ,
470
+ ) ;
570
471
}
571
472
572
473
/**
@@ -652,7 +553,7 @@ export class MatFormField
652
553
// The outline notch should be based on the label width, but needs to respect the scaling
653
554
// applied to the label if it actively floats. Since the label always floats when the notch
654
555
// is open, the MDC text-field floating label scaling is respected in notch width calculation.
655
- this . _outlineNotchWidth = this . _floatingLabel . getWidth ( ) * mdcTextFieldNumbers . LABEL_SCALE ;
556
+ this . _outlineNotchWidth = this . _floatingLabel . getWidth ( ) * LABEL_SCALE ;
656
557
}
657
558
658
559
/** Does any extra processing that is required when handling the hints. */
0 commit comments