import { Directive , ElementRef } from '@angular/core' ; import { fromEvent , merge , Observable , Subscriber } from 'rxjs' ; import { map , switchMap , takeUntil , tap } from 'rxjs/operators' ; import { stopPropagation } from './scrollbar/common' ; @ Directive ( { selector : '[scrollViewport]' } ) export class ScrollViewport { readonly nativeElement : HTMLElement ; contentWrapperElement ! : HTMLElement ; hovered ! : Observable < MouseEvent | false > ; clicked ! : Observable < MouseEvent | false > ; get clientHeight ( ) : number { return this . nativeElement . clientHeight ; } get clientWidth ( ) : number { return this . nativeElement . clientWidth ; } get scrollHeight ( ) : number { return this . nativeElement . scrollHeight ; } get scrollWidth ( ) : number { return this . nativeElement . scrollWidth ; } get scrollTop ( ) : number { return this . nativeElement . scrollTop ; } get scrollLeft ( ) : number { return this . nativeElement . scrollLeft ; } get scrollMaxX ( ) : number { return this . scrollWidth - this . clientWidth ; } get scrollMaxY ( ) : number { return this . scrollHeight - this . clientHeight ; } get contentHeight ( ) : number { return this . contentWrapperElement ?. clientHeight || 0 ; } get contentWidth ( ) : number { return this . contentWrapperElement ?. clientWidth || 0 ; } constructor ( public viewPort ) { this . nativeElement = viewPort . nativeElement ; } /**
     * Activate viewport pointer events such as 'hovered' and 'clicked' events
     */ activatePointerEvents ( propagate , destroyed ) { this . hovered = new Observable ( ( subscriber ) => { const mouseMoveStream = fromEvent < MouseEvent > ( this . nativeElement , 'mousemove' , { passive : true } ) ; const mouseMove = propagate ? mouseMoveStream : mouseMoveStream . pipe ( stopPropagation ( ) ) ; const mouseLeave = fromEvent < false > ( this . nativeElement , 'mouseleave' , { passive : true } ) . pipe ( map ( ( ) => false ) ) ; merge ( mouseMove , mouseLeave ) . pipe ( tap ( ( e ) => subscriber . next ( e ) ) , takeUntil ( destroyed ) ) . subscribe ( ) ; } ) ; this . clicked = new Observable ( ( subscriber ) => { const mouseDown = fromEvent < MouseEvent > ( this . nativeElement , 'mousedown' , { passive : true } ) . pipe ( tap ( ( e ) => subscriber . next ( e ) ) ) ; const mouseUp = fromEvent < false > ( this . nativeElement , 'mouseup' , { passive : true } ) . pipe ( tap ( ( ) => subscriber . next ( false ) ) ) ; mouseDown . pipe ( switchMap ( ( ) => mouseUp ) , takeUntil ( destroyed ) ) . subscribe ( ) ; } ) ; } /**
     * Set this directive as a non-functional wrapper, called when a custom viewport is used
     */ setAsWrapper ( ) { this . nativeElement . className = 'ng-native-scrollbar-hider ng-scroll-layer' ; if ( this . nativeElement . firstElementChild ) { this . nativeElement . firstElementChild . className = 'ng-scroll-layer' ; } } /**
     * Set this directive as  the viewport, called when no custom viewport is used
     */ setAsViewport ( customClassName ) { this . nativeElement . className = `ng-native-scrollbar-hider ng-scroll-viewport ${ customClassName }` ; if ( this . nativeElement . firstElementChild ) { this . contentWrapperElement = this . nativeElement . firstElementChild as HTMLElement ; this . contentWrapperElement . classList . add ( 'ng-scroll-content' ) ; } } /**
     * Scroll viewport vertically
     */ scrollYTo ( value ) { this . nativeElement . scrollTop = value ; } /**
     * Scroll viewport horizontally
     */ scrollXTo ( value ) { this . nativeElement . scrollLeft = value ; } }