about summary refs log tree commit diff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/Dialog/index.web.tsx36
-rw-r--r--src/components/Menu/index.tsx9
-rw-r--r--src/components/Prompt.tsx9
-rw-r--r--src/components/dialogs/GifSelect.tsx6
4 files changed, 33 insertions, 27 deletions
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>
   )
diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx
index a22f43cf8..12cf1866e 100644
--- a/src/components/Menu/index.tsx
+++ b/src/components/Menu/index.tsx
@@ -18,6 +18,7 @@ import {
   ItemTextProps,
   TriggerProps,
 } from '#/components/Menu/types'
+import {PortalComponent} from '#/components/Portal'
 import {Text} from '#/components/Typography'
 
 export {
@@ -77,9 +78,11 @@ export function Trigger({children, label}: TriggerProps) {
 export function Outer({
   children,
   showCancel,
+  Portal,
 }: React.PropsWithChildren<{
   showCancel?: boolean
   style?: StyleProp<ViewStyle>
+  Portal?: PortalComponent
 }>) {
   const context = React.useContext(Context)
   const {_} = useLingui()
@@ -87,15 +90,15 @@ export function Outer({
   return (
     <Dialog.Outer
       control={context.control}
-      nativeOptions={{preventExpansion: true}}>
+      nativeOptions={{preventExpansion: true}}
+      Portal={Portal}>
       <Dialog.Handle />
       {/* Re-wrap with context since Dialogs are portal-ed to root */}
       <Context.Provider value={context}>
-        <Dialog.ScrollableInner label={_(msg`Menu`)} style={[a.pt_sm]}>
+        <Dialog.ScrollableInner label={_(msg`Menu`)} style={[a.py_sm]}>
           <View style={[a.gap_lg]}>
             {children}
             {isNative && showCancel && <Cancel />}
-            <View style={[{height: a.pb_lg.paddingBottom}]} />
           </View>
         </Dialog.ScrollableInner>
       </Context.Provider>
diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx
index fc6919af8..c47f0d64a 100644
--- a/src/components/Prompt.tsx
+++ b/src/components/Prompt.tsx
@@ -8,6 +8,7 @@ import {Button, ButtonColor, ButtonText} from '#/components/Button'
 import * as Dialog from '#/components/Dialog'
 import {PortalComponent} from '#/components/Portal'
 import {Text} from '#/components/Typography'
+import {BottomSheetViewProps} from '../../modules/bottom-sheet'
 
 export {
   type DialogControlProps as PromptControlProps,
@@ -27,10 +28,12 @@ export function Outer({
   control,
   testID,
   Portal,
+  nativeOptions,
 }: React.PropsWithChildren<{
   control: Dialog.DialogControlProps
   testID?: string
   Portal?: PortalComponent
+  nativeOptions?: Omit<BottomSheetViewProps, 'children'>
 }>) {
   const {gtMobile} = useBreakpoints()
   const titleId = React.useId()
@@ -42,7 +45,11 @@ export function Outer({
   )
 
   return (
-    <Dialog.Outer control={control} testID={testID} Portal={Portal}>
+    <Dialog.Outer
+      control={control}
+      testID={testID}
+      Portal={Portal}
+      nativeOptions={{preventExpansion: true, ...nativeOptions}}>
       <Dialog.Handle />
       <Context.Provider value={context}>
         <Dialog.ScrollableInner
diff --git a/src/components/dialogs/GifSelect.tsx b/src/components/dialogs/GifSelect.tsx
index 6023b5808..c0ed202da 100644
--- a/src/components/dialogs/GifSelect.tsx
+++ b/src/components/dialogs/GifSelect.tsx
@@ -23,14 +23,14 @@ import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
 import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
 import {ListMethods} from '#/view/com/util/List'
 import {atoms as a, ios, native, useBreakpoints, useTheme} from '#/alf'
+import {Button, ButtonIcon, ButtonText} from '#/components/Button'
 import * as Dialog from '#/components/Dialog'
 import * as TextField from '#/components/forms/TextField'
 import {useThrottledValue} from '#/components/hooks/useThrottledValue'
 import {ArrowLeft_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow'
 import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2'
-import {Button, ButtonIcon, ButtonText} from '../Button'
-import {ListFooter, ListMaybePlaceholder} from '../Lists'
-import {PortalComponent} from '../Portal'
+import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
+import {PortalComponent} from '#/components/Portal'
 
 export function GifSelectDialog({
   controlRef,