All files / lib/internal/tooltip tooltip.directive.ts

100% Statements 144/144
100% Branches 38/38
100% Functions 13/13
100% Lines 144/144

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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 1451x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 21x 21x 21x 21x 21x 21x 1x 1x 7809x 7809x 7809x 1x 1x 208x 208x 208x 1x 1x 1x 1x 1x 1x 9263x 9263x 9263x 9263x 1x 1x 10x 10x 10x 10x 10x 1x 1x 21588x 21588x 21588x 1x 1x 1x 113744x 113744x 13583x 100161x 113744x 1x 1x 1x 113744x 113744x 6848x 106896x 113744x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8870x 8870x 8870x 8870x 8870x 8870x 8870x 8870x 8870x 8870x 8870x 8870x 60x 8870x 8870x 8870x 8870x 1x 1x 1x 28391x 9263x 9263x 9263x 9263x 4130x 4130x 9156x 40x 40x 40x 5093x 5093x 4752x 4752x 9263x 9263x 9263x 28391x 1x 1x 1x 1720x 1720x 1x  
import {
  ComponentRef,
  Directive,
  ElementRef,
  HostBinding,
  Input,
  OnChanges,
  OnDestroy,
  Optional,
  SimpleChanges,
  ViewContainerRef,
} from '@angular/core';
 
import { createWidgetKeySet } from '../../utils/utilities';
 
import { ElementInsertionContextService } from '../element-insertion-context.service';
import { OverlayContainerComponent } from '../overlay-container/overlay-container.component';
import { ConnectType, TooltipComponent } from './tooltip.component';
 
const ARIA_DESCRIBEDBY = 'aria-describedby';
const ARIA_LABELLEDBY = 'aria-labelledby';
 
@Directive({
  selector: '[data-gc-tooltip]',
  standalone: false,
})
export class TooltipDirective implements OnDestroy, OnChanges {
  @Input('data-gc-tooltip-connect-as')
  public connectAs: ConnectType = ARIA_DESCRIBEDBY;
 
  @Input('data-gc-tooltip-testid')
  public set testId(value: string) {
    (this.componentRef.location.nativeElement as HTMLElement).setAttribute(
      'data-testid',
      value,
    );
  }
 
  @Input('data-gc-tooltip-offset')
  public set offset(value: number) {
    this.componentRef.setInput('offset', value);
  }
 
  @Input('data-gc-tooltip-orientation')
  public set orientation(value: 'vertical' | 'horizontal') {
    this.componentRef.setInput('orientation', value);
  }
 
  /**
   * Set the text of the tooltip.
   * Tooltip is not created if the text is empty.
   */
  @Input({ alias: 'data-gc-tooltip', required: true })
  public set text(value: string) {
    this._text = value;
    this.componentRef.setInput('text', value);
  }
 
  @Input('data-gc-tooltip-focus-anchor')
  public set focusAnchor(
    value: ElementRef<HTMLElement> | HTMLElement | undefined,
  ) {
    this.componentRef.setInput('focusAnchor', value);
  }
 
  @Input('data-gc-tooltip-permit')
  public set permitTooltip(value: () => boolean) {
    this.componentRef.setInput('permitTooltip', value);
  }
 
  /** @ignore */
  @HostBinding('attr.aria-describedby')
  protected get ariaDescribedBy() {
    return this.connectAs === ARIA_DESCRIBEDBY && this._text !== ''
      ? this.componentRef.instance.tooltipContentId
      : undefined;
  }
 
  /** @ignore */
  @HostBinding('attr.aria-labelledby')
  protected get ariaLabelledBy() {
    return this.connectAs === ARIA_LABELLEDBY && this._text !== ''
      ? this.componentRef.instance.tooltipContentId
      : undefined;
  }
 
  /** @ignore */
  private readonly _widgetKeys = createWidgetKeySet('gc-tooltip');
 
  /** @ignore */
  private _text = '';
 
  /** @ignore */
  private readonly componentRef: ComponentRef<TooltipComponent>;
 
  /** @ignore */
  private readonly parentElement: HTMLElement;
 
  constructor(
    private readonly viewRef: ViewContainerRef,
    @Optional() eic: ElementInsertionContextService | null,
    @Optional() parent: OverlayContainerComponent | null,
  ) {
    this.componentRef = this.viewRef.createComponent(TooltipComponent);
    this.componentRef.setInput('tooltipId', this._widgetKeys.baseKey);
    this.componentRef.setInput(
      'tooltipOwner',
      this.viewRef.element.nativeElement,
    );
    let zIndex = 1000;
    if (parent) {
      zIndex = parent.zIndex + 900;
    }
    this.componentRef.setInput('zIndex', zIndex);
    this.parentElement = eic?.parent ?? document.body;
  }
 
  /** @ignore */
  ngOnChanges(changes: SimpleChanges): void {
    if ('text' in changes) {
      const change = changes.text;
      const componentAttached =
        change.firstChange || change.previousValue !== '';
      if (change.currentValue === '' && componentAttached) {
        const componentIndex = this.viewRef.indexOf(this.componentRef.hostView);
        this.viewRef.detach(componentIndex);
      } else if (change.currentValue && !componentAttached) {
        this.viewRef.insert(this.componentRef.hostView);
        this.parentElement.appendChild(
          this.componentRef.location.nativeElement,
        );
      } else if (change.firstChange) {
        this.parentElement.appendChild(
          this.componentRef.location.nativeElement,
        );
      }
    }
  }
 
  /** @ignore */
  ngOnDestroy(): void {
    this.componentRef.destroy();
  }
}