-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(theme): add new Dialog component (#688)
- Loading branch information
1 parent
d3ba6ab
commit 2edd9b3
Showing
27 changed files
with
1,252 additions
and
8 deletions.
There are no files selected for viewing
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { NgModule } from '@angular/core'; | ||
|
||
import { NbFocusTrapFactoryService } from './focus-trap'; | ||
|
||
|
||
@NgModule({ | ||
providers: [ | ||
NbFocusTrapFactoryService, | ||
], | ||
}) | ||
export class NbA11yModule { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { Inject, Injectable, NgZone } from '@angular/core'; | ||
import { FocusTrap, FocusTrapFactory, InteractivityChecker } from '@angular/cdk/a11y'; | ||
|
||
import { NB_DOCUMENT } from '../../../theme.options'; | ||
|
||
|
||
/** | ||
* Overrides angular cdk focus trap to keep restore functionality inside trap. | ||
* */ | ||
export class NbFocusTrap extends FocusTrap { | ||
protected previouslyFocusedElement: HTMLElement; | ||
|
||
constructor( | ||
protected element: HTMLElement, | ||
protected checker: InteractivityChecker, | ||
protected ngZone: NgZone, | ||
protected document: Document, | ||
deferAnchors) { | ||
super(element, checker, ngZone, document, deferAnchors); | ||
this.savePreviouslyFocusedElement(); | ||
} | ||
|
||
restoreFocus() { | ||
this.previouslyFocusedElement.focus(); | ||
this.destroy(); | ||
} | ||
|
||
blurPreviouslyFocusedElement() { | ||
this.previouslyFocusedElement.blur(); | ||
} | ||
|
||
protected savePreviouslyFocusedElement() { | ||
this.previouslyFocusedElement = this.document.activeElement as HTMLElement; | ||
} | ||
} | ||
|
||
@Injectable() | ||
export class NbFocusTrapFactoryService extends FocusTrapFactory { | ||
constructor( | ||
protected checker: InteractivityChecker, | ||
protected ngZone: NgZone, | ||
@Inject(NB_DOCUMENT) private document) { | ||
super(checker, ngZone, document); | ||
} | ||
|
||
create(element: HTMLElement, deferCaptureElements?: boolean): NbFocusTrap { | ||
return new NbFocusTrap(element, this.checker, this.ngZone, this.document, deferCaptureElements); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
export * from './overlay/mapping'; | ||
export * from './overlay'; | ||
export * from './a11y/a11y.module'; | ||
export * from './a11y/focus-trap'; | ||
export * from './adapter/overlay-container-adapter'; | ||
export * from './adapter/scroll-dispatcher-adapter'; | ||
export * from './adapter/viewport-ruler-adapter'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/** | ||
* @license | ||
* Copyright Akveo. All Rights Reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { InjectionToken, ViewContainerRef } from '@angular/core'; | ||
|
||
|
||
export const NB_DIALOG_CONFIG = new InjectionToken<NbDialogConfig>('Default dialog options'); | ||
|
||
/** | ||
* Describes all available options that may be passed to the NbDialogService. | ||
* */ | ||
export class NbDialogConfig<D = any> { | ||
/** | ||
* If true than overlay will render backdrop under a dialog. | ||
* */ | ||
hasBackdrop: boolean = true; | ||
|
||
/** | ||
* Class that'll be assigned to the backdrop element. | ||
* */ | ||
backdropClass: string = 'overlay-backdrop'; | ||
|
||
/** | ||
* If true then mouse clicks by backdrop will close a dialog. | ||
* */ | ||
closeOnBackdropClick: boolean = true; | ||
|
||
/** | ||
* If true then escape press will close a dialog. | ||
* */ | ||
closeOnEsc: boolean = true; | ||
|
||
/** | ||
* Disables scroll on content under dialog if true and does nothing otherwise. | ||
* */ | ||
hasScroll: boolean = false; | ||
|
||
/** | ||
* Focuses dialog automatically after open if true. | ||
* */ | ||
autoFocus: boolean = true; | ||
|
||
/** | ||
* Where the attached component should live in Angular's *logical* component tree. | ||
* This affects what is available for injection and the change detection order for the | ||
* component instantiated inside of the dialog. This does not affect where the dialog | ||
* content will be rendered. | ||
*/ | ||
viewContainerRef: ViewContainerRef; | ||
|
||
context: D; | ||
|
||
constructor(config: Partial<NbDialogConfig>) { | ||
Object.assign(this, config); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/** | ||
* @license | ||
* Copyright Akveo. All Rights Reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { Component, ComponentRef, ElementRef, EmbeddedViewRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; | ||
|
||
import { | ||
NbComponentPortal, | ||
NbFocusTrap, | ||
NbFocusTrapFactoryService, | ||
NbPortalOutletDirective, | ||
NbTemplatePortal, | ||
} from '../cdk'; | ||
import { NbDialogConfig } from './dialog-config'; | ||
|
||
|
||
/** | ||
* Container component for each dialog. | ||
* All the dialogs will be attached to it. | ||
* // TODO add animations | ||
* */ | ||
@Component({ | ||
selector: 'nb-dialog-container', | ||
template: '<ng-template nbPortalOutlet></ng-template>', | ||
}) | ||
export class NbDialogContainerComponent implements OnInit, OnDestroy { | ||
@ViewChild(NbPortalOutletDirective) portalOutlet: NbPortalOutletDirective; | ||
|
||
protected focusTrap: NbFocusTrap; | ||
|
||
constructor(protected config: NbDialogConfig, | ||
protected elementRef: ElementRef, | ||
protected focusTrapFactory: NbFocusTrapFactoryService) { | ||
} | ||
|
||
ngOnInit() { | ||
if (this.config.autoFocus) { | ||
this.focusTrap = this.focusTrapFactory.create(this.elementRef.nativeElement); | ||
this.focusTrap.blurPreviouslyFocusedElement(); | ||
this.focusTrap.focusInitialElement(); | ||
} | ||
} | ||
|
||
ngOnDestroy() { | ||
if (this.config.autoFocus && this.focusTrap) { | ||
this.focusTrap.restoreFocus(); | ||
} | ||
} | ||
|
||
attachComponentPortal<T>(portal: NbComponentPortal<T>): ComponentRef<T> { | ||
return this.portalOutlet.attachComponentPortal(portal); | ||
} | ||
|
||
attachTemplatePortal<C>(portal: NbTemplatePortal<C>): EmbeddedViewRef<C> { | ||
return this.portalOutlet.attachTemplatePortal(portal); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/** | ||
* @license | ||
* Copyright Akveo. All Rights Reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { ComponentRef } from '@angular/core'; | ||
import { Observable, Subject } from 'rxjs'; | ||
|
||
import { NbOverlayRef } from '../cdk'; | ||
|
||
|
||
/** | ||
* The `NbDialogRef` helps to manipulate dialog after it was created. | ||
* The dialog can be dismissed by using `close` method of the dialogRef. | ||
* You can access rendered component as `content` property of the dialogRef. | ||
* `onBackdropClick` streams click events on the backdrop of the dialog. | ||
* */ | ||
export class NbDialogRef<T> { | ||
|
||
componentRef: ComponentRef<T>; | ||
|
||
/** | ||
* Stream of backdrop click events. | ||
* */ | ||
readonly onBackdropClick: Observable<MouseEvent>; | ||
protected onClose$: Subject<any> = new Subject(); | ||
readonly onClose: Observable<any> = this.onClose$.asObservable(); | ||
|
||
constructor(protected overlayRef: NbOverlayRef) { | ||
this.onBackdropClick = this.overlayRef.backdropClick(); | ||
} | ||
|
||
/** | ||
* Hides dialog. | ||
* */ | ||
close(res?: any) { | ||
this.overlayRef.detach(); | ||
this.overlayRef.dispose(); | ||
this.onClose$.next(res); | ||
this.onClose$.complete(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/** | ||
* @license | ||
* Copyright Akveo. All Rights Reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { ModuleWithProviders, NgModule } from '@angular/core'; | ||
|
||
import { NbSharedModule } from '../shared/shared.module'; | ||
import { NbA11yModule, NbOverlayModule } from '../cdk'; | ||
import { NbDialogService } from './dialog.service'; | ||
import { NbDialogContainerComponent } from './dialog-container'; | ||
import { NB_DIALOG_CONFIG, NbDialogConfig } from './dialog-config'; | ||
|
||
|
||
@NgModule({ | ||
imports: [NbSharedModule, NbA11yModule, NbOverlayModule], | ||
declarations: [NbDialogContainerComponent], | ||
entryComponents: [NbDialogContainerComponent], | ||
}) | ||
export class NbDialogModule { | ||
static forRoot(dialogConfig: Partial<NbDialogConfig> = {}): ModuleWithProviders { | ||
return { | ||
ngModule: NbDialogModule, | ||
providers: [ | ||
NbDialogService, | ||
{ provide: NB_DIALOG_CONFIG, useValue: dialogConfig }, | ||
], | ||
} | ||
} | ||
} |
Oops, something went wrong.