@@ -24,19 +24,25 @@ export const GlobalModal = ({
2424 const isOpen = useModalDialogIsOpen ( ) ;
2525 const innerRef = useRef < HTMLDivElement | null > ( null ) ;
2626 const closeButtonRef = useRef < HTMLButtonElement | null > ( null ) ;
27+ const closingRef = useRef ( false ) ;
2728
2829 const maybeClose = useCallback (
2930 ( source : ModalCloseSource , event : ModalCloseEvent ) => {
3031 const allow = onCloseAttempt ?.( source , event ) ;
3132 if ( allow !== false ) {
3233 onClose ?.( event ) ;
3334 dialog . close ( ) ;
35+ closingRef . current = true ;
3436 }
3537 } ,
3638 [ dialog , onClose , onCloseAttempt ] ,
3739 ) ;
3840
3941 const handleClick = ( event : React . MouseEvent < HTMLButtonElement | HTMLDivElement > ) => {
42+ // Prevent DialogPortalDestination overlay from handling any click (closeAll).
43+ // Ensures overlay/button close is fully controlled by onCloseAttempt/onClose.
44+ event . stopPropagation ( ) ;
45+
4046 const target = event . target as HTMLButtonElement | HTMLDivElement ;
4147 if ( innerRef . current ?. contains ( target ) ) return ;
4248
@@ -58,8 +64,13 @@ export const GlobalModal = ({
5864 return ( ) => document . removeEventListener ( 'keydown' , handleKeyDown ) ;
5965 } , [ isOpen , maybeClose , open ] ) ;
6066
67+ // Sync open prop → dialog open. Don't close here (dialog ref changes after close → effect loop).
68+ // closingRef blocks re-open when we just closed and parent hasn't set open=false yet.
6169 useEffect ( ( ) => {
62- if ( open && ! isOpen ) {
70+ if ( ! open ) {
71+ closingRef . current = false ;
72+ }
73+ if ( open && ! isOpen && ! closingRef . current ) {
6374 dialog . open ( ) ;
6475 }
6576 } , [ dialog , isOpen , open ] ) ;
0 commit comments