From 1bd8214ca78d83bc8c06ed695a5f3a6e2b300c97 Mon Sep 17 00:00:00 2001 From: Nikita Poltoratsky Date: Thu, 29 Nov 2018 22:58:05 +0300 Subject: [PATCH] fix(select): disable layout scrolling (#1012) Closes #992 --- scripts/gulp/tasks/bundle/rollup-config.ts | 1 + .../components/cdk/adapter/adapter.module.ts | 7 ++-- .../adapter/block-scroll-strategy-adapter.ts | 39 +++++++++++++++++-- .../components/dialog/dialog.service.spec.ts | 9 ++++- .../layout/_layout.component.theme.scss | 4 ++ .../components/layout/layout.component.ts | 10 +++++ .../theme/services/scroll.service.ts | 9 +++++ 7 files changed, 71 insertions(+), 8 deletions(-) diff --git a/scripts/gulp/tasks/bundle/rollup-config.ts b/scripts/gulp/tasks/bundle/rollup-config.ts index ec05a8f109..87476ca879 100644 --- a/scripts/gulp/tasks/bundle/rollup-config.ts +++ b/scripts/gulp/tasks/bundle/rollup-config.ts @@ -22,6 +22,7 @@ const ROLLUP_GLOBALS = { '@angular/cdk/portal': 'ng.cdk.portal', '@angular/cdk/a11y': 'ng.cdk.a11y', '@angular/cdk/bidi': 'ng.cdk.bidi', + '@angular/cdk/scrolling': 'ng.cdk.scrolling', // RxJS dependencies diff --git a/src/framework/theme/components/cdk/adapter/adapter.module.ts b/src/framework/theme/components/cdk/adapter/adapter.module.ts index 9a512ed02b..ea4b808824 100644 --- a/src/framework/theme/components/cdk/adapter/adapter.module.ts +++ b/src/framework/theme/components/cdk/adapter/adapter.module.ts @@ -1,16 +1,16 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; -import { OverlayContainer, ScrollDispatcher } from '@angular/cdk/overlay'; +import { OverlayContainer, ScrollDispatcher, ScrollStrategyOptions } from '@angular/cdk/overlay'; import { NbOverlayContainerAdapter } from './overlay-container-adapter'; import { NbScrollDispatcherAdapter } from './scroll-dispatcher-adapter'; import { NbViewportRulerAdapter } from './viewport-ruler-adapter'; -import { NbBlockScrollStrategyAdapter } from './block-scroll-strategy-adapter'; +import { NbBlockScrollStrategyAdapter, NbScrollStrategyOptions } from './block-scroll-strategy-adapter'; @NgModule({}) export class NbCdkAdapterModule { static forRoot(): ModuleWithProviders { - return { + return { ngModule: NbCdkAdapterModule, providers: [ NbViewportRulerAdapter, @@ -18,6 +18,7 @@ export class NbCdkAdapterModule { NbBlockScrollStrategyAdapter, { provide: OverlayContainer, useExisting: NbOverlayContainerAdapter }, { provide: ScrollDispatcher, useClass: NbScrollDispatcherAdapter }, + { provide: ScrollStrategyOptions, useClass: NbScrollStrategyOptions }, ], }; } diff --git a/src/framework/theme/components/cdk/adapter/block-scroll-strategy-adapter.ts b/src/framework/theme/components/cdk/adapter/block-scroll-strategy-adapter.ts index 185a2dfed8..7786990832 100644 --- a/src/framework/theme/components/cdk/adapter/block-scroll-strategy-adapter.ts +++ b/src/framework/theme/components/cdk/adapter/block-scroll-strategy-adapter.ts @@ -1,11 +1,42 @@ -import { Injectable, Inject } from '@angular/core'; -import { BlockScrollStrategy } from '@angular/cdk/overlay'; +import { Inject, Injectable, NgZone } from '@angular/core'; +import { BlockScrollStrategy, ScrollDispatcher, ScrollStrategyOptions } from '@angular/cdk/overlay'; + +import { NbLayoutScrollService } from '../../../services/scroll.service'; import { NB_DOCUMENT } from '../../../theme.options'; import { NbViewportRulerAdapter } from './viewport-ruler-adapter'; + +/** + * Overrides default block scroll strategy because default strategy blocks scrolling on the body only. + * But Nebular has its own scrollable container - nb-layout. So, we need to block scrolling in it to. + * */ @Injectable() export class NbBlockScrollStrategyAdapter extends BlockScrollStrategy { - constructor(ruler: NbViewportRulerAdapter, @Inject(NB_DOCUMENT) document) { - super(ruler, document); + constructor(@Inject(NB_DOCUMENT) document: any, + viewportRuler: NbViewportRulerAdapter, + protected scrollService: NbLayoutScrollService) { + super(viewportRuler, document); + } + + enable() { + super.enable(); + this.scrollService.scrollable(false); + } + + disable() { + super.disable(); + this.scrollService.scrollable(true); } } + +export class NbScrollStrategyOptions extends ScrollStrategyOptions { + constructor(protected scrollService: NbLayoutScrollService, + protected scrollDispatcher: ScrollDispatcher, + protected viewportRuler: NbViewportRulerAdapter, + protected ngZone: NgZone, + @Inject(NB_DOCUMENT) protected document) { + super(scrollDispatcher, viewportRuler, ngZone, document); + } + + block = () => new NbBlockScrollStrategyAdapter(this.document, this.viewportRuler, this.scrollService); +} diff --git a/src/framework/theme/components/dialog/dialog.service.spec.ts b/src/framework/theme/components/dialog/dialog.service.spec.ts index b5b520e738..0e362904e0 100644 --- a/src/framework/theme/components/dialog/dialog.service.spec.ts +++ b/src/framework/theme/components/dialog/dialog.service.spec.ts @@ -1,13 +1,19 @@ import { Component, NgModule } from '@angular/core'; import { TestBed } from '@angular/core/testing'; -import { NbOverlayContainerAdapter, NbOverlayService } from '../cdk'; +import { NbOverlayContainerAdapter, NbOverlayService, NbViewportRulerAdapter } from '../cdk'; import { NbDialogService } from './dialog.service'; import { NbDialogModule } from './dialog.module'; import { NbThemeModule } from '../../theme.module'; import { NB_DOCUMENT } from '../../theme.options'; +export class NbViewportRulerMockAdapter extends NbViewportRulerAdapter { + getViewportSize(): Readonly<{ width: number; height: number; }> { + return { width: 1600, height: 900 }; + } +} + @Component({ selector: 'nb-test-dialog', template: '' }) class NbTestDialogComponent { } @@ -36,6 +42,7 @@ describe('dialog-service', () => { NbThemeModule.forRoot(), NbDialogModule.forRoot(), ], + providers: [{ provide: NbViewportRulerAdapter, useClass: NbViewportRulerMockAdapter }], }); dialog = TestBed.get(NbDialogService); diff --git a/src/framework/theme/components/layout/_layout.component.theme.scss b/src/framework/theme/components/layout/_layout.component.theme.scss index 3e6e42bb85..89513f36c3 100644 --- a/src/framework/theme/components/layout/_layout.component.theme.scss +++ b/src/framework/theme/components/layout/_layout.component.theme.scss @@ -48,6 +48,10 @@ } } + nb-layout.overlay-scroll-block .scrollable-container { + overflow: hidden; + } + .layout { // TODO: check this prop name min-width: nb-theme(layout-window-mode-min-width); diff --git a/src/framework/theme/components/layout/layout.component.ts b/src/framework/theme/components/layout/layout.component.ts index 1a0bd78d12..d99cf8d3b9 100644 --- a/src/framework/theme/components/layout/layout.component.ts +++ b/src/framework/theme/components/layout/layout.component.ts @@ -297,6 +297,7 @@ export class NbLayoutComponent implements AfterViewInit, OnDestroy { @HostBinding('class.window-mode') windowModeValue: boolean = false; @HostBinding('class.with-scroll') withScrollValue: boolean = false; @HostBinding('class.with-subheader') withSubheader: boolean = false; + @HostBinding('class.overlay-scroll-block') overlayScrollBlock: boolean = false; /** * Defines whether the layout columns will be centered after some width @@ -436,6 +437,15 @@ export class NbLayoutComponent implements AfterViewInit, OnDestroy { this.scroll(0, 0); }); + this.scrollService + .onScrollableChange() + .pipe( + filter(() => this.withScrollValue), + ) + .subscribe((scrollable: boolean) => { + this.overlayScrollBlock = !scrollable; + }); + if (isPlatformBrowser(this.platformId)) { // trigger first time so that after the change we have the initial value this.themeService.changeWindowWidth(this.window.innerWidth); diff --git a/src/framework/theme/services/scroll.service.ts b/src/framework/theme/services/scroll.service.ts index 6a5ecab077..b4e4ffbf20 100644 --- a/src/framework/theme/services/scroll.service.ts +++ b/src/framework/theme/services/scroll.service.ts @@ -35,6 +35,7 @@ export class NbLayoutScrollService { private scrollPositionReq$ = new Subject(); private manualScroll$ = new Subject(); private scroll$ = new Subject(); + private scrollable$ = new Subject(); /** * Returns scroll position @@ -86,6 +87,10 @@ export class NbLayoutScrollService { return this.scrollPositionReq$; } + onScrollableChange(): Observable { + return this.scrollable$.pipe(share()); + } + /** * @private * @param {any} event @@ -93,4 +98,8 @@ export class NbLayoutScrollService { fireScrollChange(event: any) { this.scroll$.next(event); } + + scrollable(scrollable: boolean) { + this.scrollable$.next(scrollable); + } }