-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
Focus capturing for sidenav. #1695
Conversation
this._elementFocusedBeforeDialogWasOpened = document.activeElement; | ||
this._focusTrap.focusFirstTabbableElement(); | ||
}); | ||
this._elementFocusedBeforeDialogWasOpened = document.activeElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think its worth moving this to the FocusTrap as well? Maybe like this: focusOnDeactivate=""
fixes #50 |
cc @crisbeto, relevant to dialog |
@marcysutton as far as you know, is there ever a time when you would want to trap focus within some subtree of the DOM and not automatically move focus into that subtree as soon as it's added to the page? |
@@ -1,4 +1,6 @@ | |||
import {Component, ViewEncapsulation, ViewChild, ElementRef} from '@angular/core'; | |||
import { | |||
Component, ViewEncapsulation, ViewChild, ElementRef, Input, AfterContentInit, NgZone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these are supposed to all be on separate lines.
set active(val: boolean) { | ||
this._active = val; | ||
if (val && this._contentReady) { | ||
this._ngZone.onMicrotaskEmpty.first().subscribe(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is used here and repeated down inside ngAfterContentInit
. It might a good idea to move it to a private method like waitForTabbableElement
.
@@ -45,6 +41,9 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { | |||
/** Reference to the open dialog. */ | |||
dialogRef: MdDialogRef<any>; | |||
|
|||
/** Whether the focus trap is active. */ | |||
focusTrapActive: boolean = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what the style guide says about this, but wouldn't the boolean
be inferred from the default value anyway @jelbourn?
@jelbourn focus traps are usually enabled/disabled on command when the UI requires it, such as a modal dialog being shown. Otherwise you run the risk of trapping a keyboard user inside a menu at the wrong time. You might want to check out HTML |
@marcysutton That sounds like what I'm doing here, I added an |
Changed to not automatically focus the first element when it's activated. |
private _contentReady: boolean = false; | ||
|
||
/** Whether the focus trap is active. */ | ||
private _active: boolean = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you feel about inverting this to disabled
(with coerceBooleanProperty
)? It might make more sense if active
is the default.
// Trigger setter behavior. | ||
if (this.active) { | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty if
?
@@ -106,6 +111,10 @@ export class MdSidenav implements AfterContentInit { | |||
/** Event emitted when the sidenav alignment changes. */ | |||
@Output('align-changed') onAlignChanged = new EventEmitter<void>(); | |||
|
|||
get focusTrapActive() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isFocusTrapActive
? (or isFocusTrapDisabled
is we invert it)
Add a comment like
// The focus trap is only enabled when the sidenav is open in any mode
// except for side.
link2Element.focus(); | ||
}); | ||
|
||
it('should trp focus when opened in "over" mode', fakeAsync(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trp
-> trap
expect(document.activeElement).toBe(link1Element); | ||
})); | ||
|
||
it('should trap tabs when opened in "push" mode', fakeAsync(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trap tabs?
sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance; | ||
link1Element = fixture.debugElement.query(By.css('.link1')).nativeElement; | ||
link2Element = fixture.debugElement.query(By.css('.link1')).nativeElement; | ||
link2Element.focus(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we call these something like firstFocusableElement
and lastFocusableElement
?
LGTM |
@mmalerba Presubmit is unhappy because
|
@kara fixed, strange that neither build nor lint caught that |
@mmalerba I think it needs to be internal instead of private. |
@mmalerba can you rebase? |
Captures focus when sidenav is open in "over" or "push" mode, but not when opened in "side" mode.
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Captures focus when sidenav is open in "over" or "push" mode, but not
when opened in "side" mode.