From 82759fb8e55715fe795747f0313d88d1c5316a26 Mon Sep 17 00:00:00 2001 From: Mnickii Date: Thu, 27 Jul 2023 13:43:19 +0000 Subject: [PATCH 1/8] hide flyout when last focusable element is tabbed through --- .../src/components/mgt-login/mgt-login.ts | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts index 51881e1ced..f8dd858fbb 100644 --- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts +++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts @@ -351,14 +351,43 @@ export class MgtLogin extends MgtTemplatedComponent { light-dismiss @opened=${this.flyoutOpened} @closed=${this.flyoutClosed}> -
- - ${this.renderFlyoutContent()} - -
+ + ${this.renderFlyoutContent()} + `; } + /** + * Tracks tabbing through the flyout (keydown) + */ + private readonly onUserKeyDown = (): void => { + if (!this.flyout.isOpen) { + return; + } + + const el = this.renderRoot.querySelector('.popup-content'); + const focusableEls = el.querySelectorAll('li, fluent-button'); + const lastFocusableEl = focusableEls[focusableEls.length - 1]; + + lastFocusableEl.addEventListener('keydown', this.closeFlyout); + }; + + /** + * Closes the login popup flyout on tab (keydown) + * + * @param event - event tracked on user input (keydown) + */ + private readonly closeFlyout = (e: KeyboardEvent): void => { + if (e.key === 'Tab') { + this.hideFlyout(); + } + }; + /** * Render the flyout menu content. * From 85884f7c030ab2479060e05cfad44729ee9e5a61 Mon Sep 17 00:00:00 2001 From: Mnickii Date: Tue, 8 Aug 2023 13:47:02 +0000 Subject: [PATCH 2/8] fix shift+tab behaviour --- .../mgt-components/src/components/mgt-login/mgt-login.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts index f8dd858fbb..c7e340af06 100644 --- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts +++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts @@ -365,7 +365,7 @@ export class MgtLogin extends MgtTemplatedComponent { /** * Tracks tabbing through the flyout (keydown) */ - private readonly onUserKeyDown = (): void => { + private readonly onUserKeyDown = (e: KeyboardEvent): void => { if (!this.flyout.isOpen) { return; } @@ -373,8 +373,10 @@ export class MgtLogin extends MgtTemplatedComponent { const el = this.renderRoot.querySelector('.popup-content'); const focusableEls = el.querySelectorAll('li, fluent-button'); const lastFocusableEl = focusableEls[focusableEls.length - 1]; - - lastFocusableEl.addEventListener('keydown', this.closeFlyout); + if (e.key === 'Tab' && lastFocusableEl === e.target) { + lastFocusableEl.addEventListener('keydown', this.closeFlyout); + } + el.addEventListener('blur', this.closeFlyout); }; /** From 4fe987ab63dcdf7762466562abe3c8640536ed44 Mon Sep 17 00:00:00 2001 From: Mnickii Date: Wed, 9 Aug 2023 12:16:14 +0000 Subject: [PATCH 3/8] use a focus trap to fix menu dismiss issues with shift+tab --- .../src/components/mgt-login/mgt-login.ts | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts index c7e340af06..19508ec9a0 100644 --- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts +++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts @@ -371,22 +371,18 @@ export class MgtLogin extends MgtTemplatedComponent { } const el = this.renderRoot.querySelector('.popup-content'); - const focusableEls = el.querySelectorAll('li, fluent-button'); - const lastFocusableEl = focusableEls[focusableEls.length - 1]; - if (e.key === 'Tab' && lastFocusableEl === e.target) { - lastFocusableEl.addEventListener('keydown', this.closeFlyout); + const focusableEls = el.querySelectorAll('ul, fluent-button'); + const firstFocusableEl = el.querySelector('#signout-button') || focusableEls[0]; + const lastFocusableEl = + el.querySelector('#signin-different-account-button') || focusableEls[focusableEls.length - 1]; + + if (e.key === 'Tab' && e.shiftKey && firstFocusableEl === e.target) { + e.preventDefault(); + (lastFocusableEl as HTMLElement)?.focus(); } - el.addEventListener('blur', this.closeFlyout); - }; - - /** - * Closes the login popup flyout on tab (keydown) - * - * @param event - event tracked on user input (keydown) - */ - private readonly closeFlyout = (e: KeyboardEvent): void => { - if (e.key === 'Tab') { - this.hideFlyout(); + if (e.key === 'Tab' && lastFocusableEl === e.target) { + e.preventDefault(); + (firstFocusableEl as HTMLElement)?.focus(); } }; @@ -466,6 +462,7 @@ export class MgtLogin extends MgtTemplatedComponent { template || html` void this.login()}> From ac695061132f7a1ccf1e38b80b5d4e5c1209a566 Mon Sep 17 00:00:00 2001 From: Mnickii Date: Thu, 10 Aug 2023 14:36:53 +0000 Subject: [PATCH 4/8] fix shift+tab within the focus trap --- .../mgt-components/src/components/mgt-login/mgt-login.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts index 19508ec9a0..e607bdc74c 100644 --- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts +++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts @@ -384,6 +384,15 @@ export class MgtLogin extends MgtTemplatedComponent { e.preventDefault(); (firstFocusableEl as HTMLElement)?.focus(); } + + if (e.key === 'Tab' && e.shiftKey) { + e.preventDefault(); + for (let i = 0; i < focusableEls.length; i++) { + if (focusableEls[i] === e.target) { + window.setTimeout(() => (focusableEls[i - 1] as HTMLElement)?.focus(), 0); + } + } + } }; /** From d852b08aac028ce0b0150d23e79a81d88f612550 Mon Sep 17 00:00:00 2001 From: Mnickii Date: Wed, 16 Aug 2023 13:46:30 +0000 Subject: [PATCH 5/8] fix buggy shift+tab behaviour --- .../src/components/mgt-login/mgt-login.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts index e607bdc74c..cffa0c16da 100644 --- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts +++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts @@ -381,16 +381,13 @@ export class MgtLogin extends MgtTemplatedComponent { (lastFocusableEl as HTMLElement)?.focus(); } if (e.key === 'Tab' && lastFocusableEl === e.target) { - e.preventDefault(); - (firstFocusableEl as HTMLElement)?.focus(); - } - - if (e.key === 'Tab' && e.shiftKey) { - e.preventDefault(); - for (let i = 0; i < focusableEls.length; i++) { - if (focusableEls[i] === e.target) { - window.setTimeout(() => (focusableEls[i - 1] as HTMLElement)?.focus(), 0); - } + if (e.shiftKey) { + e.preventDefault(); + const focusableArrs = Array.from(focusableEls); + window.setTimeout(() => (focusableEls[focusableArrs.indexOf(lastFocusableEl) - 1] as HTMLElement)?.focus(), 0); + } else { + e.preventDefault(); + (firstFocusableEl as HTMLElement)?.focus(); } } }; From ebbb68302e7d730d3f4527254d132eae5c4b209e Mon Sep 17 00:00:00 2001 From: Mnickii Date: Wed, 16 Aug 2023 17:47:02 +0300 Subject: [PATCH 6/8] return focus to ligin button --- .../mgt-components/src/components/mgt-login/mgt-login.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts index cffa0c16da..a5b112ee87 100644 --- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts +++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts @@ -320,6 +320,7 @@ export class MgtLogin extends MgtTemplatedComponent { const expandedState: boolean | undefined = showSignedInState ? this._isFlyoutOpen : undefined; return html` Date: Thu, 17 Aug 2023 15:12:43 +0300 Subject: [PATCH 7/8] Update packages/mgt-components/src/components/mgt-login/mgt-login.ts rewrite implementation to handle shift+tab natively Co-authored-by: Gavin Barron --- .../src/components/mgt-login/mgt-login.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts index a5b112ee87..dfc332d414 100644 --- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts +++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts @@ -381,15 +381,9 @@ export class MgtLogin extends MgtTemplatedComponent { e.preventDefault(); (lastFocusableEl as HTMLElement)?.focus(); } - if (e.key === 'Tab' && lastFocusableEl === e.target) { - if (e.shiftKey) { - e.preventDefault(); - const focusableArrs = Array.from(focusableEls); - window.setTimeout(() => (focusableEls[focusableArrs.indexOf(lastFocusableEl) - 1] as HTMLElement)?.focus(), 0); - } else { - e.preventDefault(); - (firstFocusableEl as HTMLElement)?.focus(); - } + if (e.key === 'Tab' && !e.shiftKey && lastFocusableEl === e.target) { + e.preventDefault(); + (firstFocusableEl as HTMLElement)?.focus(); } if (e.key === 'Escape') { const loginButton = this.renderRoot.querySelector('#login-button'); From a470bd3e6062ece2be6f1a6461ba5a0651f140ac Mon Sep 17 00:00:00 2001 From: Mnickii Date: Thu, 17 Aug 2023 15:32:54 +0300 Subject: [PATCH 8/8] add shift+tab case while at fluent-card --- packages/mgt-components/src/components/mgt-login/mgt-login.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts index dfc332d414..b2a3b7f858 100644 --- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts +++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts @@ -389,6 +389,10 @@ export class MgtLogin extends MgtTemplatedComponent { const loginButton = this.renderRoot.querySelector('#login-button'); (loginButton as HTMLElement)?.focus(); } + const fluentCardEl = this.renderRoot.querySelector('fluent-card'); + if (e.shiftKey && e.key === 'Tab' && e.target === fluentCardEl) { + this.hideFlyout(); + } }; /**