Skip to content

Commit f2ed92c

Browse files
committed
feat: add native-scrollbars option to workaround scrolling perf issues
1 parent d8b6e02 commit f2ed92c

File tree

4 files changed

+32
-14
lines changed

4 files changed

+32
-14
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ ReDoc makes use of the following [vendor extensions](http://swagger.io/specifica
156156
* `no-auto-auth` - do not inject Authentication section automatically
157157
* `path-in-middle-panel` - show path link and HTTP verb in the middle panel instead of the right one
158158
* `hide-loading` - do not show loading animation. Useful for small docs
159+
* `native-scrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs)
159160

160161
## Advanced usage
161162
Instead of adding `spec-url` attribute to the `<redoc>` element you can initialize ReDoc via globally exposed `Redoc` object:

lib/components/SideMenu/side-menu.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ $mobile-menu-compact-breakpoint: 550px;
99
#resources-nav {
1010
position: relative;
1111
width: 100%;
12+
overflow: scroll;
1213
}
1314

1415
ul.menu-root {

lib/services/options.service.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const OPTION_NAMES = new Set([
2222
'untrustedSpec',
2323
'hideLoading',
2424
'ignoredHeaderParameters',
25+
'nativeScrollbars',
2526
]);
2627

2728
export interface Options {
@@ -40,6 +41,7 @@ export interface Options {
4041
hideLoading?: boolean;
4142
spec?: any;
4243
ignoredHeaderParameters?: string[];
44+
nativeScrollbars?: boolean;
4345
}
4446

4547
@Injectable()
@@ -79,7 +81,7 @@ export class OptionsService {
7981
this._normalizeOptions();
8082
}
8183

82-
_normalizeOptions():void {
84+
_normalizeOptions(): void {
8385
// modify scrollYOffset to always be a function
8486
if (!isFunction(this._options.scrollYOffset)) {
8587
if (isFinite(this._options.scrollYOffset)) {
@@ -109,6 +111,8 @@ export class OptionsService {
109111
if (isString(this._options.pathInMiddlePanel)) this._options.pathInMiddlePanel = true;
110112
if (isString(this._options.untrustedSpec)) this._options.untrustedSpec = true;
111113
if (isString(this._options.hideLoading)) this._options.hideLoading = true;
114+
if (isString(this._options.nativeScrollbars))
115+
this._options.nativeScrollbars = true;
112116
if (isString(this._options.expandResponses)) {
113117
let str = this._options.expandResponses as string;
114118
if (str === 'all') return;
Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,49 @@
1-
'use strict';
2-
31
import 'perfect-scrollbar/dist/css/perfect-scrollbar.css';
42

5-
import { Directive, ElementRef, Input, OnInit, OnDestroy } from '@angular/core';
6-
import { BrowserDomAdapter as DOM } from '../../../utils/browser-adapter';
7-
3+
import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core';
84
import * as PS from 'perfect-scrollbar';
95

6+
import { OptionsService } from '../../../services/options.service';
7+
108
@Directive({
11-
selector: '[perfect-scrollbar]'
9+
selector: '[perfect-scrollbar]',
1210
})
1311
export class PerfectScrollbar implements OnInit, OnDestroy {
1412
$element: any;
1513
subscription: any;
14+
enabled: boolean = true;
1615

17-
constructor(elementRef:ElementRef) {
16+
constructor(elementRef: ElementRef, optionsService: OptionsService) {
1817
this.$element = elementRef.nativeElement;
18+
this.enabled = !optionsService.options.nativeScrollbars;
1919
}
2020

2121
update() {
22+
if (!this.enabled) return;
2223
PS.update(this.$element);
2324
}
2425

2526
ngOnInit() {
26-
requestAnimationFrame(() => PS.initialize(this.$element, {
27-
wheelSpeed: 2,
28-
wheelPropagation: false,
29-
minScrollbarLength: 20,
30-
suppressScrollX: true
31-
}));
27+
if (!this.enabled) return;
28+
requestAnimationFrame(() =>
29+
PS.initialize(this.$element, {
30+
wheelSpeed: 2,
31+
handlers: [
32+
'click-rail',
33+
'drag-scrollbar',
34+
'keyboard',
35+
'wheel',
36+
'touch',
37+
],
38+
wheelPropagation: true,
39+
minScrollbarLength: 20,
40+
suppressScrollX: true,
41+
} as any),
42+
);
3243
}
3344

3445
ngOnDestroy() {
46+
if (!this.enabled) return;
3547
PS.destroy(this.$element);
3648
}
3749
}

0 commit comments

Comments
 (0)