-
Notifications
You must be signed in to change notification settings - Fork 163
fix(left-nav): fix focus trapping #11842
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
Changes from 2 commits
887f078
a840177
f295746
bf99f81
a8a09d9
28464bb
3f7ec94
e54bfca
ab93cca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,17 +71,6 @@ class CDSSideNav extends HostListenerMixin(LitElement) { | |
| // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to | ||
| private _handleButtonToggle = async (event: CustomEvent) => { | ||
| this.expanded = event.detail.active; | ||
| if (this.expanded) { | ||
| await this._updateAndTransitionPromise; | ||
| // Checks if the side nav is not collapsed during the animation | ||
| if (this.expanded) { | ||
| ( | ||
| this.querySelector( | ||
| (this.constructor as typeof CDSSideNav).selectorNavItems | ||
| ) as HTMLElement | ||
| )?.focus(); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
|
|
@@ -179,6 +168,11 @@ class CDSSideNav extends HostListenerMixin(LitElement) { | |
| forEach(headerItems, (item) => { | ||
| item.setAttribute('tabindex', '-1'); | ||
| }); | ||
| ( | ||
| this.querySelector( | ||
| (this.constructor as typeof CDSSideNav).selectorNavItems | ||
| ) as HTMLElement | ||
| )?.focus(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moving the logic out of the event listener and into the update lifecycle ensures we focus after the seletorNavItems are added to the DOM. |
||
| } else { | ||
| forEach(headerItems, (item) => { | ||
| item.removeAttribute('tabindex'); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,11 +62,11 @@ class C4DLeftNav extends StableSelectorMixin(CDSSideNav) { | |
| private _importedSideNav = false; | ||
|
|
||
| /** | ||
| * Handles `c4d-request-focus-wrap` event on the document. | ||
| * Handles `cds-request-focus-wrap` event on the document dispatched from focuswrap. | ||
| * | ||
| * @param event The event. | ||
| */ | ||
| @HostListener('document:c4d-request-focus-wrap') | ||
| @HostListener('document:cds-request-focus-wrap') | ||
| // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to | ||
| private _handleRequestMenuButtonFocusWrap = (event: CustomEvent) => { | ||
| const { selectorButtonToggle } = this.constructor as typeof C4DLeftNav; | ||
|
|
@@ -221,7 +221,21 @@ class C4DLeftNav extends StableSelectorMixin(CDSSideNav) { | |
| document.addEventListener('click', this._handleClickOut.bind(this)); | ||
| } | ||
|
|
||
| updated(changedProperties) { | ||
| protected async willUpdate(changedProperties) { | ||
| if (changedProperties.has('expanded') && !this._importedSideNav) { | ||
| await Promise.all([ | ||
| import('./left-nav-name'), | ||
| import('./left-nav-menu'), | ||
| import('./left-nav-menu-section'), | ||
| import('./left-nav-menu-item'), | ||
| import('./left-nav-menu-category-heading'), | ||
| import('./left-nav-overlay') | ||
| ]); | ||
|
||
| this._importedSideNav = true; | ||
| } | ||
| } | ||
|
|
||
| async updated(changedProperties) { | ||
| super.updated(changedProperties); | ||
| const { usageMode } = this; | ||
| if ( | ||
|
|
@@ -256,15 +270,6 @@ class C4DLeftNav extends StableSelectorMixin(CDSSideNav) { | |
| ${c4dPrefix}-masthead-composite` | ||
| ) | ||
| ?.querySelector(`${c4dPrefix}-masthead`); | ||
| if (expanded && !this._importedSideNav) { | ||
| import('./left-nav-name'); | ||
| import('./left-nav-menu'); | ||
| import('./left-nav-menu-section'); | ||
| import('./left-nav-menu-item'); | ||
| import('./left-nav-menu-category-heading'); | ||
| import('./left-nav-overlay'); | ||
| this._importedSideNav = true; | ||
| } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if (expanded && masthead) { | ||
| this._hFocusWrap = focuswrap(this.shadowRoot!, [ | ||
| startSentinelNode, | ||
|
|
@@ -312,7 +317,7 @@ class C4DLeftNav extends StableSelectorMixin(CDSSideNav) { | |
| } | ||
| } | ||
|
|
||
| private _renderSentinel = (side: String) => { | ||
| private _renderSentinel = (side: string) => { | ||
| return html` | ||
| <button | ||
| id="${side}-sentinel" | ||
|
|
||
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.
While we change the value of
this.expandedhere, we then immediately wait for the resolution ofthis.updatefrom the component's update/render cycle.this.updateis already resolved from the last run of the component lifecycle and our current function hasn't been off the main thread to let the component start a new update.Since we're awaiting a resolved promise, we immediate move on to try to focus on elements that are not yet in the DOM.