From 2928f8409bec7b3056dca5a6f70a164e2ac3b9c3 Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Wed, 5 Jun 2019 19:19:57 +0800 Subject: [PATCH] feat(module:drawer): support pressing ESC to close drawer (#3488) --- components/drawer/nz-drawer.component.ts | 29 ++++++++++++++++-------- components/drawer/nz-drawer.spec.ts | 11 +++++++++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/components/drawer/nz-drawer.component.ts b/components/drawer/nz-drawer.component.ts index c42ca15c4cd..f419370ed35 100644 --- a/components/drawer/nz-drawer.component.ts +++ b/components/drawer/nz-drawer.component.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ +import { ESCAPE } from '@angular/cdk/keycodes'; import { DOCUMENT } from '@angular/common'; import { AfterViewInit, @@ -30,12 +31,13 @@ import { } from '@angular/core'; import { FocusTrap, FocusTrapFactory } from '@angular/cdk/a11y'; -import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; +import { Overlay, OverlayConfig, OverlayKeyboardDispatcher, OverlayRef } from '@angular/cdk/overlay'; import { CdkPortalOutlet, ComponentPortal, PortalInjector, TemplatePortal } from '@angular/cdk/portal'; import { Observable, Subject } from 'rxjs'; import { toCssPixel, InputBoolean } from 'ng-zorro-antd/core'; +import { takeUntil } from 'rxjs/operators'; import { NzDrawerOptionsOfComponent, NzDrawerPlacement } from './nz-drawer-options'; import { NzDrawerRef } from './nz-drawer-ref'; @@ -83,6 +85,7 @@ export class NzDrawerComponent extends NzDrawerRef @ViewChild('contentTemplate') contentTemplate: TemplateRef<{}>; @ViewChild(CdkPortalOutlet) bodyPortalOutlet: CdkPortalOutlet; + destroy$ = new Subject(); previouslyFocusedElement: HTMLElement; nzContentParams: D; // only service overlayRef: OverlayRef | null; @@ -162,7 +165,8 @@ export class NzDrawerComponent extends NzDrawerRef private injector: Injector, private changeDetectorRef: ChangeDetectorRef, private focusTrapFactory: FocusTrapFactory, - private viewContainerRef: ViewContainerRef + private viewContainerRef: ViewContainerRef, + private overlayKeyboardDispatcher: OverlayKeyboardDispatcher ) { super(); } @@ -185,21 +189,17 @@ export class NzDrawerComponent extends NzDrawerRef ngOnChanges(changes: SimpleChanges): void { if (changes.hasOwnProperty('nzVisible')) { const value = changes.nzVisible.currentValue; - this.updateOverlayStyle(); if (value) { - this.updateBodyOverflow(); - this.savePreviouslyFocusedElement(); - this.trapFocus(); + this.open(); } else { - setTimeout(() => { - this.updateBodyOverflow(); - this.restoreFocus(); - }, this.getAnimationDuration()); + this.close(); } } } ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); this.disposeOverlay(); } @@ -210,6 +210,7 @@ export class NzDrawerComponent extends NzDrawerRef close(result?: R): void { this.isOpen = false; this.updateOverlayStyle(); + this.overlayKeyboardDispatcher.remove(this.overlayRef!); this.changeDetectorRef.detectChanges(); setTimeout(() => { this.updateBodyOverflow(); @@ -221,6 +222,7 @@ export class NzDrawerComponent extends NzDrawerRef open(): void { this.isOpen = true; + this.overlayKeyboardDispatcher.add(this.overlayRef!); this.updateOverlayStyle(); this.updateBodyOverflow(); this.savePreviouslyFocusedElement(); @@ -261,6 +263,13 @@ export class NzDrawerComponent extends NzDrawerRef if (this.overlayRef && !this.overlayRef.hasAttached()) { this.overlayRef.attach(this.portal); + this.overlayRef!.keydownEvents() + .pipe(takeUntil(this.destroy$)) + .subscribe((event: KeyboardEvent) => { + if (event.keyCode === ESCAPE && this.isOpen) { + this.nzOnClose.emit(); + } + }); } } diff --git a/components/drawer/nz-drawer.spec.ts b/components/drawer/nz-drawer.spec.ts index 6a757f4b640..dfc62d13d00 100644 --- a/components/drawer/nz-drawer.spec.ts +++ b/components/drawer/nz-drawer.spec.ts @@ -1,3 +1,4 @@ +import { ESCAPE } from '@angular/cdk/keycodes'; import { Component, Input, TemplateRef, ViewChild } from '@angular/core'; import { async, fakeAsync, inject, tick, ComponentFixture, TestBed } from '@angular/core/testing'; @@ -5,6 +6,7 @@ import { async, fakeAsync, inject, tick, ComponentFixture, TestBed } from '@angu import { OverlayContainer } from '@angular/cdk/overlay'; import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { dispatchKeyboardEvent } from 'ng-zorro-antd'; import { NzDrawerRef } from './nz-drawer-ref'; import { NzDrawerComponent } from './nz-drawer.component'; import { NzDrawerModule } from './nz-drawer.module'; @@ -109,6 +111,15 @@ describe('NzDrawerComponent', () => { expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true); }); + it('should be closed when ESC keydown', () => { + component.open(); + fixture.detectChanges(); + expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true); + dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); + fixture.detectChanges(); + expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(false); + }); + it('should close when click mask', () => { component.maskClosable = true; component.open();