mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-03 19:43:27 +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:
@ -1,6 +1,6 @@
|
||||
describe('IonModal', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/overlay-components/modal');
|
||||
cy.visit('/overlay-components/modal-basic');
|
||||
});
|
||||
|
||||
it('display modal', () => {
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
describe('IonModal: focusTrap regression', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/overlay-components/modal-focus-trap');
|
||||
});
|
||||
|
||||
it('should allow interacting with background when focusTrap=false', () => {
|
||||
cy.get('#open-non-trapped-modal').click();
|
||||
cy.get('ion-modal').should('be.visible');
|
||||
|
||||
cy.get('#background-action').click();
|
||||
cy.get('#background-action-count').should('have.text', '1');
|
||||
});
|
||||
|
||||
it('should prevent interacting with background when focusTrap=true', () => {
|
||||
cy.get('#open-trapped-modal').click();
|
||||
cy.get('ion-modal').should('be.visible');
|
||||
|
||||
// Ensure backdrop is active and capturing pointer events
|
||||
cy.get('ion-backdrop').should('exist');
|
||||
cy.get('ion-backdrop').should('have.css', 'pointer-events', 'auto');
|
||||
|
||||
// Baseline: counter is 0
|
||||
cy.get('#background-action-count').should('have.text', '0');
|
||||
|
||||
// Click the center of the background button via body coordinates (topmost element will receive it)
|
||||
cy.get('#background-action').then(($btn) => {
|
||||
const rect = $btn[0].getBoundingClientRect();
|
||||
const x = rect.left + rect.width / 2;
|
||||
const y = rect.top + rect.height / 2;
|
||||
cy.get('body').click(x, y);
|
||||
});
|
||||
|
||||
// Counter should remain unchanged
|
||||
cy.get('#background-action-count').should('have.text', '0');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,27 @@
|
||||
describe('IonModal: inline teleport with showBackdrop=false', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/overlay-components/modal-teleport');
|
||||
});
|
||||
|
||||
it('should render and remain interactive when appended into a page container', () => {
|
||||
cy.get('#open-teleport-modal').click();
|
||||
cy.get('ion-modal').should('be.visible');
|
||||
|
||||
// Verify modal content is interactable: close button should dismiss the modal
|
||||
cy.get('#close-teleport-modal').click();
|
||||
cy.get('ion-modal').should('not.exist');
|
||||
});
|
||||
|
||||
it('should allow background interaction when showBackdrop=false', () => {
|
||||
cy.get('#open-teleport-modal').click();
|
||||
cy.get('ion-modal').should('be.visible');
|
||||
|
||||
// Ensure the background button is clickable while modal is open
|
||||
cy.get('#teleport-background-action').click();
|
||||
cy.get('#teleport-background-action-count').should('have.text', '1');
|
||||
|
||||
// Cleanup
|
||||
cy.get('#close-teleport-modal').click();
|
||||
cy.get('ion-modal').should('not.exist');
|
||||
});
|
||||
});
|
||||
@ -1,7 +1,7 @@
|
||||
describe('keepContentsMounted', () => {
|
||||
describe('modal', () => {
|
||||
it('should not mount component if false', () => {
|
||||
cy.visit('/overlay-components/modal');
|
||||
cy.visit('/overlay-components/modal-basic');
|
||||
|
||||
cy.get('ion-modal ion-content').should('not.exist');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user