Skip to content
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

fix(sidenav): unable to close by pressing escape in side mode #17967

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/material/sidenav/drawer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ describe('MatDrawer', () => {
expect(testComponent.closeCount).toBe(0, 'Expected no close events.');
expect(testComponent.closeStartCount).toBe(0, 'Expected no close start events.');

const event = dispatchKeyboardEvent(drawer.nativeElement, 'keydown', ESCAPE);
const event = dispatchKeyboardEvent(document, 'keydown', ESCAPE);
fixture.detectChanges();
flush();

Expand All @@ -230,7 +230,7 @@ describe('MatDrawer', () => {

const event = createKeyboardEvent('keydown', ESCAPE);
Object.defineProperty(event, 'altKey', {get: () => true});
dispatchEvent(drawer.nativeElement, event);
dispatchEvent(document, event);
fixture.detectChanges();
flush();

Expand Down Expand Up @@ -258,7 +258,7 @@ describe('MatDrawer', () => {
fixture.detectChanges();
tick();

dispatchKeyboardEvent(drawer.nativeElement, 'keydown', ESCAPE);
dispatchKeyboardEvent(document, 'keydown', ESCAPE);
fixture.detectChanges();
tick();

Expand Down
52 changes: 29 additions & 23 deletions src/material/sidenav/drawer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ import {fromEvent, merge, Observable, Subject} from 'rxjs';
import {
debounceTime,
filter,
map,
startWith,
take,
takeUntil,
distinctUntilChanged,
mapTo,
} from 'rxjs/operators';
import {matDrawerAnimations} from './drawer-animations';
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
Expand Down Expand Up @@ -213,30 +213,30 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
/** Event emitted when the drawer has been opened. */
@Output('opened')
get _openedStream(): Observable<void> {
return this.openedChange.pipe(filter(o => o), map(() => {}));
return this.openedChange.pipe(filter(o => o), mapTo(undefined));
}

/** Event emitted when the drawer has started opening. */
@Output()
get openedStart(): Observable<void> {
return this._animationStarted.pipe(
filter(e => e.fromState !== e.toState && e.toState.indexOf('open') === 0),
map(() => {})
mapTo(undefined)
);
}

/** Event emitted when the drawer has been closed. */
@Output('closed')
get _closedStream(): Observable<void> {
return this.openedChange.pipe(filter(o => !o), map(() => {}));
return this.openedChange.pipe(filter(o => !o), mapTo(undefined));
}

/** Event emitted when the drawer has started closing. */
@Output()
get closedStart(): Observable<void> {
return this._animationStarted.pipe(
filter(e => e.fromState !== e.toState && e.toState === 'void'),
map(() => {})
mapTo(undefined)
);
}

Expand Down Expand Up @@ -284,24 +284,6 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
}
});

/**
* Listen to `keydown` events outside the zone so that change detection is not run every
* time a key is pressed. Instead we re-enter the zone only if the `ESC` key is pressed
* and we don't have close disabled.
*/
this._ngZone.runOutsideAngular(() => {
(fromEvent(this._elementRef.nativeElement, 'keydown') as Observable<KeyboardEvent>).pipe(
filter(event => {
return event.keyCode === ESCAPE && !this.disableClose && !hasModifierKey(event);
}),
takeUntil(this._destroyed)
).subscribe(event => this._ngZone.run(() => {
this.close();
event.stopPropagation();
event.preventDefault();
}));
});

// We need a Subject with distinctUntilChanged, because the `done` event
// fires twice on some browsers. See https://github.com/angular/angular/issues/24084
this._animationEnd.pipe(distinctUntilChanged((x, y) => {
Expand Down Expand Up @@ -404,11 +386,16 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
toggle(isOpen: boolean = !this.opened, openedVia: FocusOrigin = 'program'):
Promise<MatDrawerToggleResult> {

if (isOpen === this._opened) {
return Promise.resolve(isOpen ? 'open' : 'close');
}

this._opened = isOpen;

if (isOpen) {
this._animationState = this._enableAnimations ? 'open' : 'open-instant';
this._openedVia = openedVia;
this._listenForEscapePresses();
} else {
this._animationState = 'void';
this._restoreFocus();
Expand Down Expand Up @@ -452,6 +439,25 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
this._animationEnd.next(event);
}

/** Binds the event listener that reacts to escape key presses. */
private _listenForEscapePresses(): void {
// Listen to `keydown` events outside the zone so that change detection is not run every
// time a key is pressed. Instead we re-enter the zone only if the `ESC` key is pressed
// and we don't have close disabled.
this._ngZone.runOutsideAngular(() => {
// Note that we need to listen at the document level, rather than the sidenav, because we
// don't always move focus into the sidenav (e.g. in `side` mode) which means that we won't
// be able to catch all of the events.
(fromEvent(this._doc, 'keydown') as Observable<KeyboardEvent>).pipe(
filter(event => event.keyCode === ESCAPE && !this.disableClose && !hasModifierKey(event)),
takeUntil(merge(this._destroyed, this._closedStream))
).subscribe(event => this._ngZone.run(() => {
this.close();
event.preventDefault();
}));
});
}

static ngAcceptInputType_disableClose: boolean | string | null | undefined;
static ngAcceptInputType_autoFocus: boolean | string | null | undefined;
static ngAcceptInputType_opened: boolean | string | null | undefined;
Expand Down