All files / lib/internal focus-scope.directive.ts

100% Statements 59/59
100% Branches 17/17
100% Functions 6/6
100% Lines 59/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 601x 1x 1x 1x 1x 1x 1x 797x 797x 797x 797x 797x 797x 797x 797x 1x 1x 1x 1x 1x 1x 1x 797x 797x 1x 1x 1x 156x 156x 156x 57x 57x 1x 1x 1x 1x 1x 1x 337x 238x 238x 238x 238x 1x 1x 1x 1x 1x 1x 1x 829x 2198x 1x 1x 1x 1x 394x 1x 1x  
import { AfterContentInit, ContentChildren, Directive, ElementRef, EventEmitter, Output, QueryList } from '@angular/core';
import { FocusTargetDirective } from './focus-target.directive';
 
@Directive({
  selector: '[gc-focus-scope]'
})
export class FocusScopeDirective implements AfterContentInit {
 
  @Output()
  public onFocusLeft = new EventEmitter<void>();
 
  @Output()
  public onFocusEntered = new EventEmitter<void>();
 
  @ContentChildren(FocusTargetDirective, { descendants: true })
  public focusTargets!: QueryList<FocusTargetDirective>;
 
  focusWithin = false;
 
  constructor(private el: ElementRef) {}
 
  ngAfterContentInit(): void {
    this.connectFocusTargets();
    this.focusTargets.changes.subscribe( () => this.connectFocusTargets());
  }
 
  onTargetBlur(): void {
    if (this.focusWithin) {
      setTimeout(() => {
        if (!this.isFocusWithin()) {
          this.focusWithin = false;
          this.onFocusLeft.emit();
        }
      });
    }
  }
 
  onTargetFocus(): void {
    if (!this.focusWithin) {
      setTimeout(() => {
        if (this.isFocusWithin()) {
          this.focusWithin = true;
          this.onFocusEntered.emit();
        }
      });
 
    }
  }
 
  private connectFocusTargets(): void {
    this.focusTargets.forEach( f => {
      f.scope = this;
    } );
  }
 
  private isFocusWithin(): boolean {
    return this.focusTargets.some(target => target.isFocused());
  }
}