diff --git a/components/modal/nz-modal.component.ts b/components/modal/nz-modal.component.ts index 0c5a64bd39f..16792830a0c 100644 --- a/components/modal/nz-modal.component.ts +++ b/components/modal/nz-modal.component.ts @@ -1,3 +1,4 @@ +import { FocusTrap, FocusTrapFactory } from '@angular/cdk/a11y'; import { Overlay, OverlayRef } from '@angular/cdk/overlay'; import { DOCUMENT } from '@angular/common'; import { @@ -48,6 +49,8 @@ type AnimationState = 'enter' | 'leave' | null; // tslint:disable-next-line:no-any export class NzModalComponent extends NzModalRef implements OnInit, OnChanges, AfterViewInit, OnDestroy, ModalOptions { private unsubscribe$ = new Subject(); + private previouslyFocusedElement: HTMLElement; + private focusTrap: FocusTrap; // tslint:disable-next-line:no-any locale: any = {}; @@ -125,6 +128,7 @@ export class NzModalComponent extends NzModalRef impleme private viewContainer: ViewContainerRef, private nzMeasureScrollbarService: NzMeasureScrollbarService, private modalControl: NzModalControlService, + private focusTrapFactory: FocusTrapFactory, @Inject(NZ_MODAL_CONFIG) private config: NzModalConfig, @Inject(DOCUMENT) private document: any) { // tslint:disable-line:no-any @@ -289,6 +293,8 @@ export class NzModalComponent extends NzModalRef impleme private handleVisibleStateChange(visible: boolean, animation: boolean = true, closeResult?: R): Promise { if (visible) { // Hide scrollbar at the first time when shown up this.changeBodyOverflow(1); + this.savePreviouslyFocusedElement(); + this.trapFocus(); } return Promise @@ -298,6 +304,7 @@ export class NzModalComponent extends NzModalRef impleme this.nzAfterOpen.emit(); } else { this.nzAfterClose.emit(closeResult); + this.restoreFocus(); this.changeBodyOverflow(); // Show/hide scrollbar when animation is over } }); @@ -443,6 +450,29 @@ export class NzModalComponent extends NzModalRef impleme private mergeDefaultConfig(config: NzModalConfig): NzModalConfig { return { ...NZ_MODAL_DEFAULT_CONFIG, ...config }; } + + private savePreviouslyFocusedElement(): void { + if (this.document) { + this.previouslyFocusedElement = this.document.activeElement as HTMLElement; + this.previouslyFocusedElement.blur(); + } + } + + private trapFocus(): void { + if (!this.focusTrap) { + this.focusTrap = this.focusTrapFactory.create(this.elementRef.nativeElement); + } + this.focusTrap.focusInitialElementWhenReady(); + } + + private restoreFocus(): void { + if (this.previouslyFocusedElement) { + this.previouslyFocusedElement.focus(); + } + if (this.focusTrap) { + this.focusTrap.destroy(); + } + } } ////////////