From fc82d2f6d5e8a93f0e7ce4861c5205c8a4b49c30 Mon Sep 17 00:00:00 2001
From: Samuel Newman <mozzius@protonmail.com>
Date: Tue, 8 Oct 2024 20:00:49 +0300
Subject: Move Dialogs to Radix (#5648)

* Use Redix FocusTrap (#5638)

* Use Redix FocusTrap

* force resolutions on radix libs

* add focus guards

* use @radix-ui/dismissable-layer for escape handling

* fix banner menu keypress by using `Pressable`

* add menu in dialog example to storybook

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

* use DismissableLayer/FocusScope for composer

* fix storybook dialog

* thread Portal through Prompt and avatar/banner

* fix dialog style regression

* remove tamagui

---------

Co-authored-by: Eric Bailey <git@esb.lol>
---
 src/components/Dialog/index.web.tsx | 36 ++++++++++++++++--------------------
 1 file changed, 16 insertions(+), 20 deletions(-)

(limited to 'src/components/Dialog/index.web.tsx')

diff --git a/src/components/Dialog/index.web.tsx b/src/components/Dialog/index.web.tsx
index 7b9cfb693..1a20311d3 100644
--- a/src/components/Dialog/index.web.tsx
+++ b/src/components/Dialog/index.web.tsx
@@ -10,7 +10,9 @@ import {
 import Animated, {FadeIn, FadeInDown} from 'react-native-reanimated'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
-import {FocusScope} from '@tamagui/focus-scope'
+import {DismissableLayer} from '@radix-ui/react-dismissable-layer'
+import {useFocusGuards} from '@radix-ui/react-focus-guards'
+import {FocusScope} from '@radix-ui/react-focus-scope'
 
 import {logger} from '#/logger'
 import {useDialogStateControlContext} from '#/state/dialogs'
@@ -31,6 +33,7 @@ export * from '#/components/Dialog/utils'
 export {Input} from '#/components/forms/TextField'
 
 const stopPropagation = (e: any) => e.stopPropagation()
+const preventDefault = (e: any) => e.preventDefault()
 
 export function Outer({
   children,
@@ -85,21 +88,6 @@ export function Outer({
     [close, open],
   )
 
-  React.useEffect(() => {
-    if (!isOpen) return
-
-    function handler(e: KeyboardEvent) {
-      if (e.key === 'Escape') {
-        e.stopPropagation()
-        close()
-      }
-    }
-
-    document.addEventListener('keydown', handler)
-
-    return () => document.removeEventListener('keydown', handler)
-  }, [close, isOpen])
-
   const context = React.useMemo(
     () => ({
       close,
@@ -168,9 +156,11 @@ export function Inner({
   accessibilityDescribedBy,
 }: DialogInnerProps) {
   const t = useTheme()
+  const {close} = React.useContext(Context)
   const {gtMobile} = useBreakpoints()
+  useFocusGuards()
   return (
-    <FocusScope loop enabled trapped>
+    <FocusScope loop asChild trapped>
       <Animated.View
         role="dialog"
         aria-role="dialog"
@@ -183,7 +173,7 @@ export function Inner({
         onTouchEnd={stopPropagation}
         entering={FadeInDown.duration(100)}
         // exiting={FadeOut.duration(100)}
-        style={[
+        style={flatten([
           a.relative,
           a.rounded_md,
           a.w_full,
@@ -198,8 +188,14 @@ export function Inner({
             shadowRadius: 30,
           },
           flatten(style),
-        ]}>
-        {children}
+        ])}>
+        <DismissableLayer
+          onInteractOutside={preventDefault}
+          onFocusOutside={preventDefault}
+          onDismiss={close}
+          style={{display: 'flex', flexDirection: 'column'}}>
+          {children}
+        </DismissableLayer>
       </Animated.View>
     </FocusScope>
   )
-- 
cgit 1.4.1

