@@ -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.
@@ -154,6 +162,8 @@ export class MdCheckbox implements ControlValueAccessor {
154
162
/** The native `<input type="checkbox"> element */
155
163
@ViewChild ( 'input' ) _inputElement : ElementRef ;
156
164
165
+ @ViewChild ( MdRipple ) _ripple : MdRipple ;
166
+
157
167
/**
158
168
* Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor.
159
169
* @docs -private
@@ -172,14 +182,38 @@ export class MdCheckbox implements ControlValueAccessor {
172
182
173
183
private _controlValueAccessorChangeFn : ( value : any ) => void = ( value ) => { } ;
174
184
175
- _hasFocus : boolean = false ;
185
+ /** Reference to the focused state ripple. */
186
+ private _focusedRipple : RippleRef ;
187
+
188
+ /** Reference to the focus origin monitor subscription. */
189
+ private _focusedSubscription : Subscription ;
176
190
177
191
constructor ( private _renderer : Renderer ,
178
192
private _elementRef : ElementRef ,
179
- private _changeDetectorRef : ChangeDetectorRef ) {
193
+ private _changeDetectorRef : ChangeDetectorRef ,
194
+ private _focusOriginMonitor : FocusOriginMonitor ) {
180
195
this . color = 'accent' ;
181
196
}
182
197
198
+ ngAfterViewInit ( ) {
199
+ this . _focusedSubscription = this . _focusOriginMonitor
200
+ . monitor ( this . _inputElement . nativeElement , this . _renderer , false )
201
+ . subscribe ( focusOrigin => {
202
+ if ( ! this . _focusedRipple && focusOrigin === 'keyboard' ) {
203
+ this . _focusedRipple = this . _ripple . launch ( 0 , 0 , { persistent : true , centered : true } ) ;
204
+ }
205
+ } ) ;
206
+ }
207
+
208
+ ngOnDestroy ( ) {
209
+ this . _focusOriginMonitor . unmonitor ( this . _inputElement . nativeElement ) ;
210
+
211
+ if ( this . _focusedSubscription ) {
212
+ this . _focusedSubscription . unsubscribe ( ) ;
213
+ this . _focusedSubscription = null ;
214
+ }
215
+ }
216
+
183
217
/**
184
218
* Whether the checkbox is checked. Note that setting `checked` will immediately set
185
219
* `indeterminate` to false.
@@ -313,14 +347,9 @@ export class MdCheckbox implements ControlValueAccessor {
313
347
this . change . emit ( event ) ;
314
348
}
315
349
316
- /** Informs the component when the input has focus so that we can style accordingly */
317
- _onInputFocus ( ) {
318
- this . _hasFocus = true ;
319
- }
320
-
321
350
/** Informs the component when we lose focus in order to style accordingly */
322
351
_onInputBlur ( ) {
323
- this . _hasFocus = false ;
352
+ this . _removeFocusedRipple ( ) ;
324
353
this . onTouched ( ) ;
325
354
}
326
355
@@ -346,6 +375,8 @@ export class MdCheckbox implements ControlValueAccessor {
346
375
// Preventing bubbling for the second event will solve that issue.
347
376
event . stopPropagation ( ) ;
348
377
378
+ this . _removeFocusedRipple ( ) ;
379
+
349
380
if ( ! this . disabled ) {
350
381
this . toggle ( ) ;
351
382
@@ -358,8 +389,7 @@ export class MdCheckbox implements ControlValueAccessor {
358
389
359
390
/** Focuses the checkbox. */
360
391
focus ( ) : void {
361
- this . _renderer . invokeElementMethod ( this . _inputElement . nativeElement , 'focus' ) ;
362
- this . _onInputFocus ( ) ;
392
+ this . _focusOriginMonitor . focusVia ( this . _inputElement . nativeElement , this . _renderer , 'keyboard' ) ;
363
393
}
364
394
365
395
_onInteractionEvent ( event : Event ) {
@@ -399,13 +429,21 @@ export class MdCheckbox implements ControlValueAccessor {
399
429
return `mat-checkbox-anim-${ animSuffix } ` ;
400
430
}
401
431
432
+ /** Fades out the focused state ripple. */
433
+ private _removeFocusedRipple ( ) : void {
434
+ if ( this . _focusedRipple ) {
435
+ this . _focusedRipple . fadeOut ( ) ;
436
+ this . _focusedRipple = null ;
437
+ }
438
+ }
402
439
}
403
440
404
441
405
442
@NgModule ( {
406
443
imports : [ CommonModule , MdRippleModule , CompatibilityModule ] ,
407
444
exports : [ MdCheckbox , CompatibilityModule ] ,
408
445
declarations : [ MdCheckbox ] ,
446
+ providers : [ FocusOriginMonitor ]
409
447
} )
410
448
export class MdCheckboxModule {
411
449
/** @deprecated */
0 commit comments