1- import  { Subscription }  from  'rxjs' ; 
2- import  { take }  from  'rxjs/operators' ; 
1+ import  { fromEvent ,   merge ,   Subject }  from  'rxjs' ; 
2+ import  { filter ,   take ,   takeUntil }  from  'rxjs/operators' ; 
33import  { 
44  ChangeDetectionStrategy , 
55  ChangeDetectorRef , 
66  Component , 
7+   ElementRef , 
8+   EventEmitter , 
9+   forwardRef , 
710  Input , 
11+   NgZone , 
812  OnChanges , 
9-   TemplateRef , 
10-   forwardRef , 
13+   OnDestroy , 
1114  OnInit , 
12-   SimpleChanges , 
13-   EventEmitter , 
1415  Output , 
15-   OnDestroy , 
16-   ElementRef , 
17-   NgZone , 
16+   SimpleChanges , 
17+   TemplateRef , 
18+   ViewChild , 
1819  ViewEncapsulation 
1920}  from  '@angular/core' ; 
20- import  { NG_VALUE_ACCESSOR ,   ControlValueAccessor }  from  '@angular/forms' ; 
21+ import  { ControlValueAccessor ,   NG_VALUE_ACCESSOR }  from  '@angular/forms' ; 
2122import  { NgbCalendar }  from  './ngb-calendar' ; 
2223import  { NgbDate }  from  './ngb-date' ; 
2324import  { NgbDatepickerService }  from  './datepicker-service' ; 
@@ -29,6 +30,7 @@ import {NgbDateAdapter} from './adapters/ngb-date-adapter';
2930import  { NgbDateStruct }  from  './ngb-date-struct' ; 
3031import  { NgbDatepickerI18n }  from  './datepicker-i18n' ; 
3132import  { isChangedDate }  from  './datepicker-tools' ; 
33+ import  { hasClassName }  from  '../util/util' ; 
3234
3335const  NGB_DATEPICKER_VALUE_ACCESSOR  =  { 
3436  provide : NG_VALUE_ACCESSOR , 
@@ -85,7 +87,7 @@ export interface NgbDatepickerNavigateEvent {
8587      </ngb-datepicker-navigation> 
8688    </div> 
8789
88-     <div class="ngb-dp-months" (keydown)="onKeyDown($event)" (focusin)="showFocus(true)" (focusout)="showFocus(false )"> 
90+     <div #months  class="ngb-dp-months" (keydown)="onKeyDown($event)"> 
8991      <ng-template ngFor let-month [ngForOf]="model.months" let-i="index"> 
9092        <div class="ngb-dp-month"> 
9193          <div *ngIf="navigation === 'none' || (displayMonths > 1 && navigation === 'select')" 
@@ -111,9 +113,10 @@ export class NgbDatepicker implements OnDestroy,
111113    OnChanges ,  OnInit ,  ControlValueAccessor  { 
112114  model : DatepickerViewModel ; 
113115
116+   @ViewChild ( 'months' )  private  _monthsEl : ElementRef < HTMLElement > ; 
114117  private  _controlValue : NgbDate ; 
115-   private  _subscription :  Subscription ; 
116-    private   _selectSubscription :  Subscription ; 
118+   private  _destroyed$   =   new   Subject < void > ( ) ; 
119+ 
117120  /** 
118121   * Reference for the custom template for the day display 
119122   */ 
@@ -214,9 +217,9 @@ export class NgbDatepicker implements OnDestroy,
214217     'maxDate' ,  'navigation' ,  'outsideDays' ,  'showWeekdays' ,  'showWeekNumbers' ,  'startDate' ] 
215218        . forEach ( input  =>  this [ input ]  =  config [ input ] ) ; 
216219
217-     this . _selectSubscription   =   _service . select$ . subscribe ( date  =>  {  this . select . emit ( date ) ;  } ) ; 
220+     _service . select$ . pipe ( takeUntil ( this . _destroyed$ ) ) . subscribe ( date  =>  {  this . select . emit ( date ) ;  } ) ; 
218221
219-     this . _subscription   =   _service . model$ . subscribe ( model  =>  { 
222+     _service . model$ . pipe ( takeUntil ( this . _destroyed$ ) ) . subscribe ( model  =>  { 
220223      const  newDate  =  model . firstDate ; 
221224      const  oldDate  =  this . model  ? this . model . firstDate  : null ; 
222225      const  newSelectedDate  =  model . selectedDate ; 
@@ -271,11 +274,25 @@ export class NgbDatepicker implements OnDestroy,
271274    this . _service . open ( NgbDate . from ( date  ? date . day  ? date  as  NgbDateStruct  : { ...date ,  day : 1 }  : null ) ) ; 
272275  } 
273276
274-   ngOnDestroy ( )  { 
275-     this . _subscription . unsubscribe ( ) ; 
276-     this . _selectSubscription . unsubscribe ( ) ; 
277+   ngAfterContentInit ( )  { 
278+     this . _ngZone . runOutsideAngular ( ( )  =>  { 
279+       const  focusIns$  =  fromEvent < FocusEvent > ( this . _monthsEl . nativeElement ,  'focusin' ) ; 
280+       const  focusOuts$  =  fromEvent < FocusEvent > ( this . _monthsEl . nativeElement ,  'focusout' ) ; 
281+ 
282+       // we're changing 'focusVisible' only when entering or leaving months view 
283+       // and ignoring all focus events where both 'target' and 'related' target are day cells 
284+       merge ( focusIns$ ,  focusOuts$ ) 
285+           . pipe ( 
286+               filter ( 
287+                   ( { target,  relatedTarget} )  => 
288+                       ! ( hasClassName ( target ,  'ngb-dp-day' )  &&  hasClassName ( relatedTarget ,  'ngb-dp-day' ) ) ) , 
289+               takeUntil ( this . _destroyed$ ) ) 
290+           . subscribe ( ( { type} )  =>  this . _ngZone . run ( ( )  =>  this . _service . focusVisible  =  type  ===  'focusin' ) ) ; 
291+     } ) ; 
277292  } 
278293
294+   ngOnDestroy ( )  {  this . _destroyed$ . next ( ) ;  } 
295+ 
279296  ngOnInit ( )  { 
280297    if  ( this . model  ===  undefined )  { 
281298      [ 'dayTemplateData' ,  'displayMonths' ,  'markDisabled' ,  'firstDayOfWeek' ,  'navigation' ,  'minDate' ,  'maxDate' , 
@@ -322,8 +339,6 @@ export class NgbDatepicker implements OnDestroy,
322339
323340  setDisabledState ( isDisabled : boolean )  {  this . _service . disabled  =  isDisabled ;  } 
324341
325-   showFocus ( focusVisible : boolean )  {  this . _service . focusVisible  =  focusVisible ;  } 
326- 
327342  writeValue ( value )  { 
328343    this . _controlValue  =  NgbDate . from ( this . _ngbDateAdapter . fromModel ( value ) ) ; 
329344    this . _service . select ( this . _controlValue ) ; 
0 commit comments