@@ -12,11 +12,20 @@ import {
12
12
NgModule ,
13
13
ModuleWithProviders ,
14
14
ViewChild ,
15
+ AfterViewInit ,
16
+ OnDestroy ,
15
17
} from '@angular/core' ;
16
18
import { CommonModule } from '@angular/common' ;
17
19
import { NG_VALUE_ACCESSOR , ControlValueAccessor } from '@angular/forms' ;
18
20
import { 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' ;
20
29
21
30
22
31
/** Monotonically increasing integer used to auto-generate unique ids for checkbox components. */
@@ -73,13 +82,12 @@ export class MdCheckboxChange {
73
82
'[class.mat-checkbox-checked]' : 'checked' ,
74
83
'[class.mat-checkbox-disabled]' : 'disabled' ,
75
84
'[class.mat-checkbox-label-before]' : 'labelPosition == "before"' ,
76
- '[class.mat-checkbox-focused]' : '_hasFocus' ,
77
85
} ,
78
86
providers : [ MD_CHECKBOX_CONTROL_VALUE_ACCESSOR ] ,
79
87
encapsulation : ViewEncapsulation . None ,
80
88
changeDetection : ChangeDetectionStrategy . OnPush
81
89
} )
82
- export class MdCheckbox implements ControlValueAccessor {
90
+ export class MdCheckbox implements ControlValueAccessor , AfterViewInit , OnDestroy {
83
91
/**
84
92
* Attached to the aria-label attribute of the host element. In most cases, arial-labelledby will
85
93
* take precedence so this may be omitted.
@@ -157,6 +165,8 @@ export class MdCheckbox implements ControlValueAccessor {
157
165
/** The native `<input type="checkbox"> element */
158
166
@ViewChild ( 'input' ) _inputElement : ElementRef ;
159
167
168
+ @ViewChild ( MdRipple ) _ripple : MdRipple ;
169
+
160
170
/**
161
171
* Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor.
162
172
* @docs -private
@@ -175,14 +185,38 @@ export class MdCheckbox implements ControlValueAccessor {
175
185
176
186
private _controlValueAccessorChangeFn : ( value : any ) => void = ( value ) => { } ;
177
187
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 ;
179
193
180
194
constructor ( private _renderer : Renderer ,
181
195
private _elementRef : ElementRef ,
182
- private _changeDetectorRef : ChangeDetectorRef ) {
196
+ private _changeDetectorRef : ChangeDetectorRef ,
197
+ private _focusOriginMonitor : FocusOriginMonitor ) {
183
198
this . color = 'accent' ;
184
199
}
185
200
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
+
186
220
/**
187
221
* Whether the checkbox is checked. Note that setting `checked` will immediately set
188
222
* `indeterminate` to false.
@@ -315,14 +349,9 @@ export class MdCheckbox implements ControlValueAccessor {
315
349
this . change . emit ( event ) ;
316
350
}
317
351
318
- /** Informs the component when the input has focus so that we can style accordingly */
319
- _onInputFocus ( ) {
320
- this . _hasFocus = true ;
321
- }
322
-
323
352
/** Informs the component when we lose focus in order to style accordingly */
324
353
_onInputBlur ( ) {
325
- this . _hasFocus = false ;
354
+ this . _removeFocusedRipple ( ) ;
326
355
this . onTouched ( ) ;
327
356
}
328
357
@@ -348,6 +377,8 @@ export class MdCheckbox implements ControlValueAccessor {
348
377
// Preventing bubbling for the second event will solve that issue.
349
378
event . stopPropagation ( ) ;
350
379
380
+ this . _removeFocusedRipple ( ) ;
381
+
351
382
if ( ! this . disabled ) {
352
383
this . toggle ( ) ;
353
384
this . _transitionCheckState (
@@ -362,8 +393,7 @@ export class MdCheckbox implements ControlValueAccessor {
362
393
363
394
/** Focuses the checkbox. */
364
395
focus ( ) : void {
365
- this . _renderer . invokeElementMethod ( this . _inputElement . nativeElement , 'focus' ) ;
366
- this . _onInputFocus ( ) ;
396
+ this . _focusOriginMonitor . focusVia ( this . _inputElement . nativeElement , this . _renderer , 'keyboard' ) ;
367
397
}
368
398
369
399
_onInteractionEvent ( event : Event ) {
@@ -405,13 +435,21 @@ export class MdCheckbox implements ControlValueAccessor {
405
435
return `mat-checkbox-anim-${ animSuffix } ` ;
406
436
}
407
437
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
+ }
408
445
}
409
446
410
447
411
448
@NgModule ( {
412
449
imports : [ CommonModule , MdRippleModule , CompatibilityModule ] ,
413
450
exports : [ MdCheckbox , CompatibilityModule ] ,
414
451
declarations : [ MdCheckbox ] ,
452
+ providers : [ FocusOriginMonitor ]
415
453
} )
416
454
export class MdCheckboxModule {
417
455
/** @deprecated */
0 commit comments