-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/overlay #679
Feature/overlay #679
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { NgModule } from '@angular/core'; | ||
import { OverlayContainer, ScrollDispatcher } from '@angular/cdk/overlay'; | ||
|
||
import { NbOverlayContainerAdapter } from './overlay-container-adapter'; | ||
import { NbScrollDispatcherAdapter } from './scroll-dispatcher-adapter'; | ||
import { NbViewportRulerAdapter } from './viewport-ruler-adapter'; | ||
|
||
|
||
@NgModule({ | ||
providers: [ | ||
NbViewportRulerAdapter, | ||
{ provide: OverlayContainer, useClass: NbOverlayContainerAdapter }, | ||
{ provide: ScrollDispatcher, useClass: NbScrollDispatcherAdapter }, | ||
], | ||
}) | ||
export class NbAdapterModule { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Injectable } from '@angular/core'; | ||
|
||
import { NbOverlayContainer } from '../overlay/mapping'; | ||
|
||
|
||
@Injectable() | ||
export class NbOverlayContainerAdapter extends NbOverlayContainer { | ||
protected _createContainer(): void { | ||
Tibing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const container = this._document.createElement('div'); | ||
Tibing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
container.classList.add('cdk-overlay-container'); | ||
this._document.querySelector('nb-layout').appendChild(container); | ||
Tibing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this._containerElement = container; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Injectable, NgZone } from '@angular/core'; | ||
import { CdkScrollable, ScrollDispatcher } from '@angular/cdk/overlay'; | ||
import { Observable } from 'rxjs'; | ||
|
||
import { NbPlatform } from '../overlay/mapping'; | ||
import { NbLayoutScrollService } from '../../../services/scroll.service'; | ||
|
||
@Injectable() | ||
export class NbScrollDispatcherAdapter extends ScrollDispatcher { | ||
constructor(_ngZone: NgZone, _platform: NbPlatform, protected scrollService: NbLayoutScrollService) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why |
||
super(_ngZone, _platform); | ||
} | ||
|
||
scrolled(auditTimeInMs?: number): Observable<CdkScrollable | void> { | ||
return this.scrollService.onScroll(); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Injectable, NgZone } from '@angular/core'; | ||
import { ViewportRuler } from '@angular/cdk/overlay'; | ||
import { map } from 'rxjs/operators'; | ||
|
||
import { NbPlatform } from '../overlay/mapping'; | ||
import { NbLayoutRulerService } from '../../../services/ruler.service'; | ||
import { NbLayoutScrollService, NbScrollPosition } from '../../../services/scroll.service'; | ||
|
||
|
||
@Injectable() | ||
export class NbViewportRulerAdapter extends ViewportRuler { | ||
constructor(_platform: NbPlatform, ngZone: NgZone, | ||
protected ruler: NbLayoutRulerService, | ||
protected scroll: NbLayoutScrollService) { | ||
super(_platform, ngZone); | ||
} | ||
|
||
getViewportSize(): Readonly<{ width: number; height: number; }> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's add a comment why this is a synchronous operation |
||
let res; | ||
this.ruler.getDimensions() | ||
.pipe(map(dimensions => ({ width: dimensions.clientWidth, height: dimensions.clientHeight }))) | ||
.subscribe(rect => res = rect); | ||
return res; | ||
} | ||
|
||
getViewportScrollPosition(): { left: number; top: number } { | ||
let res; | ||
this.scroll.getPosition() | ||
.pipe(map((position: NbScrollPosition) => ({ top: position.y, left: position.x }))) | ||
.subscribe(position => res = position); | ||
return res; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './overlay/mapping'; | ||
export * from './overlay'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
@mixin nb-overlay-theme { | ||
.overlay-backdrop { | ||
background: rgba(0, 0, 0, 0.288); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this looks like a |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export * from './overlay.module'; | ||
export * from './overlay'; | ||
export * from './overlay-position'; | ||
export * from './overlay-container'; | ||
export * from './overlay-trigger'; | ||
export * from './mapping'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { Directive, Injectable, NgModule, TemplateRef, ViewContainerRef } from '@angular/core'; | ||
import { CdkPortal, ComponentPortal, Portal, PortalModule, TemplatePortal } from '@angular/cdk/portal'; | ||
import { | ||
ComponentType, | ||
ConnectedOverlayPositionChange, | ||
ConnectedPosition, | ||
ConnectionPositionPair, | ||
FlexibleConnectedPositionStrategy, | ||
GlobalPositionStrategy, | ||
Overlay, | ||
OverlayContainer, | ||
OverlayModule, | ||
OverlayPositionBuilder, | ||
OverlayRef, | ||
PositionStrategy, | ||
} from '@angular/cdk/overlay'; | ||
import { Platform } from '@angular/cdk/platform'; | ||
|
||
|
||
@Directive({ selector: '[nbPortal]' }) | ||
export class NbPortalDirective extends CdkPortal { | ||
} | ||
|
||
@Injectable() | ||
export class NbOverlayService extends Overlay { | ||
} | ||
|
||
@Injectable() | ||
export class NbPlatform extends Platform { | ||
} | ||
|
||
@Injectable() | ||
export class NbOverlayPositionBuilder extends OverlayPositionBuilder { | ||
} | ||
|
||
export class NbComponentPortal<T = any> extends ComponentPortal<T> { | ||
} | ||
|
||
export class NbTemplatePortal<T = any> extends TemplatePortal<T> { | ||
constructor(template: TemplateRef<T>, viewContainerRef?: ViewContainerRef, context?: T) { | ||
super(template, viewContainerRef, context); | ||
} | ||
} | ||
|
||
export class NbOverlayContainer extends OverlayContainer { | ||
} | ||
|
||
export class NbFlexibleConnectedPositionStrategy extends FlexibleConnectedPositionStrategy { | ||
} | ||
|
||
export type NbPortal<T = any> = Portal<T>; | ||
export type NbOverlayRef = OverlayRef; | ||
export type NbComponentType<T = any> = ComponentType<T>; | ||
export type NbGlobalPositionStrategy = GlobalPositionStrategy; | ||
export type NbPositionStrategy = PositionStrategy; | ||
export type NbConnectedPosition = ConnectedPosition; | ||
export type NbConnectedOverlayPositionChange = ConnectedOverlayPositionChange; | ||
export type NbConnectionPositionPair = ConnectionPositionPair; | ||
|
||
const CDK_MODULES = [OverlayModule, PortalModule]; | ||
|
||
const CDK_PROVIDERS = [ | ||
NbOverlayService, | ||
NbPlatform, | ||
NbOverlayPositionBuilder, | ||
]; | ||
|
||
/** | ||
* This module helps us to keep all angular/cdk deps inside our cdk module via providing aliases. | ||
* Approach will help us move cdk in separate npm package and refactor nebular/theme code. | ||
* */ | ||
@NgModule({ | ||
imports: [...CDK_MODULES], | ||
exports: [ | ||
...CDK_MODULES, | ||
NbPortalDirective, | ||
], | ||
declarations: [NbPortalDirective], | ||
providers: [...CDK_PROVIDERS], | ||
}) | ||
export class NbCdkMappingModule { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { ChangeDetectorRef, Component, HostBinding, Input, TemplateRef, Type, ViewChild } from '@angular/core'; | ||
import { NgComponentOutlet } from '@angular/common'; | ||
|
||
import { NbPosition } from './overlay-position'; | ||
|
||
export abstract class NbPositionedContainer { | ||
@Input() position: NbPosition; | ||
|
||
@HostBinding('class.top') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we make this class more specific? That would be safer |
||
get top(): boolean { | ||
return this.position === NbPosition.TOP | ||
} | ||
|
||
@HostBinding('class.right') | ||
get right(): boolean { | ||
return this.position === NbPosition.RIGHT | ||
} | ||
|
||
@HostBinding('class.bottom') | ||
get bottom(): boolean { | ||
return this.position === NbPosition.BOTTOM | ||
} | ||
|
||
@HostBinding('class.left') | ||
get left(): boolean { | ||
return this.position === NbPosition.LEFT | ||
} | ||
} | ||
|
||
@Component({ | ||
selector: 'nb-overlay-container', | ||
template: ` | ||
<ng-container *ngIf="isTemplate"> | ||
<ng-container *ngTemplateOutlet="content; context: context"></ng-container> | ||
</ng-container> | ||
<ng-container *ngIf="isComponent" [ngComponentOutlet]="content"></ng-container> | ||
<ng-container *ngIf="isPrimitive"> | ||
<div class="primitive-overlay">{{content}}</div> | ||
</ng-container> | ||
`, | ||
}) | ||
export class NbOverlayContainerComponent { | ||
@Input() | ||
content: any; | ||
|
||
@Input() | ||
context: Object; | ||
|
||
constructor(private cd: ChangeDetectorRef) { | ||
} | ||
|
||
@ViewChild(NgComponentOutlet) | ||
set componentOutlet(el) { | ||
if (this.isComponent) { | ||
Object.assign(el._componentRef.instance, this.context); | ||
/** | ||
* Change detection have to performed here, because another way applied context | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. have -> has to be |
||
* will be rendered on the next change detection loop and | ||
* we'll have incorrect positioning. Because rendered component may change its size | ||
* based on the context. | ||
* */ | ||
this.cd.detectChanges(); | ||
} | ||
} | ||
|
||
/** | ||
* Check that content is a TemplateRef. | ||
* | ||
* @return boolean | ||
* */ | ||
get isTemplate(): boolean { | ||
return this.content instanceof TemplateRef; | ||
} | ||
|
||
/** | ||
* Check that content is an angular component. | ||
* | ||
* @return boolean | ||
* */ | ||
get isComponent(): boolean { | ||
return this.content instanceof Type; | ||
} | ||
|
||
/** | ||
* Check that if content is not a TemplateRef or an angular component it means a primitive. | ||
* */ | ||
get isPrimitive(): boolean { | ||
return !this.isTemplate && !this.isComponent; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NbCdkAdapter maybe? As
NbAdapterModule
is too abstract to me