Skip to content
Snippets Groups Projects
Select Git revision
  • 10fc5c119872ffe794aba4e714cfa9881368ba1d
  • main default protected
  • KOP-3064-Test-Nachrichten-Fuer-Enaio-DMS
  • KOP-3139-ozgcloud-Abhaengigkeit-entfernen
  • OZG-8085-ci-components-poc
  • KOP-3126-Reproduce-Bug
  • 0.2.2
  • 0.2.1
  • 0.2.0
9 results

XtaClientITCase.java

Blame
  • tooltip.directive.ts 3.02 KiB
    import { isEscapeKey } from '@alfa-client/tech-shared';
    import { InteractivityChecker } from '@angular/cdk/a11y';
    import {
      ComponentRef,
      Directive,
      ElementRef,
      HostListener,
      inject,
      Input,
      OnDestroy,
      Renderer2,
      ViewContainerRef,
    } from '@angular/core';
    import { uniqueId } from 'lodash-es';
    import { TooltipComponent } from './tooltip.component';
    
    @Directive({
      selector: '[tooltip]',
      standalone: true,
    })
    export class TooltipDirective implements OnDestroy {
      @Input() tooltip: string = '';
    
      componentRef: ComponentRef<TooltipComponent> = null;
      focusableElement: HTMLElement = null;
      tooltipId: string;
    
      public viewContainerRef: ViewContainerRef = inject(ViewContainerRef);
      public elementRef: ElementRef<HTMLElement> = inject(ElementRef);
      public renderer: Renderer2 = inject(Renderer2);
      public interactivityChecker: InteractivityChecker = inject(InteractivityChecker);
    
      ngOnDestroy(): void {
        this.destroy();
      }
    
      @HostListener('mouseenter')
      @HostListener('focusin')
      createTooltip(): void {
        if (this.componentRef === null) {
          const nativeElement: HTMLElement = this.elementRef.nativeElement;
          const attachedToFocused: boolean = nativeElement.contains(document.activeElement);
          this.componentRef = this.viewContainerRef.createComponent(TooltipComponent);
          nativeElement.appendChild(this.componentRef.location.nativeElement);
          this.setDescribedBy();
          this.setTooltipProperties(attachedToFocused);
        }
      }
    
      @HostListener('mouseleave')
      @HostListener('window:scroll')
      @HostListener('focusout')
      destroyTooltip(): void {
        this.destroy();
      }
    
      @HostListener('keydown', ['$event'])
      onKeydown(e: KeyboardEvent): void {
        if (isEscapeKey(e)) {
          this.destroy();
        }
      }
    
      setTooltipProperties(attachedToFocused = false): void {
        if (this.componentRef !== null) {
          const { left, right, bottom } = this.elementRef.nativeElement.getBoundingClientRect();
          this.componentRef.instance.left = (right + left) / 2;
          this.componentRef.instance.top = attachedToFocused ? bottom + 4 : bottom;
          this.componentRef.instance.text = this.tooltip;
          this.componentRef.instance.id = this.tooltipId;
        }
      }
    
      setDescribedBy(): void {
        const nativeElement: HTMLElement = this.elementRef.nativeElement;
        this.tooltipId = uniqueId('tooltip');
        this.focusableElement =
          this.interactivityChecker.isFocusable(nativeElement) ? nativeElement : this.getFocusableElement(nativeElement);
        this.renderer.setAttribute(this.focusableElement, 'aria-describedby', this.tooltipId);
      }
    
      removeDescribedBy(): void {
        this.renderer.removeAttribute(this.focusableElement, 'aria-describedby');
      }
    
      getFocusableElement(element: HTMLElement): HTMLElement {
        return element.querySelector('a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])');
      }
    
      destroy(): void {
        if (this.componentRef !== null) {
          this.componentRef.destroy();
          this.componentRef = null;
          this.removeDescribedBy();
          this.focusableElement = null;
        }
      }
    }