diff --git a/src/demo-app/sidenav/sidenav-demo.html b/src/demo-app/sidenav/sidenav-demo.html
index 31de4f40dd7f..728a85dacd48 100644
--- a/src/demo-app/sidenav/sidenav-demo.html
+++ b/src/demo-app/sidenav/sidenav-demo.html
@@ -9,9 +9,9 @@
[fixedInViewport]="fixed" [fixedTopGap]="fixedTop" [fixedBottomGap]="fixedBottom">
Start Side Sidenav
-
+
-
+
Mode: {{start.mode}}
@@ -24,7 +24,7 @@
[fixedInViewport]="fixed" [fixedTopGap]="fixedTop" [fixedBottomGap]="fixedBottom">
End Side Sidenav
-
+
Filler Content
@@ -39,8 +39,8 @@
Sidenav
-
-
+
+
Fixed mode
Sidenav covers header/footer
diff --git a/src/lib/button-toggle/button-toggle.scss b/src/lib/button-toggle/button-toggle.scss
index ea408e5505bb..89c58c628809 100644
--- a/src/lib/button-toggle/button-toggle.scss
+++ b/src/lib/button-toggle/button-toggle.scss
@@ -38,10 +38,13 @@ $mat-button-toggle-border-radius: 2px !default;
.mat-button-toggle {
white-space: nowrap;
position: relative;
-}
-.mat-button-toggle.cdk-keyboard-focused .mat-button-toggle-focus-overlay {
- opacity: 1;
+ &.cdk-keyboard-focused,
+ &.cdk-program-focused {
+ .mat-button-toggle-focus-overlay {
+ opacity: 1;
+ }
+ }
}
.mat-button-toggle-label-content {
diff --git a/src/lib/button/_button-base.scss b/src/lib/button/_button-base.scss
index 44b9e39e3aa8..e3606174d34b 100644
--- a/src/lib/button/_button-base.scss
+++ b/src/lib/button/_button-base.scss
@@ -51,7 +51,7 @@ $mat-mini-fab-padding: 8px !default;
cursor: default;
}
- &.cdk-keyboard-focused {
+ &.cdk-keyboard-focused, &.cdk-program-focused {
.mat-button-focus-overlay {
opacity: 1;
}
diff --git a/src/lib/datepicker/_datepicker-theme.scss b/src/lib/datepicker/_datepicker-theme.scss
index 729adf43fb17..f1a48d7bf71f 100644
--- a/src/lib/datepicker/_datepicker-theme.scss
+++ b/src/lib/datepicker/_datepicker-theme.scss
@@ -52,7 +52,8 @@ $mat-calendar-weekday-table-font-size: 11px !default;
}
:not(.mat-calendar-body-disabled):hover,
- .cdk-keyboard-focused .mat-calendar-body-active {
+ .cdk-keyboard-focused .mat-calendar-body-active,
+ .cdk-program-focused .mat-calendar-body-active {
& > .mat-calendar-body-cell-content:not(.mat-calendar-body-selected) {
background-color: mat-color($background, hover);
}
diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts
index 9fd9a2b449a7..830fb944b947 100644
--- a/src/lib/sidenav/drawer.ts
+++ b/src/lib/sidenav/drawer.ts
@@ -7,7 +7,7 @@
*/
import {animate, AnimationEvent, state, style, transition, trigger} from '@angular/animations';
-import {FocusTrap, FocusTrapFactory} from '@angular/cdk/a11y';
+import {FocusTrap, FocusTrapFactory, FocusMonitor, FocusOrigin} from '@angular/cdk/a11y';
import {Directionality} from '@angular/cdk/bidi';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {ESCAPE} from '@angular/cdk/keycodes';
@@ -172,6 +172,9 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
/** Whether the drawer is opened. */
private _opened: boolean = false;
+ /** How the sidenav was opened (keypress, mouse click etc.) */
+ private _openedVia: FocusOrigin | null;
+
/** Emits whenever the drawer has started animating. */
_animationStarted = new EventEmitter
();
@@ -230,6 +233,7 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
constructor(private _elementRef: ElementRef,
private _focusTrapFactory: FocusTrapFactory,
+ private _focusMonitor: FocusMonitor,
@Optional() @Inject(DOCUMENT) private _doc: any) {
this.openedChange.subscribe((opened: boolean) => {
if (opened) {
@@ -251,16 +255,18 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
* opened.
*/
private _restoreFocus() {
- let activeEl = this._doc && this._doc.activeElement;
+ const activeEl = this._doc && this._doc.activeElement;
+
if (activeEl && this._elementRef.nativeElement.contains(activeEl)) {
if (this._elementFocusedBeforeDrawerWasOpened instanceof HTMLElement) {
- this._elementFocusedBeforeDrawerWasOpened.focus();
+ this._focusMonitor.focusVia(this._elementFocusedBeforeDrawerWasOpened, this._openedVia);
} else {
this._elementRef.nativeElement.blur();
}
}
this._elementFocusedBeforeDrawerWasOpened = null;
+ this._openedVia = null;
}
ngAfterContentInit() {
@@ -285,10 +291,13 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
this.toggle(coerceBooleanProperty(v));
}
-
- /** Open the drawer. */
- open(): Promise {
- return this.toggle(true);
+ /**
+ * Open the drawer.
+ * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.
+ * Used for focus management after the sidenav is closed.
+ */
+ open(openedVia?: FocusOrigin): Promise {
+ return this.toggle(true, openedVia);
}
/** Close the drawer. */
@@ -299,12 +308,17 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
/**
* Toggle this drawer.
* @param isOpen Whether the drawer should be open.
+ * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.
+ * Used for focus management after the sidenav is closed.
*/
- toggle(isOpen: boolean = !this.opened): Promise {
+ toggle(isOpen: boolean = !this.opened, openedVia: FocusOrigin = 'program'):
+ Promise {
+
this._opened = isOpen;
if (isOpen) {
this._animationState = this._enableAnimations ? 'open' : 'open-instant';
+ this._openedVia = openedVia;
} else {
this._animationState = 'void';
}
diff --git a/src/lib/slider/slider.scss b/src/lib/slider/slider.scss
index f27f052bd1b2..edcf83304b87 100644
--- a/src/lib/slider/slider.scss
+++ b/src/lib/slider/slider.scss
@@ -93,7 +93,8 @@ $mat-slider-focus-ring-size: 30px !default;
background-color $swift-ease-out-duration $swift-ease-out-timing-function,
opacity $swift-ease-out-duration $swift-ease-out-timing-function;
- .cdk-keyboard-focused & {
+ .cdk-keyboard-focused &,
+ .cdk-program-focused & {
transform: scale(1);
opacity: 1;
}