Skip to content

Commit 92bbc7b

Browse files
committed
fix(emcn): broaden modal popper guard to onInteractOutside
Covers the focusOutside dismissal path too: when a popper's focus scope unwinds on close, the transient focus shift could still dismiss the modal (and simultaneous body pointer-events lock teardown could freeze the page). Same data-state="open" scoping as the pointer guard.
1 parent 16fd91e commit 92bbc7b

2 files changed

Lines changed: 17 additions & 13 deletions

File tree

apps/sim/components/emcn/components/modal/modal.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,20 +217,24 @@ const ModalContent = React.forwardRef<
217217
onPointerUp={(e) => {
218218
e.stopPropagation()
219219
}}
220-
onPointerDownOutside={(e) => {
220+
onInteractOutside={(e) => {
221221
if (!isInteractionReady) {
222222
e.preventDefault()
223223
return
224224
}
225225
/**
226-
* Radix dispatches pointer-down-outside to every open layer at
227-
* once, so a click that should only dismiss an open dropdown /
228-
* select / combobox (portaled into a popper wrapper above this
229-
* modal) would also close the modal. Keep the modal open and let
230-
* the click dismiss just the popper layer. The `data-state="open"`
231-
* filter ignores poppers that are merely animating closed, so a
232-
* follow-up click during the exit animation still dismisses the
233-
* modal.
226+
* Radix dispatches outside-interaction events to every open
227+
* layer at once, so a click that should only dismiss an open
228+
* dropdown / select / combobox (portaled into a popper wrapper
229+
* above this modal) would also close the modal — both via the
230+
* pointer event and via the transient focus shift when the
231+
* popper's focus scope unwinds (`focusOutside`). Worse, the
232+
* modal and the popper tearing down their body pointer-events
233+
* locks in the same tick can leave the page frozen. Keep the
234+
* modal open and let the interaction dismiss just the popper
235+
* layer. The `data-state="open"` filter ignores poppers that
236+
* are merely animating closed, so a follow-up click during the
237+
* exit animation still dismisses the modal.
234238
*/
235239
if (
236240
document.querySelector('[data-radix-popper-content-wrapper] [data-state="open"]')

apps/sim/components/emcn/components/s-modal/s-modal.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ const SModalContent = React.forwardRef<
9595
onPointerUp={(e) => {
9696
e.stopPropagation()
9797
}}
98-
onPointerDownOutside={(e) => {
98+
onInteractOutside={(e) => {
9999
if (!isInteractionReady) {
100100
e.preventDefault()
101101
return
102102
}
103103
/**
104-
* Mirrors ModalContent: an outside click that dismisses an open
105-
* popper layer (dropdown/select/combobox) must not also close the
106-
* modal. See modal.tsx for details.
104+
* Mirrors ModalContent: an outside interaction (pointer or the
105+
* transient focus shift from a closing popper) that dismisses an
106+
* open popper layer must not also close the modal. See modal.tsx.
107107
*/
108108
if (document.querySelector('[data-radix-popper-content-wrapper] [data-state="open"]')) {
109109
e.preventDefault()

0 commit comments

Comments
 (0)