UNPKG

ngx-scrollbar-v8

Version:

Custom overlay-scrollbars with native scrolling mechanism.

1,032 lines (1,020 loc) 37.7 kB
import { Directive, Inject, PLATFORM_ID, ElementRef, NgModule, Optional, Component, ChangeDetectionStrategy, ChangeDetectorRef, Input, ViewChild, ContentChild, forwardRef, NgZone } from '@angular/core'; import { isPlatformBrowser, DOCUMENT, CommonModule } from '@angular/common'; import { ScrollingModule, CdkVirtualScrollViewport, CdkScrollable } from '@angular/cdk/scrolling'; import { Breakpoints, BreakpointObserver, LayoutModule } from '@angular/cdk/layout'; import { Directionality, BidiModule } from '@angular/cdk/bidi'; import { supportsScrollBehavior } from '@angular/cdk/platform'; import { from, of, animationFrameScheduler, Subject, fromEvent, Subscription, BehaviorSubject } from 'rxjs'; import { tap, takeUntil, throttleTime, debounceTime, pluck, mergeMap } from 'rxjs/operators'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class SmoothScroll { /** * @param {?} _platform * @param {?} el */ constructor(_platform, el) { this._platform = _platform; this.view = el.nativeElement; } /** * @private * @param {?} left * @param {?} top * @return {?} */ scrollFunc(left, top) { if (supportsScrollBehavior()) { this.view.scrollTo({ top, left }); } else { this.view.scrollTop = top; this.view.scrollLeft = left; } } /** * @param {?} options * @return {?} */ scrollTo(options) { // Avoid SSR error if (isPlatformBrowser(this._platform)) { /** @type {?} */ const scrollFunc = (/** * @param {?} left * @param {?} top * @return {?} */ (left, top) => { if (supportsScrollBehavior()) { this.view.scrollTo({ top, left }); } else { this.view.scrollTop = top; this.view.scrollLeft = left; } }); if (options.duration) { /** @type {?} */ const smoothScrollOptions = { top: options.top, left: options.left, duration: options.duration, easeFunc: options.easeFunc || easeInOutQuad, offsetTop: this.view.scrollTop, offsetLeft: this.view.scrollLeft, scrollFunc }; return from(smoothScroll(smoothScrollOptions)); } this.scrollFunc(options.left, options.top); } return of(); } /** * @param {?} selector * @param {?=} offset * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToElement(selector, offset = 0, duration, easeFunc) { /** @type {?} */ const target = this.view.querySelector(selector); return target ? this.scrollTo({ left: target.offsetLeft, top: target.offsetTop - offset, duration, easeFunc }) : of(); } /** * @param {?} left * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollXTo(left, duration, easeFunc) { return this.scrollTo({ left, duration, easeFunc }); } /** * @param {?} top * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollYTo(top, duration, easeFunc) { return this.scrollTo({ top, duration, easeFunc }); } /** * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToTop(duration, easeFunc) { return this.scrollYTo(0, duration, easeFunc); } /** * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToBottom(duration, easeFunc) { return this.scrollYTo(this.view.scrollHeight - this.view.clientHeight, duration, easeFunc); } /** * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToRight(duration, easeFunc) { return this.scrollXTo(this.view.scrollWidth, duration, easeFunc); } /** * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToLeft(duration, easeFunc) { return this.scrollXTo(0, duration, easeFunc); } } SmoothScroll.decorators = [ { type: Directive, args: [{ selector: '[smoothScroll], [smooth-scroll]' },] } ]; /** @nocollapse */ SmoothScroll.ctorParameters = () => [ { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }, { type: ElementRef } ]; /** * @param {?} options * @return {?} */ function smoothScroll(options) { return new Promise((/** * @param {?} resolve * @return {?} */ resolve => { /** @type {?} */ let currentTime = 0; /** @type {?} */ const increment = 10; /** @type {?} */ let valX = options.offsetLeft; /** @type {?} */ let valY = options.offsetTop; /** @type {?} */ const animateScroll = (/** * @return {?} */ () => { // increment the time currentTime += increment; // find the value with the easing function if (typeof options.left !== 'undefined') { /** @type {?} */ const deltaX = options.left - options.offsetLeft; valX = options.easeFunc(currentTime, options.offsetLeft, deltaX, options.duration); } if (typeof options.top !== 'undefined') { /** @type {?} */ const deltaY = options.top - options.offsetTop; valY = options.easeFunc(currentTime, options.offsetTop, deltaY, options.duration); } // scroll to position options.scrollFunc(valX, valY); // do the animation unless its over if (currentTime < options.duration) { animationFrameScheduler.schedule(animateScroll); } else { resolve(); } }); animateScroll(); })); } // easing functions http://goo.gl/5HLl8 /** * @param {?} t * @param {?} b * @param {?} c * @param {?} d * @return {?} */ function easeInOutQuad(t, b, c, d) { t /= d / 2; if (t < 1) { return (c / 2) * t * t + b; } t--; return (-c / 2) * (t * (t - 2) - 1) + b; } /** * @param {?} t * @param {?} b * @param {?} c * @param {?} d * @return {?} */ function easeInCubic(t, b, c, d) { /** @type {?} */ const tc = (t /= d) * t * t; return b + c * tc; } /** * @param {?} t * @param {?} b * @param {?} c * @param {?} d * @return {?} */ function inOutQuintic(t, b, c, d) { /** @type {?} */ const ts = (t /= d) * t; /** @type {?} */ const tc = ts * t; return b + c * (6 * tc * ts + -15 * ts * ts + 10 * tc); } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class SmoothScrollModule { } SmoothScrollModule.decorators = [ { type: NgModule, args: [{ imports: [ScrollingModule], declarations: [SmoothScroll], exports: [SmoothScroll] },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NgScrollbarView { /** * @param {?} virtualScrollViewport * @param {?} smoothScroll */ constructor(virtualScrollViewport, smoothScroll) { this.virtualScrollViewport = virtualScrollViewport; this.smoothScroll = smoothScroll; if (!virtualScrollViewport) { throw new Error('NgScrollBar: add [NgScrollbarView] directive on CdkVirtualScrollViewport component only'); } if (!smoothScroll) { throw new Error('NgScrollBar: add [smoothScroll] directive is required with [NgScrollbarView]'); } } } NgScrollbarView.decorators = [ { type: Directive, args: [{ selector: '[ngScrollbarView]', host: { '[class.ng-custom-scroll-view]': 'true' } },] } ]; /** @nocollapse */ NgScrollbarView.ctorParameters = () => [ { type: CdkVirtualScrollViewport, decorators: [{ type: Optional }] }, { type: SmoothScroll, decorators: [{ type: Optional }] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NgScrollbar { /** * @param {?} _changeDetectorRef * @param {?} _breakpointObserver * @param {?} _platform */ constructor(_changeDetectorRef, _breakpointObserver, _platform) { this._changeDetectorRef = _changeDetectorRef; this._breakpointObserver = _breakpointObserver; this._platform = _platform; /** * Horizontal custom scrollbar */ this.trackX = false; /** * Vertical custom Scrollbar */ this.trackY = true; /** * Scrollbar visibility */ this.shown = 'native'; /** * Auto update scrollbars on content changes (Mutation Observer) */ this.autoUpdate = true; /** * The smooth scroll duration when a scrollbar is clicked */ this.scrollToDuration = 300; /** * Disable custom scrollbars on specific breakpoints */ this.disableOnBreakpoints = [ Breakpoints.HandsetLandscape, Breakpoints.HandsetPortrait ]; this._disabled = false; /** * Unsubscribe component observables on destroy */ this._unsubscribe$ = new Subject(); /** * Steam that emits when scrollbar thumbnail needs to update (for internal uses) */ this._updateObserver = new Subject(); this.updateObserver = this._updateObserver.asObservable(); } /** * Disable custom scrollbars and switch back to native scrollbars * @return {?} */ get disabled() { return this._disabled; } /** * @param {?} disable * @return {?} */ set disabled(disable) { disable ? this.disable() : this.enable(); } /** * Viewport Element * @return {?} */ get view() { return this.customViewPort ? this.customViewPort.virtualScrollViewport.getElementRef().nativeElement : this.scrollViewport.getElementRef().nativeElement; } /** * @return {?} */ get scrollable() { return this.customViewPort ? this.customViewPort.virtualScrollViewport : this.scrollViewport; } /** * @return {?} */ get smoothScroll() { return this.customViewPort ? this.customViewPort.smoothScroll : this.viewSmoothScroll; } /** * @return {?} */ showScrollbarY() { return this.shown === 'always' || this.view.scrollHeight > this.view.clientHeight; } /** * @return {?} */ showScrollbarX() { return this.shown === 'always' || this.view.scrollWidth > this.view.clientWidth; } /** * @return {?} */ ngAfterViewInit() { // Avoid 'expression has changed after it was checked' error when 'disableOnBreakpoints' is set to false Promise.resolve().then((/** * @return {?} */ () => { if (!this.disabled) { if (this.disableOnBreakpoints) { // Enable/Disable custom scrollbar on breakpoints (Used to disable scrollbars on mobile phones) this._breakpointObserver.observe(this.disableOnBreakpoints).pipe(tap((/** * @param {?} result * @return {?} */ (result) => result.matches ? this.disable() : this.enable())), takeUntil(this._unsubscribe$)).subscribe(); } else { this.enable(); } } // Update state on content changes this.updateObserver.pipe(throttleTime(200), tap((/** * @return {?} */ () => this._changeDetectorRef.markForCheck())), takeUntil(this._unsubscribe$)).subscribe(); if (isPlatformBrowser(this._platform)) { // Update on window resize fromEvent(window, 'resize').pipe(throttleTime(200), tap((/** * @return {?} */ () => this.update())), takeUntil(this._unsubscribe$)).subscribe(); } })); } /** * @return {?} */ ngOnDestroy() { this._unsubscribe$.next(); this._unsubscribe$.complete(); if (this._observer) { this._observer.disconnect(); } } /** * Update scrollbar thumbnail position * @return {?} */ update() { if (!this.disabled) { this._updateObserver.next(); } } /** * Enable custom scrollbar * @return {?} */ enable() { if (this.view) { this._disabled = false; // Update view this._changeDetectorRef.markForCheck(); if (!this.customViewPort && this.autoUpdate && isPlatformBrowser(this._platform)) { // Observe content changes this._observer = new MutationObserver((/** * @return {?} */ () => this.update())); this._observer.observe(this.view, { subtree: true, childList: true, characterData: true }); } } } /** * Disable custom scrollbar * @return {?} */ disable() { this._disabled = true; if (this._observer) { this._observer.disconnect(); } } /** * @param {?} options * @return {?} */ scrollTo(options) { return this.smoothScroll.scrollTo(options); } /** * @param {?} selector * @param {?=} offset * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToElement(selector, offset = 0, duration, easeFunc) { return this.smoothScroll.scrollToElement(selector, offset, duration, easeFunc); } /** * @param {?} to * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollXTo(to, duration, easeFunc) { return this.smoothScroll.scrollXTo(to, duration, easeFunc); } /** * @param {?} to * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollYTo(to, duration, easeFunc) { return this.smoothScroll.scrollYTo(to, duration, easeFunc); } /** * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToTop(duration, easeFunc) { return this.smoothScroll.scrollToTop(duration, easeFunc); } /** * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToBottom(duration, easeFunc) { return this.smoothScroll.scrollToBottom(duration, easeFunc); } /** * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToRight(duration, easeFunc) { return this.smoothScroll.scrollToRight(duration, easeFunc); } /** * @param {?=} duration * @param {?=} easeFunc * @return {?} */ scrollToLeft(duration, easeFunc) { return this.smoothScroll.scrollToLeft(duration, easeFunc); } } NgScrollbar.decorators = [ { type: Component, args: [{ selector: 'ng-scrollbar', template: "<div class=\"ng-scrollbar-layout ng-scrollbar-x-layout\"\n [class.ng-scrollbar-invert]=\"invertX\">\n\n <div class=\"ng-scrollbar-layout ng-scrollbar-y-layout\"\n [class.ng-scrollbar-invert]=\"invertY\">\n\n <div class=\"ng-scroll-view-container\">\n <div #view\n cdkScrollable\n smoothScroll\n class=\"ng-scroll-view {{viewClass}}\">\n <ng-content></ng-content>\n </div>\n </div>\n\n <ng-scrollbar-y #y\n *ngIf=\"!disabled && trackY\"\n [class.ng-scrollbar-visible]=\"showScrollbarY()\"\n [barClass]=\"barClass\"\n [thumbClass]=\"thumbClass\"\n [scrollToDuration]=\"scrollToDuration\">\n </ng-scrollbar-y>\n </div>\n\n <ng-scrollbar-x #x\n *ngIf=\"!disabled && trackX\"\n [class.ng-scrollbar-visible]=\"showScrollbarX()\"\n [barClass]=\"barClass\"\n [thumbClass]=\"thumbClass\"\n [scrollToDuration]=\"scrollToDuration\">\n </ng-scrollbar-x>\n\n</div>\n", changeDetection: ChangeDetectionStrategy.OnPush, host: { '[attr.customView]': '!!customViewPort', '[attr.trackX]': 'trackX', '[attr.trackY]': 'trackY', '[attr.compact]': 'compact', '[attr.autoHide]': 'shown === "hover"', '[attr.disabled]': 'disabled' }, styles: [":host{display:block;overflow:hidden;--scrollbar-color:transparent;--scrollbar-container-color:transparent;--scrollbar-thumb-color:rgba(0, 0, 0, 0.2);--scrollbar-thumb-hover-color:rgba(0, 0, 0, 0.3);--scrollbar-border-radius:4px;--scrollbar-size:6px;--scrollbar-padding:8px;--scroll-view-margin:0;--scroll-view-color:transparent}:host[trackY=true]>.ng-scrollbar-layout>.ng-scrollbar-layout>.ng-scroll-view-container>.ng-scroll-view{overflow-y:scroll}:host[trackX=true]>.ng-scrollbar-layout>.ng-scrollbar-layout>.ng-scroll-view-container>.ng-scroll-view{overflow-x:scroll}:host>.ng-scrollbar-x-layout{flex-direction:column}:host>.ng-scrollbar-x-layout.ng-scrollbar-invert{flex-direction:column-reverse}:host>.ng-scrollbar-x-layout>.ng-scrollbar-y-layout{flex-direction:row}:host>.ng-scrollbar-x-layout>.ng-scrollbar-y-layout.ng-scrollbar-invert{flex-direction:row-reverse}:host[compact=true]>.ng-scrollbar-x-layout>ng-scrollbar-x{position:absolute;bottom:0}:host[compact=true]>.ng-scrollbar-x-layout.ng-scrollbar-invert>ng-scrollbar-x{top:0;bottom:unset}:host[compact=true]>.ng-scrollbar-x-layout>.ng-scrollbar-y-layout>ng-scrollbar-y{position:absolute;right:0;left:unset}:host[compact=true]>.ng-scrollbar-x-layout>.ng-scrollbar-y-layout.ng-scrollbar-invert>ng-scrollbar-y{right:unset;left:0}:host[autoHide=true]>.ng-scrollbar-layout>.ng-scrollbar-layout>ng-scrollbar-y,:host[autoHide=true]>.ng-scrollbar-layout>ng-scrollbar-x{opacity:0;transition:opacity 120ms ease-out}:host[autoHide=true]:active>.ng-scrollbar-layout>.ng-scrollbar-layout>ng-scrollbar-y,:host[autoHide=true]:active>.ng-scrollbar-layout>ng-scrollbar-x,:host[autoHide=true]:focus>.ng-scrollbar-layout>.ng-scrollbar-layout>ng-scrollbar-y,:host[autoHide=true]:focus>.ng-scrollbar-layout>ng-scrollbar-x,:host[autoHide=true]:hover>.ng-scrollbar-layout>.ng-scrollbar-layout>ng-scrollbar-y,:host[autoHide=true]:hover>.ng-scrollbar-layout>ng-scrollbar-x{opacity:1;transition:opacity 340ms ease-out}:host[customView=true] .ng-scroll-view{overflow:hidden!important}.ng-scroll-view,.ng-scrollbar-layout,:host{position:relative;height:100%;width:100%}.ng-scrollbar-layout{display:flex;min-height:0}.ng-scroll-view-container{flex:1;position:relative;overflow:hidden;margin:var(--scroll-view-margin)}.ng-scroll-view{box-sizing:content-box;-webkit-transform:translateZ(0);transform:translateZ(0);background:var(--scroll-view-color);-webkit-overflow-scrolling:touch}ng-scrollbar-x,ng-scrollbar-y{display:none;box-sizing:border-box;padding:var(--scrollbar-padding);background:var(--scrollbar-container-color)}ng-scrollbar-x.ng-scrollbar-visible,ng-scrollbar-y.ng-scrollbar-visible{display:block}ng-scrollbar-y{top:0;bottom:0}ng-scrollbar-x{left:0;right:0}::ng-deep ng-scrollbar-y .ng-scrollbar{width:var(--scrollbar-size)}::ng-deep ng-scrollbar-y .ng-scrollbar-thumb{width:100%}::ng-deep ng-scrollbar-x .ng-scrollbar{height:var(--scrollbar-size)}::ng-deep ng-scrollbar-x .ng-scrollbar-thumb{height:100%}::ng-deep .ng-scrollbar{height:100%;width:100%;z-index:1;border-radius:var(--scrollbar-border-radius);background-color:var(--scrollbar-color)}::ng-deep .ng-scrollbar-thumb{box-sizing:border-box;position:relative;width:0;height:0;border-radius:inherit;background-color:var(--scrollbar-thumb-color);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);transition:height 150ms ease-out}::ng-deep .ng-scrollbar-thumb:active,::ng-deep .ng-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover-color)}::ng-deep .ng-custom-scroll-view{height:100%}.show-native-scrollbars,:host[disabled=true] .ng-scroll-view,:host[disabled=true] ::ng-deep .ng-scroll-view>.ng-custom-scroll-view{margin:0!important;padding:0!important}.hide-native-scrollbars,:host[disabled=false] .ng-scroll-view,:host[disabled=false] ::ng-deep .ng-scroll-view>.ng-custom-scroll-view{margin-right:-30px!important;padding-right:30px!important;margin-bottom:-30px!important;padding-bottom:30px!important}"] }] } ]; /** @nocollapse */ NgScrollbar.ctorParameters = () => [ { type: ChangeDetectorRef }, { type: BreakpointObserver }, { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] } ]; NgScrollbar.propDecorators = { trackX: [{ type: Input }], trackY: [{ type: Input }], shown: [{ type: Input }], autoUpdate: [{ type: Input }], viewClass: [{ type: Input }], barClass: [{ type: Input }], thumbClass: [{ type: Input }], scrollToDuration: [{ type: Input }], compact: [{ type: Input }], invertY: [{ type: Input }], invertX: [{ type: Input }], disableOnBreakpoints: [{ type: Input }], disabled: [{ type: Input, args: ['disabled',] }], verticalScrollbar: [{ type: ViewChild, args: ['y', { read: ElementRef, static: false },] }], horizontalScrollbar: [{ type: ViewChild, args: ['x', { read: ElementRef, static: false },] }], scrollViewport: [{ type: ViewChild, args: [CdkScrollable, { static: true },] }], viewSmoothScroll: [{ type: ViewChild, args: [SmoothScroll, { static: true },] }], customViewPort: [{ type: ContentChild, args: [NgScrollbarView, { static: true },] }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NgScrollbarThumb { /** * @param {?} _parent * @param {?} _platform * @param {?} _zone */ constructor(_parent, _platform, _zone) { this._parent = _parent; this._platform = _platform; this._zone = _zone; this._minThumbSize = 20; this._naturalThumbSize = 0; this._thumbSize = 0; this._trackMax = 0; this._scrollMax = 0; this._currPos = 0; this._scroll$ = Subscription.EMPTY; this._thumbDrag$ = Subscription.EMPTY; this._updateObserver$ = Subscription.EMPTY; this._state = new BehaviorSubject({ transform: 'translate3d(0, 0, 0)' }); /** * Scrollbar styles */ this.scrollbarStyle = this._state.asObservable(); } /** * @return {?} */ get thumbSize() { return 0; } /** * @return {?} */ ngAfterViewInit() { // Avoid SSR Error if (isPlatformBrowser(this._platform)) { this._view = this._parent.view; // Start view scroll event this._scroll$ = this._parent.scrollable.elementScrolled() .subscribe((/** * @return {?} */ () => this.updateScrollbar())); // Start scrollbar thumbnail drag events this._zone.runOutsideAngular((/** * @return {?} */ () => this._thumbDrag$ = this.startThumbEvents().subscribe())); // Update scrollbar thumbnail size on content changes this._updateObserver$ = this._parent.updateObserver.pipe(throttleTime(200), tap((/** * @return {?} */ () => this.updateScrollbar())), // Make sure scrollbar thumbnail position is correct after the new content is rendered debounceTime(200), tap((/** * @return {?} */ () => this.updateScrollbar()))).subscribe(); // Initialize scrollbar setTimeout((/** * @return {?} */ () => this.updateScrollbar()), 200); } } /** * @return {?} */ ngOnDestroy() { this._scroll$.unsubscribe(); this._thumbDrag$.unsubscribe(); this._updateObserver$.unsubscribe(); } /** * Scrollbar click * @param {?} e Mouse event * @return {?} */ onScrollbarHolderClick(e) { } /** * Update scrollbar * @protected * @return {?} */ updateScrollbar() { } /** * Start vertical thumb worker * @protected * @return {?} */ startThumbEvents() { return undefined; } /** * Get scrollbar thumb size * @protected * @param {?} naturalThumbSize * @param {?} scrollMax * @return {?} */ scrollBoundaries(naturalThumbSize, scrollMax) { return (naturalThumbSize < this._minThumbSize) ? this._minThumbSize : scrollMax ? naturalThumbSize : 0; } /** * @protected * @param {?} state * @return {?} */ updateState(state) { this._state.next(Object.assign({}, this._state.value, state)); } } NgScrollbarThumb.propDecorators = { barClass: [{ type: Input }], thumbClass: [{ type: Input }], scrollToDuration: [{ type: Input }], bar: [{ type: ViewChild, args: ['bar', { static: true },] }], thumb: [{ type: ViewChild, args: ['thumb', { static: true },] }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NgScrollbarY extends NgScrollbarThumb { /** * @param {?} _document * @param {?} _parent * @param {?} _platform * @param {?} _zone */ constructor(_document, _parent, _platform, _zone) { super(_parent, _platform, _zone); this._document = _document; this._parent = _parent; this._zone = _zone; } /** * Calculate scrollbar thumbnail size * @return {?} */ get thumbSize() { /** @type {?} */ const barClientHeight = this.bar.nativeElement.clientHeight; /** @type {?} */ const viewClientHeight = this._view.clientHeight; /** @type {?} */ const viewScrollHeight = this._view.scrollHeight; this._naturalThumbSize = barClientHeight / viewScrollHeight * barClientHeight; this._scrollMax = viewScrollHeight - viewClientHeight; return this.scrollBoundaries(this._naturalThumbSize, this._scrollMax); } /** * Scrollbar click * @param {?} e Mouse event * @return {?} */ onScrollbarHolderClick(e) { if (e.target === e.currentTarget) { /** @type {?} */ const offsetY = e.offsetY - this._naturalThumbSize * .5; /** @type {?} */ const thumbPositionPercentage = offsetY * 100 / this.bar.nativeElement.clientHeight; /** @type {?} */ const value = thumbPositionPercentage * this._view.scrollHeight / 100; this._parent.scrollTo((/** @type {?} */ ({ top: value, duration: this.scrollToDuration }))).subscribe(); } } /** * Update scrollbar * @protected * @return {?} */ updateScrollbar() { this._thumbSize = this.thumb.nativeElement.clientHeight; this._trackMax = this.bar.nativeElement.clientHeight - this._thumbSize; this._currPos = this._view.scrollTop * this._trackMax / this._scrollMax; this._zone.run((/** * @return {?} */ () => { animationFrameScheduler.schedule((/** * @return {?} */ () => this.updateState({ transform: `translate3d(0, ${this._currPos}px, 0)`, height: `${this.thumbSize}px` }))); })); } /** * Start vertical thumb worker * @protected * @return {?} */ startThumbEvents() { /** @type {?} */ const mouseDown$ = fromEvent(this.thumb.nativeElement, 'mousedown'); /** @type {?} */ const mouseMove$ = fromEvent(this._document, 'mousemove'); /** @type {?} */ const mouseUp$ = fromEvent(this._document, 'mouseup').pipe(tap((/** * @return {?} */ () => this._document.onselectstart = null))); return mouseDown$.pipe(tap((/** * @return {?} */ () => { this._document.onselectstart = (/** * @return {?} */ () => false); // Initialize trackMax for before start dragging this._trackMax = this.bar.nativeElement.clientHeight - this._thumbSize; })), pluck('offsetY'), mergeMap((/** * @param {?} mouseDownOffset * @return {?} */ (mouseDownOffset) => mouseMove$.pipe(takeUntil(mouseUp$), pluck('clientY'), tap((/** * @param {?} mouseMoveClient * @return {?} */ (mouseMoveClient) => { /** @type {?} */ const offsetY = mouseMoveClient - this.bar.nativeElement.getBoundingClientRect().top; /** @type {?} */ const value = this._scrollMax * (offsetY - mouseDownOffset) / this._trackMax; this._parent.scrollable.scrollTo({ top: value }); })))))); } } NgScrollbarY.decorators = [ { type: Component, args: [{ selector: 'ng-scrollbar-y', changeDetection: ChangeDetectionStrategy.OnPush, template: ` <div #bar class="ng-scrollbar {{barClass}}" (mousedown)="onScrollbarHolderClick($event)"> <div #thumb class="ng-scrollbar-thumb {{thumbClass}}" [ngStyle]="scrollbarStyle | async"></div> </div> ` }] } ]; /** @nocollapse */ NgScrollbarY.ctorParameters = () => [ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }, { type: NgScrollbar, decorators: [{ type: Inject, args: [forwardRef((/** * @return {?} */ () => NgScrollbar)),] }] }, { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }, { type: NgZone } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NgScrollbarX extends NgScrollbarThumb { /** * @param {?} _document * @param {?} _parent * @param {?} _platform * @param {?} _dir * @param {?} _zone */ constructor(_document, _parent, _platform, _dir, _zone) { super(_parent, _platform, _zone); this._document = _document; this._parent = _parent; this._dir = _dir; this._zone = _zone; } /** * Calculate scrollbar thumbnail size * @return {?} */ get thumbSize() { /** @type {?} */ const barClientWidth = this.bar.nativeElement.clientWidth; /** @type {?} */ const viewClientWidth = this._view.clientWidth; /** @type {?} */ const viewScrollWidth = this._view.scrollWidth; this._naturalThumbSize = barClientWidth / viewScrollWidth * barClientWidth; this._scrollMax = viewScrollWidth - viewClientWidth; return this.scrollBoundaries(this._naturalThumbSize, this._scrollMax); } /** * Scrollbar click * @param {?} e Mouse event * @return {?} */ onScrollbarHolderClick(e) { if (e.target === e.currentTarget) { /** @type {?} */ const offsetX = e.offsetX - this._naturalThumbSize * .5; /** @type {?} */ const thumbPositionPercentage = offsetX * 100 / this.bar.nativeElement.clientWidth; /** @type {?} */ const value = thumbPositionPercentage * this._view.scrollWidth / 100; this._parent.scrollTo((/** @type {?} */ ({ left: value, duration: this.scrollToDuration }))).subscribe(); } } /** * Update scrollbar * @protected * @return {?} */ updateScrollbar() { this._thumbSize = this.thumb.nativeElement.clientWidth; this._trackMax = this.bar.nativeElement.clientWidth - this._thumbSize; this._currPos = this._view.scrollLeft * this._trackMax / this._scrollMax; this._zone.run((/** * @return {?} */ () => { animationFrameScheduler.schedule((/** * @return {?} */ () => this.updateState({ transform: `translate3d(${this._dir.value === 'rtl' ? this._currPos - this._trackMax : this._currPos}px, 0, 0)`, width: `${this.thumbSize}px` }))); })); } /** * Start horizontal thumb worker * @protected * @return {?} */ startThumbEvents() { /** @type {?} */ const mouseDown$ = fromEvent(this.thumb.nativeElement, 'mousedown'); /** @type {?} */ const mouseMove$ = fromEvent(this._document, 'mousemove'); /** @type {?} */ const mouseUp$ = fromEvent(this._document, 'mouseup').pipe(tap((/** * @return {?} */ () => this._document.onselectstart = null))); return mouseDown$.pipe(tap((/** * @return {?} */ () => { this._document.onselectstart = (/** * @return {?} */ () => false); // Initialize trackMax for before start dragging this._trackMax = this.bar.nativeElement.clientWidth - this._thumbSize; })), pluck('offsetX'), mergeMap((/** * @param {?} mouseDownOffset * @return {?} */ (mouseDownOffset) => mouseMove$.pipe(takeUntil(mouseUp$), pluck('clientX'), tap((/** * @param {?} mouseMoveClient * @return {?} */ (mouseMoveClient) => { /** @type {?} */ const offsetX = mouseMoveClient - this.bar.nativeElement.getBoundingClientRect().left; /** @type {?} */ let value = this._scrollMax * (offsetX - mouseDownOffset) / this._trackMax; if (this._dir.value === 'rtl') { value = value === 0 ? offsetX - this._trackMax : value; } this._parent.scrollable.scrollTo({ left: value }); })))))); } } NgScrollbarX.decorators = [ { type: Component, args: [{ selector: 'ng-scrollbar-x', changeDetection: ChangeDetectionStrategy.OnPush, template: ` <div #bar class="ng-scrollbar {{barClass}}" (mousedown)="onScrollbarHolderClick($event)"> <div #thumb class="ng-scrollbar-thumb {{thumbClass}}" [ngStyle]="scrollbarStyle | async"></div> </div> ` }] } ]; /** @nocollapse */ NgScrollbarX.ctorParameters = () => [ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }, { type: NgScrollbar, decorators: [{ type: Inject, args: [forwardRef((/** * @return {?} */ () => NgScrollbar)),] }] }, { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }, { type: Directionality }, { type: NgZone } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NgScrollbarModule { } NgScrollbarModule.decorators = [ { type: NgModule, args: [{ imports: [ CommonModule, ScrollingModule, LayoutModule, BidiModule, SmoothScrollModule ], declarations: [ NgScrollbar, NgScrollbarY, NgScrollbarX, NgScrollbarView ], exports: [ NgScrollbar, NgScrollbarView, SmoothScrollModule ] },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { NgScrollbar, NgScrollbarModule, SmoothScroll, SmoothScrollModule, easeInCubic, easeInOutQuad, inOutQuintic, smoothScroll, NgScrollbarView as ɵa, NgScrollbarY as ɵb, NgScrollbarThumb as ɵc, NgScrollbarX as ɵd }; //# sourceMappingURL=ngx-scrollbar.js.map