@@ -40,7 +40,6 @@ export const createInlineOverlayComponent = <PropType, ElementType>(
4040 ref : React . RefObject < HTMLIonOverlayElement > ;
4141 wrapperRef : React . RefObject < HTMLElement > ;
4242 stableMergedRefs : React . RefCallback < HTMLElement > ;
43- mutationObserver : MutationObserver | null = null ;
4443
4544 constructor ( props : IonicReactInternalProps < PropType > ) {
4645 super ( props ) ;
@@ -60,57 +59,6 @@ export const createInlineOverlayComponent = <PropType, ElementType>(
6059 this . ref . current ?. addEventListener ( 'ionMount' , this . handleIonMount ) ;
6160 this . ref . current ?. addEventListener ( 'willPresent' , this . handleWillPresent ) ;
6261 this . ref . current ?. addEventListener ( 'didDismiss' , this . handleDidDismiss ) ;
63-
64- /**
65- * Watch for when ancestor pages become hidden (ion-page-hidden class).
66- * This handles React Router 6 where pages stay mounted on forward PUSH.
67- * When a page is hidden, we dismiss any open overlays within it.
68- */
69- this . setupPageVisibilityObserver ( ) ;
70- }
71-
72- setupPageVisibilityObserver ( ) {
73- /**
74- * Watch for when ancestor pages get the ion-page-hidden class.
75- * We use a subtree observer on a parent container because:
76- * 1. The overlay's component might not have an IonPage wrapper
77- * 2. Pages might be added dynamically after this component mounts
78- * 3. We want to dismiss overlays when navigation hides the containing page
79- *
80- * This handles React Router 6 where pages stay mounted but get hidden.
81- */
82- this . mutationObserver = new MutationObserver ( ( mutations ) => {
83- if ( ! this . state . isOpen ) return ;
84-
85- for ( const mutation of mutations ) {
86- if ( mutation . type === 'attributes' && mutation . attributeName === 'class' ) {
87- const target = mutation . target as HTMLElement ;
88- // If any element gets the ion-page-hidden or ion-page-invisible class, dismiss overlay
89- if ( target . classList . contains ( 'ion-page-hidden' ) || target . classList . contains ( 'ion-page-invisible' ) ) {
90- /**
91- * Only dismiss the overlay if the hidden page is an ancestor of the overlay,
92- * not a descendant. Pages inside the overlay (e.g., IonPage in modal content)
93- * may get ion-page-invisible when they mount inside an outlet context, but
94- * this should not dismiss the overlay.
95- */
96- const overlayElement = this . ref . current ;
97- if ( overlayElement && ! overlayElement . contains ( target ) ) {
98- this . dismissOverlay ( ) ;
99- return ;
100- }
101- }
102- }
103- }
104- } ) ;
105-
106- // Observe a parent container with subtree: true to catch all descendant class changes
107- // This works even if pages are added after mount or if the current route has no IonPage
108- const appRoot = document . querySelector ( '#root' ) || document . body ;
109- this . mutationObserver . observe ( appRoot , {
110- attributes : true ,
111- attributeFilter : [ 'class' ] ,
112- subtree : true , // Watch all descendants
113- } ) ;
11462 }
11563
11664 componentDidUpdate ( prevProps : IonicReactInternalProps < PropType > ) {
@@ -152,25 +100,6 @@ export const createInlineOverlayComponent = <PropType, ElementType>(
152100 node . remove ( ) ;
153101 detachProps ( node , this . props ) ;
154102 }
155-
156- // Clean up mutation observer
157- if ( this . mutationObserver ) {
158- this . mutationObserver . disconnect ( ) ;
159- this . mutationObserver = null ;
160- }
161- }
162-
163- dismissOverlay ( ) {
164- const node = this . ref . current ;
165- if ( node && this . state . isOpen ) {
166- /**
167- * Dismiss the overlay without animation when the page is hidden.
168- * This matches the behavior in componentWillUnmount.
169- */
170- node . removeEventListener ( 'didDismiss' , this . handleDidDismiss ) ;
171- node . remove ( ) ;
172- detachProps ( node , this . props ) ;
173- }
174103 }
175104
176105 render ( ) {
0 commit comments