fix(overlays): do not return focus if application has already moved focus manually (#28850)

Issue number: resolves #28849

---------

## What is the current behavior?

If the developer tries to set focus to a custom element on overlay
dismissal, Ionic will always override that focus.

## What is the new behavior?

- If focus is already set by developer during dismissal, then Ionic will
not restore focus to previous element

## Does this introduce a breaking change?

- [ ] Yes
- [x] No


## Other information

In the before video, you can see the text box is focused by developer
code when "Mention User" is tapped, which opens the keyboard. Shortly
after that, when the bottom sheet fully dismisses, Ionic focuses the
button, removing focus from the text box and hiding the keyboard.

In the after, Ionic detects that the developer has already focused the
text box and does not change that focus.

|Before|After|
|---|---|
|<video
src="https://github.com/ionic-team/ionic-framework/assets/2166114/47d55eff-29af-4019-ac3c-00f9fe722ca7"></video>|
<video
src="https://github.com/ionic-team/ionic-framework/assets/2166114/508ae466-d037-41eb-b518-92338a122b22"></video>|
This commit is contained in:
Alexander Harding
2024-02-13 08:56:45 -06:00
committed by GitHub
parent f07eabe12e
commit a016670a8a
2 changed files with 77 additions and 3 deletions

View File

@@ -254,5 +254,52 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await expect(modalInputOne).toBeFocused();
});
test('should not return focus to another element if focus already manually returned', async ({
page,
skip,
}, testInfo) => {
skip.browser(
'webkit',
'WebKit does not consider buttons to be focusable, so this test always passes since the input is the only focusable element.'
);
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/28849',
});
await page.setContent(
`
<button id="open-action-sheet">open</button>
<ion-action-sheet trigger="open-action-sheet"></ion-action-sheet>
<input id="test-input" />
<script>
const actionSheet = document.querySelector('ion-action-sheet');
actionSheet.addEventListener('ionActionSheetWillDismiss', () => {
requestAnimationFrame(() => {
document.querySelector('#test-input').focus();
});
});
</script>
`,
config
);
const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');
const actionSheet = page.locator('ion-action-sheet');
const input = page.locator('#test-input');
const trigger = page.locator('#open-action-sheet');
// present action sheet
await trigger.click();
await ionActionSheetDidPresent.next();
// dismiss action sheet
await actionSheet.evaluate((el: HTMLIonActionSheetElement) => el.dismiss());
// verify focus is in correct location
await expect(input).toBeFocused();
});
});
});