fix(overlays): prevent scroll gestures when the overlay is presented (#28415)

Issue number: Resolves #23942

---------

<!-- 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. -->

When an overlay is created (inserted in the DOM), but not presented, the
scroll gesture is prevented. This behavior comes from the
`connectedCallback` of `ion-backdrop`, where the gesture is prevented as
soon as the backdrop is inserted in the DOM.

This means in situations where a developer creates an overlay, but does
not present it immediately, the user cannot scroll. This is not desired.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Scroll blocking behavior tied to the gesture has been removed from
`ion-backdrop` and implemented into the overlays directly.
- When an overlay is presented, scroll blocking is enabled on the `body`
element (the user cannot scroll on the main content).
- When the last presented overlay is dismissed, scroll blocking is
disabled on the `body` element (the user can scroll on the main
content).

## Does this introduce a breaking change?

- [x] Yes
- [ ] No

`ion-backdrop` no longer prevents scrolling on the main content when the
backdrop is either inserted into the DOM or removed from the DOM.
Developers using Ionic overlays do not need to migrate their
implementations.

Developers with custom overlays using `ion-backdrop` internally can
either use Ionic's gesture controller to disable scrolling when their
overlay is presented/dismissed or can manually add the
`backdrop-no-scroll` Ionic global class to the `body` element.

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

---------
This commit is contained in:
Sean Perkins
2023-11-01 14:58:53 -04:00
committed by GitHub
parent 6cd819a059
commit 7ba939fb94
5 changed files with 98 additions and 18 deletions

View File

@ -20,6 +20,7 @@ import type {
} from '../interface';
import { CoreDelegate } from './framework-delegate';
import { BACKDROP_NO_SCROLL } from './gesture/gesture-controller';
import { OVERLAY_BACK_BUTTON_PRIORITY } from './hardware-back-button';
import { addEventListener, componentOnReady, focusElement, getElementRoot, removeEventListener } from './helpers';
import { printIonWarning } from './logging';
@ -471,6 +472,8 @@ export const present = async <OverlayPresentOptions>(
setRootAriaHidden(true);
document.body.classList.add(BACKDROP_NO_SCROLL);
overlay.presented = true;
overlay.willPresent.emit();
overlay.willPresentShorthand?.emit();
@ -549,12 +552,15 @@ export const dismiss = async <OverlayDismissOptions>(
return false;
}
const lastOverlay = doc !== undefined && getPresentedOverlays(doc).length === 1;
/**
* If this is the last visible overlay then
* we want to re-add the root to the accessibility tree.
*/
if (doc !== undefined && getPresentedOverlays(doc).length === 1) {
if (lastOverlay) {
setRootAriaHidden(false);
document.body.classList.remove(BACKDROP_NO_SCROLL);
}
overlay.presented = false;
@ -574,6 +580,7 @@ export const dismiss = async <OverlayDismissOptions>(
if (role !== GESTURE) {
await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
}
overlay.didDismiss.emit({ data, role });
overlay.didDismissShorthand?.emit({ data, role });