fix(overlays): restore presented state after a DOM move - #31400
Open
ShaneK wants to merge 2 commits into
Open
Conversation
Co-authored-by: ptmkenny <github@ptmkenny.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
2 tasks
Contributor
|
Thank you for working on this! It looks much better than the solution I proposed. I updated to |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue number: resolves #31389
What is the current behavior?
Currently,
componentWillUnmountincreateInlineOverlayComponentremoves a nested inline overlay host thatCoreDelegatehas teleported out of its<template>. React also runs that hook when it only hides a subtree, so a Suspense fallback, an Offscreen tree, or the StrictMode cycle deletes an overlay that is still presenting. React did not remove the host, so React never puts it back. Core emitsionMountand then goes quiet: nowillPresent, nodidPresent, and no dismiss lifecycle, while the React tree still believes the overlay is open. The user sees nothing at all.What is the new behavior?
The wrapper now tells a React hide from a real destroy instead of treating both as an unmount. The marker
<template>is the discriminator, since it stays at the JSX position and leaves the document only on a real unmount, so the teardown defers a microtask and runs only if the marker really left. A hide leaves the host exactly where it is,present()anddidDismisskeep working while the subtree is hidden, and a destroy that hits while it is already hidden still cleans up even though React skips the secondcomponentWillUnmountthere. This addresses #31223's requirements by making a relocated portaled host move back intoportalTargetsynchronously, and the StrictMode cycle still leaves exactly one copy in the DOM.Separately, the five overlays that release the app root on disconnect (
modal,popover,alert,action-sheet,loading) now restore it on reconnect, along with the modal's safe-area overrides and parent-removal observer, and the button gesture onalertandaction-sheet. A presented overlay that gets detached and re-inserted across a task previously came back with the root lock and safe-area gone.Does this introduce a breaking change?
Other information
This supersedes #31390, which fixes the same issue by recording the removed host and re-appending it on remount. That works for the reported case, but it keeps the removal, and the removal costs more than the DOM node: the disconnect releases the root lock, clears the safe-area overrides and the sheet's
--ion-modal-offset-top, destroys the button gesture, and drops the parent-removal observer. Putting the node back restores none of that, so the smaller fix needs the core half of this PR anyway. Not removing it in the first place avoids all of that, and also covers the portaled overlays, the destroy-while-hidden case, and a dismiss landing during the hidden window, which #31390 doesn't reach. Thanks to @ptmkenny for the report, the analysis, and the original patch, which is where the diagnosis came from.Note that the core half is defence-in-depth rather than a requirement for #31389. Once the React wrapper stops removing the host, core no longer sees a detach and re-attach in the reported flow. It does fix a real pre-existing bug though, since a presented modal moved by anything else lost its safe-area, so it's worth keeping.
Preview:
Current dev build: