diff --git a/src/app/components/api/overlayoptions.ts b/src/app/components/api/overlayoptions.ts index 06debfa3993..55291a15e0c 100644 --- a/src/app/components/api/overlayoptions.ts +++ b/src/app/components/api/overlayoptions.ts @@ -44,6 +44,7 @@ export interface OverlayOptions { baseZIndex?: number; showTransitionOptions?: string; hideTransitionOptions?: string; + hideOnEscape?: boolean; listener?: (event: Event, options?: OverlayListenerOptions) => boolean | void; responsive?: ResponsiveOverlayOptions | undefined; onBeforeShow?: (event?: OverlayOnBeforeShowEvent) => void; diff --git a/src/app/components/overlay/overlay.ts b/src/app/components/overlay/overlay.ts index 3789c336d93..e880d315796 100644 --- a/src/app/components/overlay/overlay.ts +++ b/src/app/components/overlay/overlay.ts @@ -3,7 +3,6 @@ import { CommonModule, DOCUMENT } from '@angular/common'; import { AfterContentInit, ChangeDetectionStrategy, - ChangeDetectorRef, Component, ContentChildren, ElementRef, @@ -12,6 +11,7 @@ import { Inject, Input, NgModule, + NgZone, OnDestroy, Output, QueryList, @@ -266,6 +266,8 @@ export class Overlay implements AfterContentInit, OnDestroy { documentResizeListener: any; + private documentKeyboardListener: VoidFunction | null; + private window: Window | null; protected transformOptions: any = { @@ -293,11 +295,11 @@ export class Overlay implements AfterContentInit, OnDestroy { return this.mode || (this.modal ? 'modal' : 'overlay'); } - get overlayOptions() { + get overlayOptions(): OverlayOptions { return { ...this.config?.overlayOptions, ...this.options }; // TODO: Improve performance } - get overlayResponsiveOptions() { + get overlayResponsiveOptions(): ResponsiveOverlayOptions { return { ...this.overlayOptions?.responsive, ...this.responsive }; // TODO: Improve performance } @@ -317,7 +319,7 @@ export class Overlay implements AfterContentInit, OnDestroy { return DomHandler.getTargetElement(this.target, this.el?.nativeElement); } - constructor(@Inject(DOCUMENT) private document: Document, public el: ElementRef, public renderer: Renderer2, private config: PrimeNGConfig, public overlayService: OverlayService, private cd: ChangeDetectorRef) { + constructor(@Inject(DOCUMENT) private document: Document, public el: ElementRef, public renderer: Renderer2, private config: PrimeNGConfig, public overlayService: OverlayService, private zone: NgZone) { this.window = this.document.defaultView; } @@ -435,12 +437,14 @@ export class Overlay implements AfterContentInit, OnDestroy { this.bindScrollListener(); this.bindDocumentClickListener(); this.bindDocumentResizeListener(); + this.bindDocumentKeyboardListener(); } unbindListeners() { this.unbindScrollListener(); this.unbindDocumentClickListener(); this.unbindDocumentResizeListener(); + this.unbindDocumentKeyboardListener(); } bindScrollListener() { @@ -483,7 +487,7 @@ export class Overlay implements AfterContentInit, OnDestroy { bindDocumentResizeListener() { if (!this.documentResizeListener) { - this.documentResizeListener = this.renderer.listen('window', 'resize', (event) => { + this.documentResizeListener = this.renderer.listen(this.window, 'resize', (event) => { const valid = this.listener ? this.listener(event, { type: 'resize', mode: this.overlayMode, valid: !DomHandler.isTouchDevice() }) : !DomHandler.isTouchDevice(); valid && this.hide(event, true); @@ -498,6 +502,35 @@ export class Overlay implements AfterContentInit, OnDestroy { } } + bindDocumentKeyboardListener(): void { + if (this.documentKeyboardListener) { + return; + } + + this.zone.runOutsideAngular(() => { + this.documentKeyboardListener = this.renderer.listen(this.window, 'keydown', (event) => { + if (!this.overlayOptions.hideOnEscape || event.keyCode !== 27) { + return; + } + + const valid = this.listener ? this.listener(event, { type: 'keydown', mode: this.overlayMode, valid: !DomHandler.isTouchDevice() }) : !DomHandler.isTouchDevice(); + + if (valid) { + this.zone.run(() => { + this.hide(event, true); + }); + } + }); + }); + } + + unbindDocumentKeyboardListener(): void { + if (this.documentKeyboardListener) { + this.documentKeyboardListener(); + this.documentKeyboardListener = null; + } + } + ngOnDestroy() { this.hide(this.overlayEl, true);