diff --git a/README.md b/README.md index 1b206b1ba9..7f353c9f75 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ ReDoc makes use of the following [vendor extensions](http://swagger.io/specifica * `no-auto-auth` - do not inject Authentication section automatically * `path-in-middle-panel` - show path link and HTTP verb in the middle panel instead of the right one * `hide-loading` - do not show loading animation. Useful for small docs +* `native-scrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs) ## Advanced usage Instead of adding `spec-url` attribute to the `` element you can initialize ReDoc via globally exposed `Redoc` object: diff --git a/lib/components/SideMenu/side-menu.scss b/lib/components/SideMenu/side-menu.scss index 4cb5275444..f213f41995 100644 --- a/lib/components/SideMenu/side-menu.scss +++ b/lib/components/SideMenu/side-menu.scss @@ -9,6 +9,7 @@ $mobile-menu-compact-breakpoint: 550px; #resources-nav { position: relative; width: 100%; + overflow: scroll; } ul.menu-root { diff --git a/lib/services/options.service.ts b/lib/services/options.service.ts index ef2cc975c4..97d099d386 100644 --- a/lib/services/options.service.ts +++ b/lib/services/options.service.ts @@ -22,6 +22,7 @@ const OPTION_NAMES = new Set([ 'untrustedSpec', 'hideLoading', 'ignoredHeaderParameters', + 'nativeScrollbars', ]); export interface Options { @@ -40,6 +41,7 @@ export interface Options { hideLoading?: boolean; spec?: any; ignoredHeaderParameters?: string[]; + nativeScrollbars?: boolean; } @Injectable() @@ -79,7 +81,7 @@ export class OptionsService { this._normalizeOptions(); } - _normalizeOptions():void { + _normalizeOptions(): void { // modify scrollYOffset to always be a function if (!isFunction(this._options.scrollYOffset)) { if (isFinite(this._options.scrollYOffset)) { @@ -109,6 +111,8 @@ export class OptionsService { if (isString(this._options.pathInMiddlePanel)) this._options.pathInMiddlePanel = true; if (isString(this._options.untrustedSpec)) this._options.untrustedSpec = true; if (isString(this._options.hideLoading)) this._options.hideLoading = true; + if (isString(this._options.nativeScrollbars)) + this._options.nativeScrollbars = true; if (isString(this._options.expandResponses)) { let str = this._options.expandResponses as string; if (str === 'all') return; diff --git a/lib/shared/components/PerfectScrollbar/perfect-scrollbar.ts b/lib/shared/components/PerfectScrollbar/perfect-scrollbar.ts index 5ef6fc0dae..7ceafb4510 100644 --- a/lib/shared/components/PerfectScrollbar/perfect-scrollbar.ts +++ b/lib/shared/components/PerfectScrollbar/perfect-scrollbar.ts @@ -1,37 +1,49 @@ -'use strict'; - import 'perfect-scrollbar/dist/css/perfect-scrollbar.css'; -import { Directive, ElementRef, Input, OnInit, OnDestroy } from '@angular/core'; -import { BrowserDomAdapter as DOM } from '../../../utils/browser-adapter'; - +import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core'; import * as PS from 'perfect-scrollbar'; +import { OptionsService } from '../../../services/options.service'; + @Directive({ - selector: '[perfect-scrollbar]' + selector: '[perfect-scrollbar]', }) export class PerfectScrollbar implements OnInit, OnDestroy { $element: any; subscription: any; + enabled: boolean = true; - constructor(elementRef:ElementRef) { + constructor(elementRef: ElementRef, optionsService: OptionsService) { this.$element = elementRef.nativeElement; + this.enabled = !optionsService.options.nativeScrollbars; } update() { + if (!this.enabled) return; PS.update(this.$element); } ngOnInit() { - requestAnimationFrame(() => PS.initialize(this.$element, { - wheelSpeed: 2, - wheelPropagation: false, - minScrollbarLength: 20, - suppressScrollX: true - })); + if (!this.enabled) return; + requestAnimationFrame(() => + PS.initialize(this.$element, { + wheelSpeed: 2, + handlers: [ + 'click-rail', + 'drag-scrollbar', + 'keyboard', + 'wheel', + 'touch', + ], + wheelPropagation: true, + minScrollbarLength: 20, + suppressScrollX: true, + } as any), + ); } ngOnDestroy() { + if (!this.enabled) return; PS.destroy(this.$element); } }