mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-07 06:57:02 +08:00
fix(modal): allow sheet modals to skip focus trap (#30689)
Issue number: resolves #30684 --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> Recently, we [fixed some issues with aria-hidden in modals](https://github.com/ionic-team/ionic-framework/pull/30563), unfortunately at this time we neglected modals that opt out of focus trapping. As a result, a lot of modals that disable focus trapping still have it happening and it doesn't get cleaned up properly on dismiss. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> We're now properly checking for and skipping focus traps on modals that do not want them. ## Does this introduce a breaking change? - [ ] Yes - [X] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information I created regression tests for Angular in this to prevent this from happening again. I initially tried to do this with core, but the issue doesn't seem to reproduce with core. <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Current dev build: ``` 8.7.5-dev.11758652700.103435a3 ```
This commit is contained in:
@ -0,0 +1,38 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Modals: Dynamic Wrapper', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/lazy/modal-dynamic-wrapper');
|
||||
});
|
||||
|
||||
test('should render dynamic component inside modal', async ({ page }) => {
|
||||
await page.locator('#open-dynamic-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
await expect(page.locator('#dynamic-component-loaded')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should allow interacting with background content while sheet is open', async ({ page }) => {
|
||||
await page.locator('#open-dynamic-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
|
||||
await page.locator('#background-action').click();
|
||||
|
||||
await expect(page.locator('#background-action-count')).toHaveText('1');
|
||||
});
|
||||
|
||||
test('should prevent interacting with background content when focus is trapped', async ({ page }) => {
|
||||
await page.locator('#open-focused-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
|
||||
// Attempt to click the background button via coordinates; click should be intercepted by backdrop
|
||||
const box = await page.locator('#background-action').boundingBox();
|
||||
if (box) {
|
||||
await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
|
||||
}
|
||||
|
||||
await expect(page.locator('#background-action-count')).toHaveText('0');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,34 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Modals: Inline Sheet', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/lazy/modal-sheet-inline');
|
||||
});
|
||||
|
||||
test('should open inline sheet modal', async ({ page }) => {
|
||||
await page.locator('#present-inline-sheet-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
await expect(page.locator('#current-breakpoint')).toHaveText('0.2');
|
||||
await expect(page.locator('ion-modal ion-item')).toHaveCount(4);
|
||||
});
|
||||
|
||||
test('should expand to 0.75 breakpoint when searchbar is clicked', async ({ page }) => {
|
||||
await page.locator('#present-inline-sheet-modal').click();
|
||||
await expect(page.locator('#current-breakpoint')).toHaveText('0.2');
|
||||
|
||||
await page.locator('ion-modal ion-searchbar').click();
|
||||
|
||||
await expect(page.locator('#current-breakpoint')).toHaveText('0.75');
|
||||
});
|
||||
|
||||
test('should allow interacting with background content while sheet is open', async ({ page }) => {
|
||||
await page.locator('#present-inline-sheet-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
|
||||
await page.locator('#background-action').click();
|
||||
|
||||
await expect(page.locator('#background-action-count')).toHaveText('1');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,38 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Modals: Dynamic Wrapper (standalone)', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/standalone/modal-dynamic-wrapper');
|
||||
});
|
||||
|
||||
test('should render dynamic component inside modal', async ({ page }) => {
|
||||
await page.locator('#open-dynamic-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
await expect(page.locator('#dynamic-component-loaded')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should allow interacting with background content while sheet is open', async ({ page }) => {
|
||||
await page.locator('#open-dynamic-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
|
||||
await page.locator('#background-action').click();
|
||||
|
||||
await expect(page.locator('#background-action-count')).toHaveText('1');
|
||||
});
|
||||
|
||||
test('should prevent interacting with background content when focus is trapped', async ({ page }) => {
|
||||
await page.locator('#open-focused-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
|
||||
// Attempt to click the background button via coordinates; click should be intercepted by backdrop
|
||||
const box = await page.locator('#background-action').boundingBox();
|
||||
if (box) {
|
||||
await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
|
||||
}
|
||||
|
||||
await expect(page.locator('#background-action-count')).toHaveText('0');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,34 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Modals: Inline Sheet (standalone)', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/standalone/modal-sheet-inline');
|
||||
});
|
||||
|
||||
test('should open inline sheet modal', async ({ page }) => {
|
||||
await page.locator('#present-inline-sheet-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
await expect(page.locator('#current-breakpoint')).toHaveText('0.2');
|
||||
await expect(page.locator('ion-modal ion-item')).toHaveCount(4);
|
||||
});
|
||||
|
||||
test('should expand to 0.75 breakpoint when searchbar is clicked', async ({ page }) => {
|
||||
await page.locator('#present-inline-sheet-modal').click();
|
||||
await expect(page.locator('#current-breakpoint')).toHaveText('0.2');
|
||||
|
||||
await page.locator('ion-modal ion-searchbar').click();
|
||||
|
||||
await expect(page.locator('#current-breakpoint')).toHaveText('0.75');
|
||||
});
|
||||
|
||||
test('should allow interacting with background content while sheet is open', async ({ page }) => {
|
||||
await page.locator('#present-inline-sheet-modal').click();
|
||||
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
|
||||
await page.locator('#background-action').click();
|
||||
|
||||
await expect(page.locator('#background-action-count')).toHaveText('1');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user