import { AnimationEvent } from '@angular/animations' ; import { ChangeDetectionStrategy , ChangeDetectorRef , Component , HostListener , ViewEncapsulation } from '@angular/core' ; import { Observable , Subject } from 'rxjs' ; import { tooltipAnimations } from './tooltip-animations' ; export type TooltipVisibility = 'initial' | 'visible' | 'hidden' ; @ Component ( { selector : 'gd-tooltip' , templateUrl : './tooltip.component.html' , styleUrls : [ './tooltip.component.scss' ] , encapsulation : ViewEncapsulation . None , changeDetection : ChangeDetectionStrategy . OnPush , animations : [ tooltipAnimations . tooltipState ] , host : { '[attr.aria-hidden]' : 'true' , } , } ) export class TooltipComponent { /** Message to display in the tooltip */ message : string ; /** The timeout ID of any current timer set to show the tooltip */ _showTimeoutId : number ; /** The timeout ID of any current timer set to hide the tooltip */ _hideTimeoutId : number ; /** Property watched by the animation framework to show or hide the tooltip */ _visibility : TooltipVisibility = 'initial' ; /** Whether interactions on the page should close the tooltip */ private closeOnInteraction : boolean = false ; /** Subject for notifying that the tooltip has been hidden from the view */ private readonly _onHide = new Subject < any > ( ) ; constructor ( private changeDetectorRef ) { } show ( delay ) { if ( this . _hideTimeoutId ) { window . clearTimeout ( this . _hideTimeoutId ) ; } this . closeOnInteraction = true ; this . _showTimeoutId = window . setTimeout ( ( ) => { this . _visibility = 'visible' ; this . _markForCheck ( ) ; } , delay ) ; } param delay hide ( delay ) { if ( this . _showTimeoutId ) { window . clearTimeout ( this . _showTimeoutId ) ; } this . _hideTimeoutId = window . setTimeout ( ( ) => { this . _visibility = 'hidden' ; this . _markForCheck ( ) ; } , delay ) ; } /** Returns an observable that notifies when the tooltip has been hidden from view. */ afterHidden ( ) { return this . _onHide . asObservable ( ) ; } /** Whether the tooltip is being displayed. */ isVisible ( ) { return this . _visibility === 'visible' ; } _animationStart ( ) { this . closeOnInteraction = false ; } _animationDone ( event ) { const toState = event . toState as TooltipVisibility ; if ( toState === 'hidden' && ! this . isVisible ( ) ) { this . _onHide . next ( ) ; } if ( toState === 'visible' || toState === 'hidden' ) { this . closeOnInteraction = true ; } } /**
     * Marks that the tooltip needs to be checked in the next change detection run.
     * Mainly used for rendering the initial text before positioning a tooltip, which
     * can be problematic in components with OnPush change detection.
     */ _markForCheck ( ) { this . changeDetectorRef . markForCheck ( ) ; } /**
     * Interactions on the HTML body should close the tooltip immediately as defined in the
     * material design spec.
     * https://material.google.com/components/tooltips.html#tooltips-interaction
     */ @ HostListener ( 'body:click' ) private handleBodyInteraction ( ) { if ( this . closeOnInteraction ) { this . hide ( 0 ) ; } } }