diff --git a/src/demo-app/button/button-demo.html b/src/demo-app/button/button-demo.html index 2b3400b15761..211d2c0c33b9 100644 --- a/src/demo-app/button/button-demo.html +++ b/src/demo-app/button/button-demo.html @@ -73,11 +73,12 @@ + - - off - + + off + diff --git a/src/demo-app/demo-app/demo-app.html b/src/demo-app/demo-app/demo-app.html index cb6e9d904537..ba6af65434be 100644 --- a/src/demo-app/demo-app/demo-app.html +++ b/src/demo-app/demo-app/demo-app.html @@ -24,7 +24,7 @@
-
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; }