@@ -12,11 +12,20 @@ import {
1212    NgModule , 
1313    ModuleWithProviders , 
1414    ViewChild , 
15+     AfterViewInit , 
16+     OnDestroy , 
1517}  from  '@angular/core' ; 
1618import  { CommonModule }  from  '@angular/common' ; 
1719import  { NG_VALUE_ACCESSOR ,  ControlValueAccessor }  from  '@angular/forms' ; 
1820import  { coerceBooleanProperty }  from  '../core/coercion/boolean-property' ; 
19- import  { MdRippleModule ,  CompatibilityModule }  from  '../core' ; 
21+ import  { Subscription }  from  'rxjs/Subscription' ; 
22+ import  { 
23+   CompatibilityModule , 
24+   MdRippleModule , 
25+   MdRipple , 
26+   RippleRef , 
27+   FocusOriginMonitor , 
28+ }  from  '../core' ; 
2029
2130
2231/** Monotonically increasing integer used to auto-generate unique ids for checkbox components. */ 
@@ -73,13 +82,12 @@ export class MdCheckboxChange {
7382    '[class.mat-checkbox-checked]' : 'checked' , 
7483    '[class.mat-checkbox-disabled]' : 'disabled' , 
7584    '[class.mat-checkbox-label-before]' : 'labelPosition == "before"' , 
76-     '[class.mat-checkbox-focused]' : '_hasFocus' , 
7785  } , 
7886  providers : [ MD_CHECKBOX_CONTROL_VALUE_ACCESSOR ] , 
7987  encapsulation : ViewEncapsulation . None , 
8088  changeDetection : ChangeDetectionStrategy . OnPush 
8189} ) 
82- export  class  MdCheckbox  implements  ControlValueAccessor  { 
90+ export  class  MdCheckbox  implements  ControlValueAccessor ,   AfterViewInit ,   OnDestroy  { 
8391  /** 
8492   * Attached to the aria-label attribute of the host element. In most cases, arial-labelledby will 
8593   * take precedence so this may be omitted. 
@@ -157,6 +165,8 @@ export class MdCheckbox implements ControlValueAccessor {
157165  /** The native `<input type="checkbox"> element */ 
158166  @ViewChild ( 'input' )  _inputElement : ElementRef ; 
159167
168+   @ViewChild ( MdRipple )  _ripple : MdRipple ; 
169+ 
160170  /** 
161171   * Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor. 
162172   * @docs -private 
@@ -175,14 +185,38 @@ export class MdCheckbox implements ControlValueAccessor {
175185
176186  private  _controlValueAccessorChangeFn : ( value : any )  =>  void =  ( value )  =>  { } ; 
177187
178-   _hasFocus : boolean  =  false ; 
188+   /** Reference to the focused state ripple. */ 
189+   private  _focusedRipple : RippleRef ; 
190+ 
191+   /** Reference to the focus origin monitor subscription. */ 
192+   private  _focusedSubscription : Subscription ; 
179193
180194  constructor ( private  _renderer : Renderer , 
181195              private  _elementRef : ElementRef , 
182-               private  _changeDetectorRef : ChangeDetectorRef )  { 
196+               private  _changeDetectorRef : ChangeDetectorRef , 
197+               private  _focusOriginMonitor : FocusOriginMonitor )  { 
183198    this . color  =  'accent' ; 
184199  } 
185200
201+   ngAfterViewInit ( )  { 
202+     this . _focusedSubscription  =  this . _focusOriginMonitor 
203+       . monitor ( this . _inputElement . nativeElement ,  this . _renderer ,  false ) 
204+       . subscribe ( focusOrigin  =>  { 
205+         if  ( ! this . _focusedRipple  &&  focusOrigin  ===  'keyboard' )  { 
206+           this . _focusedRipple  =  this . _ripple . launch ( 0 ,  0 ,  {  persistent : true ,  centered : true  } ) ; 
207+         } 
208+       } ) ; 
209+   } 
210+ 
211+   ngOnDestroy ( )  { 
212+     this . _focusOriginMonitor . unmonitor ( this . _inputElement . nativeElement ) ; 
213+ 
214+     if  ( this . _focusedSubscription )  { 
215+       this . _focusedSubscription . unsubscribe ( ) ; 
216+       this . _focusedSubscription  =  null ; 
217+     } 
218+   } 
219+ 
186220  /** 
187221   * Whether the checkbox is checked. Note that setting `checked` will immediately set 
188222   * `indeterminate` to false. 
@@ -315,14 +349,9 @@ export class MdCheckbox implements ControlValueAccessor {
315349    this . change . emit ( event ) ; 
316350  } 
317351
318-   /** Informs the component when the input has focus so that we can style accordingly */ 
319-   _onInputFocus ( )  { 
320-     this . _hasFocus  =  true ; 
321-   } 
322- 
323352  /** Informs the component when we lose focus in order to style accordingly */ 
324353  _onInputBlur ( )  { 
325-     this . _hasFocus   =   false ; 
354+     this . _removeFocusedRipple ( ) ; 
326355    this . onTouched ( ) ; 
327356  } 
328357
@@ -348,6 +377,8 @@ export class MdCheckbox implements ControlValueAccessor {
348377    // Preventing bubbling for the second event will solve that issue. 
349378    event . stopPropagation ( ) ; 
350379
380+     this . _removeFocusedRipple ( ) ; 
381+ 
351382    if  ( ! this . disabled )  { 
352383      this . toggle ( ) ; 
353384      this . _transitionCheckState ( 
@@ -362,8 +393,7 @@ export class MdCheckbox implements ControlValueAccessor {
362393
363394  /** Focuses the checkbox. */ 
364395  focus ( ) : void { 
365-     this . _renderer . invokeElementMethod ( this . _inputElement . nativeElement ,  'focus' ) ; 
366-     this . _onInputFocus ( ) ; 
396+     this . _focusOriginMonitor . focusVia ( this . _inputElement . nativeElement ,  this . _renderer ,  'keyboard' ) ; 
367397  } 
368398
369399  _onInteractionEvent ( event : Event )  { 
@@ -405,13 +435,21 @@ export class MdCheckbox implements ControlValueAccessor {
405435    return  `mat-checkbox-anim-${ animSuffix }  ; 
406436  } 
407437
438+   /** Fades out the focused state ripple. */ 
439+   private  _removeFocusedRipple ( ) : void { 
440+     if  ( this . _focusedRipple )  { 
441+       this . _focusedRipple . fadeOut ( ) ; 
442+       this . _focusedRipple  =  null ; 
443+     } 
444+   } 
408445} 
409446
410447
411448@NgModule ( { 
412449  imports : [ CommonModule ,  MdRippleModule ,  CompatibilityModule ] , 
413450  exports : [ MdCheckbox ,  CompatibilityModule ] , 
414451  declarations : [ MdCheckbox ] , 
452+   providers : [ FocusOriginMonitor ] 
415453} ) 
416454export  class  MdCheckboxModule  { 
417455  /** @deprecated  */ 
0 commit comments