import { ConnectedPosition , Overlay , OverlayPositionBuilder , OverlayRef , PositionStrategy } from '@angular/cdk/overlay' ; import { ComponentPortal , ComponentType } from '@angular/cdk/portal' ; import { AfterViewInit , ChangeDetectorRef , Directive , ElementRef , HostListener , Input , OnDestroy , ViewRef , } from '@angular/core' ; @ Directive ( { selector : '[componentTooltip]' , } ) export class ComponentTooltipDirective implements AfterViewInit , OnDestroy { private _componentInput : any ; private _componentType : ComponentType < any > ; private viewInit = false ; @ Input ( ) set componentType ( value ) { this . _componentType = value ; if ( value && value !== this . _componentType ) { this . updatePositionStrategy ( ) ; } } @ Input ( ) set componentInput ( value ) { this . _componentInput = value ; if ( value && value !== this . _componentInput ) { this . updatePositionStrategy ( ) ; } } @ Input ( 'componentTooltipPosition' ) set position ( value ) { if ( value === this . _position ) { return ; } this . _position = value ; this . updatePositionStrategy ( ) ; } private _position : 'bottom' | 'right' | 'left' | 'top' | 'global-top-center' | 'global-top-left' | 'global-bottom-left' = 'right' ; private tooltipPortal ; private overlayRef : OverlayRef ; private positionStrategy : PositionStrategy ; constructor ( private overlayPositionBuilder , private elementRef , private overlay , private cdr ) { } ngAfterViewInit ( ) { this . viewInit = true ; this . updatePositionStrategy ( ) ; } private updatePositionStrategy ( ) { if ( ! this . viewInit ) { return ; } if ( this . overlayRef ) { this . overlayRef . detach ( ) ; this . overlayRef . dispose ( ) ; } const positions = this . buildPositions ( ) ; if ( this . _position === 'global-top-center' ) { this . positionStrategy = this . overlayPositionBuilder . global ( ) . centerHorizontally ( ) . top ( ) ; } else if ( this . _position === 'global-top-left' ) { this . positionStrategy = this . overlayPositionBuilder . global ( ) . left ( ) . top ( ) ; } else if ( this . _position === 'global-bottom-left' ) { this . positionStrategy = this . overlayPositionBuilder . global ( ) . left ( ) . bottom ( ) ; } else { this . positionStrategy = this . overlayPositionBuilder . flexibleConnectedTo ( this . elementRef ) . withPositions ( positions ) ; } this . overlayRef = this . overlay . create ( { positionStrategy : this . positionStrategy } ) ; if ( ! ( this . cdr as ViewRef ) ?. destroyed ) { this . cdr . detectChanges ( ) ; } } @ HostListener ( 'window:beforeunload' ) ngOnDestroy ( ) { if ( this . overlayRef ) { this . overlayRef . detach ( ) ; } } @ HostListener ( 'mouseenter' ) onMouseEnter ( ) { this . tooltipPortal = new ComponentPortal ( this . _componentType ) ; const tooltipRef = this . overlayRef . attach ( this . tooltipPortal ) ; tooltipRef . instance . config = this . _componentInput ; this . positionStrategy . apply ( ) ; if ( ! ( this . cdr as ViewRef ) ?. destroyed ) { this . cdr . detectChanges ( ) ; } } @ HostListener ( 'mouseleave' ) onMouseLeave ( ) { if ( this . overlayRef ) { this . overlayRef . detach ( ) ; if ( ! ( this . cdr as ViewRef ) ?. destroyed ) { this . cdr . detectChanges ( ) ; } } } private buildPositions ( ) { switch ( this . _position ) { case 'right' : return [ { originX : 'end' , originY : 'center' , overlayX : 'start' , overlayY : 'center' , } , ] ; case 'left' : return [ { originX : 'start' , originY : 'center' , overlayX : 'end' , overlayY : 'center' , } , ] ; case 'top' : return [ { originX : 'center' , originY : 'top' , overlayX : 'center' , overlayY : 'bottom' , } , ] ; case 'bottom' : return [ { originX : 'center' , originY : 'bottom' , overlayX : 'center' , overlayY : 'top' , } , ] ; } } }