From ffc4297451ad4d1f043460adbc82ff791ba058c6 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 10:48:36 -0400 Subject: [PATCH 1/9] fix(overlay): do not hide overlay if toast is presented --- core/src/utils/overlays.ts | 21 ++++++++++-- core/src/utils/test/overlays/overlays.spec.ts | 33 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index 11ec2f56698..af8ff81c9a9 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -549,7 +549,13 @@ export const present = async ( */ if (doc !== undefined) { const presentedOverlays = getPresentedOverlays(doc); - presentedOverlays.forEach((o) => o.setAttribute('aria-hidden', 'true')); + presentedOverlays.forEach((o, i) => { + if (i === presentedOverlays.length - 1 && overlay.el.tagName === 'ION-TOAST') { + return; + } + + o.setAttribute('aria-hidden', 'true'); + }); } overlay.presented = true; @@ -728,7 +734,18 @@ export const dismiss = async ( * topmost one from screen readers. */ if (doc !== undefined) { - getPresentedOverlay(doc)?.removeAttribute('aria-hidden'); + const overlays = getPresentedOverlays(doc); + + for (let i = overlays.length - 1; i >= 0; i--) { + const overlay = overlays[i]; + + if (overlay.tagName === 'ION-TOAST') { + overlay.removeAttribute('aria-hidden'); + } else { + overlay.removeAttribute('aria-hidden'); + break; + } + } } return true; diff --git a/core/src/utils/test/overlays/overlays.spec.ts b/core/src/utils/test/overlays/overlays.spec.ts index 7b67a221832..8418276aa9b 100644 --- a/core/src/utils/test/overlays/overlays.spec.ts +++ b/core/src/utils/test/overlays/overlays.spec.ts @@ -1,6 +1,7 @@ import { newSpecPage } from '@stencil/core/testing'; import { Modal } from '../../../components/modal/modal'; +import { Toast } from '../../../components/toast/toast'; import { Nav } from '../../../components/nav/nav'; import { RouterOutlet } from '../../../components/router-outlet/router-outlet'; import { setRootAriaHidden } from '../../overlays'; @@ -193,4 +194,36 @@ describe('aria-hidden on individual overlays', () => { await modalOne.present(); expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); }); + + it('should not hide previous overlay is top-most overlay is toast', async () => { + const page = await newSpecPage({ + components: [Modal, Toast], + html: ` + + + + `, + }); + + const modalOne = page.body.querySelector('ion-modal#one')!; + const modalTwo = page.body.querySelector('ion-modal#two')!; + const toast = page.body.querySelector('ion-toast')!; + + await modalOne.present(); + await toast.present(); + + expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); + + await modalTwo.present(); + + expect(modalOne.hasAttribute('aria-hidden')).toEqual(true); + expect(toast.hasAttribute('aria-hidden')).toEqual(true); + expect(modalTwo.hasAttribute('aria-hidden')).toEqual(false); + + await modalTwo.dismiss(); + + expect(toast.hasAttribute('aria-hidden')).toEqual(false); + + expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); + }); }); From 500c2dc0c6ad0ac9c7114416181cff7c4c0e5990 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 11:44:15 -0400 Subject: [PATCH 2/9] test: improve test coverage --- core/src/utils/test/overlays/overlays.spec.ts | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/core/src/utils/test/overlays/overlays.spec.ts b/core/src/utils/test/overlays/overlays.spec.ts index 8418276aa9b..c5f00b452cb 100644 --- a/core/src/utils/test/overlays/overlays.spec.ts +++ b/core/src/utils/test/overlays/overlays.spec.ts @@ -195,35 +195,41 @@ describe('aria-hidden on individual overlays', () => { expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); }); - it('should not hide previous overlay is top-most overlay is toast', async () => { + it.only('should not hide previous overlay is top-most overlay is toast', async () => { const page = await newSpecPage({ components: [Modal, Toast], html: ` - - - + + + + `, }); - const modalOne = page.body.querySelector('ion-modal#one')!; - const modalTwo = page.body.querySelector('ion-modal#two')!; - const toast = page.body.querySelector('ion-toast')!; + const modalOne = page.body.querySelector('ion-modal#m-one')!; + const modalTwo = page.body.querySelector('ion-modal#m-two')!; + const toastOne = page.body.querySelector('ion-toast#t-one')!; + const toastTwo = page.body.querySelector('ion-toast#t-two')!; await modalOne.present(); - await toast.present(); + await toastOne.present(); + await toastTwo.present(); expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); + expect(toastOne.hasAttribute('aria-hidden')).toEqual(false); + expect(toastTwo.hasAttribute('aria-hidden')).toEqual(false); await modalTwo.present(); expect(modalOne.hasAttribute('aria-hidden')).toEqual(true); - expect(toast.hasAttribute('aria-hidden')).toEqual(true); + expect(toastOne.hasAttribute('aria-hidden')).toEqual(true); + expect(toastTwo.hasAttribute('aria-hidden')).toEqual(true); expect(modalTwo.hasAttribute('aria-hidden')).toEqual(false); await modalTwo.dismiss(); - expect(toast.hasAttribute('aria-hidden')).toEqual(false); - expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); + expect(toastOne.hasAttribute('aria-hidden')).toEqual(false); + expect(toastTwo.hasAttribute('aria-hidden')).toEqual(false); }); }); From 897c08dc94a80009b5d0e6621670c1f35e6b341f Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 12:15:46 -0400 Subject: [PATCH 3/9] account for when toast is mix throughout --- core/src/utils/overlays.ts | 54 ++++++++++++------- core/src/utils/test/overlays/overlays.spec.ts | 38 +++++++++++-- 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index af8ff81c9a9..df6f38177da 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -543,19 +543,29 @@ export const present = async ( setRootAriaHidden(true); /** - * Hide all other overlays from screen readers so only this one - * can be read. Note that presenting an overlay always makes - * it the topmost one. + * Ensure that underlying overlays have aria-hidden if necessary so that screen readers + * cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout + * events here because those events do not fire when the screen readers moves to a non-focusable + * element such as text. */ if (doc !== undefined) { - const presentedOverlays = getPresentedOverlays(doc); - presentedOverlays.forEach((o, i) => { - if (i === presentedOverlays.length - 1 && overlay.el.tagName === 'ION-TOAST') { - return; - } + const overlays = getPresentedOverlays(doc); - o.setAttribute('aria-hidden', 'true'); - }); + for (let i = overlays.length - 1; i >= 0; i--) { + const presentedOverlay = overlays[i]; + const nextPresentedOverlay = overlays[i + 1] ?? overlay.el; + + // If next overlay has aria-hidden then all remaining overlays will have it too. + if (nextPresentedOverlay.hasAttribute('aria-hidden')) { + presentedOverlay.setAttribute('aria-hidden', 'true'); + /** + * If the next overlay is a Toast this does not have aria-hidden then current overlay + * should not have aria-hidden either so focus can remain in the current overlay. + */ + } else if (nextPresentedOverlay.tagName !== 'ION-TOAST') { + presentedOverlay.setAttribute('aria-hidden', 'true'); + } + } } overlay.presented = true; @@ -729,20 +739,28 @@ export const dismiss = async ( overlay.el.remove(); - /** - * If there are other overlays presented, unhide the new - * topmost one from screen readers. - */ + // If there are other overlays presented, unhide the new topmost one from screen readers. if (doc !== undefined) { const overlays = getPresentedOverlays(doc); for (let i = overlays.length - 1; i >= 0; i--) { - const overlay = overlays[i]; + const currentOverlay = overlays[i]; - if (overlay.tagName === 'ION-TOAST') { - overlay.removeAttribute('aria-hidden'); + /** + * If the current we are looking at is a Toast then we can remove aria-hidden. + * However, we potentially need to keep looking at the overlay stack because there + * could be more Toasts underneath. Additionally, we need to unhide the closest non-Toast + * overlay too so focus can move there since focus is never automatically moved to the Toast. + */ + if (currentOverlay.tagName === 'ION-TOAST') { + currentOverlay.removeAttribute('aria-hidden'); + /** + * If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely + * since this overlay should always receive focus. As a result, all underlying overlays should still + * be hidden from screen readers. + */ } else { - overlay.removeAttribute('aria-hidden'); + currentOverlay.removeAttribute('aria-hidden'); break; } } diff --git a/core/src/utils/test/overlays/overlays.spec.ts b/core/src/utils/test/overlays/overlays.spec.ts index c5f00b452cb..c6d42ea06a7 100644 --- a/core/src/utils/test/overlays/overlays.spec.ts +++ b/core/src/utils/test/overlays/overlays.spec.ts @@ -195,14 +195,14 @@ describe('aria-hidden on individual overlays', () => { expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); }); - it.only('should not hide previous overlay is top-most overlay is toast', async () => { + it('should not hide previous overlay is top-most overlay is toast', async () => { const page = await newSpecPage({ components: [Modal, Toast], html: ` + - `, }); @@ -212,24 +212,52 @@ describe('aria-hidden on individual overlays', () => { const toastTwo = page.body.querySelector('ion-toast#t-two')!; await modalOne.present(); + await modalTwo.present(); await toastOne.present(); await toastTwo.present(); - expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); + expect(modalOne.hasAttribute('aria-hidden')).toEqual(true); + expect(modalTwo.hasAttribute('aria-hidden')).toEqual(false); expect(toastOne.hasAttribute('aria-hidden')).toEqual(false); expect(toastTwo.hasAttribute('aria-hidden')).toEqual(false); + await toastTwo.dismiss(); + + expect(modalOne.hasAttribute('aria-hidden')).toEqual(true); + expect(modalTwo.hasAttribute('aria-hidden')).toEqual(false); + expect(toastOne.hasAttribute('aria-hidden')).toEqual(false); + + await toastOne.dismiss(); + + expect(modalOne.hasAttribute('aria-hidden')).toEqual(true); + expect(modalTwo.hasAttribute('aria-hidden')).toEqual(false); + }); + + it('should hide previous overlay even with a toast that is not the top-most overlay', async () => { + const page = await newSpecPage({ + components: [Modal, Toast], + html: ` + + + + `, + }); + + const modalOne = page.body.querySelector('ion-modal#m-one')!; + const modalTwo = page.body.querySelector('ion-modal#m-two')!; + const toastOne = page.body.querySelector('ion-toast#t-one')!; + + await modalOne.present(); + await toastOne.present(); await modalTwo.present(); expect(modalOne.hasAttribute('aria-hidden')).toEqual(true); expect(toastOne.hasAttribute('aria-hidden')).toEqual(true); - expect(toastTwo.hasAttribute('aria-hidden')).toEqual(true); expect(modalTwo.hasAttribute('aria-hidden')).toEqual(false); await modalTwo.dismiss(); expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); expect(toastOne.hasAttribute('aria-hidden')).toEqual(false); - expect(toastTwo.hasAttribute('aria-hidden')).toEqual(false); }); }); From fc29a6c96334484fcc4906d608faf920fa67533e Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 12:23:21 -0400 Subject: [PATCH 4/9] clean up code --- core/src/utils/overlays.ts | 120 +++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 52 deletions(-) diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index df6f38177da..b9383b3747e 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -541,32 +541,7 @@ export const present = async ( } setRootAriaHidden(true); - - /** - * Ensure that underlying overlays have aria-hidden if necessary so that screen readers - * cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout - * events here because those events do not fire when the screen readers moves to a non-focusable - * element such as text. - */ - if (doc !== undefined) { - const overlays = getPresentedOverlays(doc); - - for (let i = overlays.length - 1; i >= 0; i--) { - const presentedOverlay = overlays[i]; - const nextPresentedOverlay = overlays[i + 1] ?? overlay.el; - - // If next overlay has aria-hidden then all remaining overlays will have it too. - if (nextPresentedOverlay.hasAttribute('aria-hidden')) { - presentedOverlay.setAttribute('aria-hidden', 'true'); - /** - * If the next overlay is a Toast this does not have aria-hidden then current overlay - * should not have aria-hidden either so focus can remain in the current overlay. - */ - } else if (nextPresentedOverlay.tagName !== 'ION-TOAST') { - presentedOverlay.setAttribute('aria-hidden', 'true'); - } - } - } + hideOverlaysFromScreenReaders(overlay.el); overlay.presented = true; overlay.willPresent.emit(); @@ -739,32 +714,7 @@ export const dismiss = async ( overlay.el.remove(); - // If there are other overlays presented, unhide the new topmost one from screen readers. - if (doc !== undefined) { - const overlays = getPresentedOverlays(doc); - - for (let i = overlays.length - 1; i >= 0; i--) { - const currentOverlay = overlays[i]; - - /** - * If the current we are looking at is a Toast then we can remove aria-hidden. - * However, we potentially need to keep looking at the overlay stack because there - * could be more Toasts underneath. Additionally, we need to unhide the closest non-Toast - * overlay too so focus can move there since focus is never automatically moved to the Toast. - */ - if (currentOverlay.tagName === 'ION-TOAST') { - currentOverlay.removeAttribute('aria-hidden'); - /** - * If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely - * since this overlay should always receive focus. As a result, all underlying overlays should still - * be hidden from screen readers. - */ - } else { - currentOverlay.removeAttribute('aria-hidden'); - break; - } - } - } + revealOverlaysToScreenReaders(); return true; }; @@ -1001,3 +951,69 @@ export const createTriggerController = () => { removeClickListener, }; }; + +/** + * Ensure that underlying overlays have aria-hidden if necessary so that screen readers + * cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout + * events here because those events do not fire when the screen readers moves to a non-focusable + * element such as text. + * Without this logic screen readers would be able to move focus outside of the top focus-trapped overlay. + * + * @param newTopMostOverlay - The overlay that is being presented. Since the overlay has not been + * fully presented yet at the time this function is called it will not be included in the getPresentedOverlays result. + */ +const hideOverlaysFromScreenReaders = (newTopMostOverlay: HTMLIonOverlayElement) => { + if (doc === undefined) return; + + const overlays = getPresentedOverlays(doc); + + for (let i = overlays.length - 1; i >= 0; i--) { + const presentedOverlay = overlays[i]; + const nextPresentedOverlay = overlays[i + 1] ?? newTopMostOverlay; + + // If next overlay has aria-hidden then all remaining overlays will have it too. + if (nextPresentedOverlay.hasAttribute('aria-hidden')) { + presentedOverlay.setAttribute('aria-hidden', 'true'); + /** + * If the next overlay is a Toast this does not have aria-hidden then current overlay + * should not have aria-hidden either so focus can remain in the current overlay. + */ + } else if (nextPresentedOverlay.tagName !== 'ION-TOAST') { + presentedOverlay.setAttribute('aria-hidden', 'true'); + } + } +}; + +/** + * When dismissing an overlay we need to reveal the new top-most overlay to screen readers. + * If the top-most overlay is a Toast we potentially need to reveal more overlays since + * focus is never automatically moved to the Toast. + */ +const revealOverlaysToScreenReaders = () => { + if (doc === undefined) return; + + // If there are other overlays presented, unhide the new topmost one from screen readers. + const overlays = getPresentedOverlays(doc); + + for (let i = overlays.length - 1; i >= 0; i--) { + const currentOverlay = overlays[i]; + + /** + * If the current we are looking at is a Toast then we can remove aria-hidden. + * However, we potentially need to keep looking at the overlay stack because there + * could be more Toasts underneath. Additionally, we need to unhide the closest non-Toast + * overlay too so focus can move there since focus is never automatically moved to the Toast. + */ + if (currentOverlay.tagName === 'ION-TOAST') { + currentOverlay.removeAttribute('aria-hidden'); + /** + * If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely + * since this overlay should always receive focus. As a result, all underlying overlays should still + * be hidden from screen readers. + */ + } else { + currentOverlay.removeAttribute('aria-hidden'); + break; + } + } +}; From c89434f96fa42e1938dad3a9f1bc30f353fd1d6e Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 14:35:50 -0400 Subject: [PATCH 5/9] Update core/src/utils/test/overlays/overlays.spec.ts Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com> --- core/src/utils/test/overlays/overlays.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/utils/test/overlays/overlays.spec.ts b/core/src/utils/test/overlays/overlays.spec.ts index c6d42ea06a7..29a77c3c268 100644 --- a/core/src/utils/test/overlays/overlays.spec.ts +++ b/core/src/utils/test/overlays/overlays.spec.ts @@ -195,7 +195,7 @@ describe('aria-hidden on individual overlays', () => { expect(modalOne.hasAttribute('aria-hidden')).toEqual(false); }); - it('should not hide previous overlay is top-most overlay is toast', async () => { + it('should not hide previous overlay if top-most overlay is toast', async () => { const page = await newSpecPage({ components: [Modal, Toast], html: ` From 4390d134fd5efa1a490135afb6808fcd69569dbe Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 14:35:56 -0400 Subject: [PATCH 6/9] Update core/src/utils/overlays.ts Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com> --- core/src/utils/overlays.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index b9383b3747e..538084b2456 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -975,7 +975,7 @@ const hideOverlaysFromScreenReaders = (newTopMostOverlay: HTMLIonOverlayElement) if (nextPresentedOverlay.hasAttribute('aria-hidden')) { presentedOverlay.setAttribute('aria-hidden', 'true'); /** - * If the next overlay is a Toast this does not have aria-hidden then current overlay + * If the next overlay is a Toast that does not have aria-hidden then current overlay * should not have aria-hidden either so focus can remain in the current overlay. */ } else if (nextPresentedOverlay.tagName !== 'ION-TOAST') { From 3c24670bb43cd1b35c9c1ad98051660157a9cb94 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 14:36:03 -0400 Subject: [PATCH 7/9] Update core/src/utils/overlays.ts Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com> --- core/src/utils/overlays.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index 538084b2456..d9948be7ef5 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -992,7 +992,6 @@ const hideOverlaysFromScreenReaders = (newTopMostOverlay: HTMLIonOverlayElement) const revealOverlaysToScreenReaders = () => { if (doc === undefined) return; - // If there are other overlays presented, unhide the new topmost one from screen readers. const overlays = getPresentedOverlays(doc); for (let i = overlays.length - 1; i >= 0; i--) { From 6864d630236574f205e2e636bfcd3c435b267445 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 14:36:41 -0400 Subject: [PATCH 8/9] Update core/src/utils/overlays.ts Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com> --- core/src/utils/overlays.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index d9948be7ef5..d8ba3245ed9 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -1003,15 +1003,14 @@ const revealOverlaysToScreenReaders = () => { * could be more Toasts underneath. Additionally, we need to unhide the closest non-Toast * overlay too so focus can move there since focus is never automatically moved to the Toast. */ - if (currentOverlay.tagName === 'ION-TOAST') { - currentOverlay.removeAttribute('aria-hidden'); - /** - * If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely - * since this overlay should always receive focus. As a result, all underlying overlays should still - * be hidden from screen readers. - */ - } else { - currentOverlay.removeAttribute('aria-hidden'); + currentOverlay.removeAttribute('aria-hidden'); + + /** + * If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely + * since this overlay should always receive focus. As a result, all underlying overlays should still + * be hidden from screen readers. + */ + if (currentOverlay.tagName !== 'ION-TOAST') { break; } } From 3b2492aa2fbadafb69dcc5795909fa4b4df6e43f Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 12 Mar 2024 14:39:52 -0400 Subject: [PATCH 9/9] chore: simplify if block --- core/src/utils/overlays.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index d8ba3245ed9..b248206151a 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -971,14 +971,12 @@ const hideOverlaysFromScreenReaders = (newTopMostOverlay: HTMLIonOverlayElement) const presentedOverlay = overlays[i]; const nextPresentedOverlay = overlays[i + 1] ?? newTopMostOverlay; - // If next overlay has aria-hidden then all remaining overlays will have it too. - if (nextPresentedOverlay.hasAttribute('aria-hidden')) { - presentedOverlay.setAttribute('aria-hidden', 'true'); - /** - * If the next overlay is a Toast that does not have aria-hidden then current overlay - * should not have aria-hidden either so focus can remain in the current overlay. - */ - } else if (nextPresentedOverlay.tagName !== 'ION-TOAST') { + /** + * If next overlay has aria-hidden then all remaining overlays will have it too. + * Or, if the next overlay is a Toast that does not have aria-hidden then current overlay + * should not have aria-hidden either so focus can remain in the current overlay. + */ + if (nextPresentedOverlay.hasAttribute('aria-hidden') || nextPresentedOverlay.tagName !== 'ION-TOAST') { presentedOverlay.setAttribute('aria-hidden', 'true'); } } @@ -1004,7 +1002,7 @@ const revealOverlaysToScreenReaders = () => { * overlay too so focus can move there since focus is never automatically moved to the Toast. */ currentOverlay.removeAttribute('aria-hidden'); - + /** * If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely * since this overlay should always receive focus. As a result, all underlying overlays should still