about summary refs log tree commit diff
path: root/src/view/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com')
-rw-r--r--src/view/com/composer/Composer.tsx18
-rw-r--r--src/view/com/composer/text-input/web/EmojiPicker.web.tsx19
-rw-r--r--src/view/com/util/UserAvatar.tsx14
-rw-r--r--src/view/com/util/UserBanner.tsx16
4 files changed, 27 insertions, 40 deletions
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index 55c2d81ab..8cc8fba0d 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -65,7 +65,6 @@ import {useDialogStateControlContext} from '#/state/dialogs'
 import {emitPostCreated} from '#/state/events'
 import {ComposerImage, pasteImage} from '#/state/gallery'
 import {useModalControls} from '#/state/modals'
-import {useModals} from '#/state/modals'
 import {useRequireAltTextEnabled} from '#/state/preferences'
 import {
   toPostLanguages,
@@ -146,7 +145,6 @@ export const ComposePost = ({
   const queryClient = useQueryClient()
   const currentDid = currentAccount!.did
   const {data: currentProfile} = useProfileQuery({did: currentDid})
-  const {isModalActive} = useModals()
   const {closeComposer} = useComposerControls()
   const pal = usePalette('default')
   const {isMobile} = useWebMediaQueries()
@@ -303,22 +301,6 @@ export const ComposePost = ({
     }
   }, [onPressCancel, closeAllDialogs, closeAllModals])
 
-  // listen to escape key on desktop web
-  const onEscape = useCallback(
-    (e: KeyboardEvent) => {
-      if (e.key === 'Escape') {
-        onPressCancel()
-      }
-    },
-    [onPressCancel],
-  )
-  useEffect(() => {
-    if (isWeb && !isModalActive) {
-      window.addEventListener('keydown', onEscape)
-      return () => window.removeEventListener('keydown', onEscape)
-    }
-  }, [onEscape, isModalActive])
-
   const onNewLink = useCallback((uri: string) => {
     dispatch({type: 'embed_add_uri', uri})
   }, [])
diff --git a/src/view/com/composer/text-input/web/EmojiPicker.web.tsx b/src/view/com/composer/text-input/web/EmojiPicker.web.tsx
index ad3bb30ec..1d5dad486 100644
--- a/src/view/com/composer/text-input/web/EmojiPicker.web.tsx
+++ b/src/view/com/composer/text-input/web/EmojiPicker.web.tsx
@@ -6,6 +6,7 @@ import {
   View,
 } from 'react-native'
 import Picker from '@emoji-mart/react'
+import {DismissableLayer} from '@radix-ui/react-dismissable-layer'
 
 import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEmitter'
 import {atoms as a} from '#/alf'
@@ -143,13 +144,17 @@ export function EmojiPicker({state, close, pinToTop}: IProps) {
         {/* eslint-disable-next-line react-native-a11y/has-valid-accessibility-descriptors */}
         <TouchableWithoutFeedback onPress={e => e.stopPropagation()}>
           <View style={[{position: 'absolute'}, position]}>
-            <Picker
-              data={async () => {
-                return (await import('./EmojiPickerData.json')).default
-              }}
-              onEmojiSelect={onInsert}
-              autoFocus={true}
-            />
+            <DismissableLayer
+              onFocusOutside={evt => evt.preventDefault()}
+              onDismiss={close}>
+              <Picker
+                data={async () => {
+                  return (await import('./EmojiPickerData.json')).default
+                }}
+                onEmojiSelect={onInsert}
+                autoFocus={true}
+              />
+            </DismissableLayer>
           </View>
         </TouchableWithoutFeedback>
       </View>
diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx
index 43555ccb4..b311f7887 100644
--- a/src/view/com/util/UserAvatar.tsx
+++ b/src/view/com/util/UserAvatar.tsx
@@ -1,5 +1,5 @@
 import React, {memo, useMemo} from 'react'
-import {Image, StyleSheet, TouchableOpacity, View} from 'react-native'
+import {Image, Pressable, StyleSheet, View} from 'react-native'
 import {Image as RNImage} from 'react-native-image-crop-picker'
 import Svg, {Circle, Path, Rect} from 'react-native-svg'
 import {AppBskyActorDefs, ModerationUI} from '@atproto/api'
@@ -30,6 +30,7 @@ import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
 import {Link} from '#/components/Link'
 import {MediaInsetBorder} from '#/components/MediaInsetBorder'
 import * as Menu from '#/components/Menu'
+import {PortalComponent} from '#/components/Portal'
 import {ProfileHoverCard} from '#/components/ProfileHoverCard'
 import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
 
@@ -50,6 +51,7 @@ interface UserAvatarProps extends BaseUserAvatarProps {
 
 interface EditableUserAvatarProps extends BaseUserAvatarProps {
   onSelectNewAvatar: (img: RNImage | null) => void
+  Portal?: PortalComponent
 }
 
 interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
@@ -266,6 +268,7 @@ let EditableUserAvatar = ({
   size,
   avatar,
   onSelectNewAvatar,
+  Portal,
 }: EditableUserAvatarProps): React.ReactNode => {
   const t = useTheme()
   const pal = usePalette('default')
@@ -346,10 +349,7 @@ let EditableUserAvatar = ({
     <Menu.Root>
       <Menu.Trigger label={_(msg`Edit avatar`)}>
         {({props}) => (
-          <TouchableOpacity
-            {...props}
-            activeOpacity={0.8}
-            testID="changeAvatarBtn">
+          <Pressable {...props} testID="changeAvatarBtn">
             {avatar ? (
               <HighPriorityImage
                 testID="userAvatarImage"
@@ -363,10 +363,10 @@ let EditableUserAvatar = ({
             <View style={[styles.editButtonContainer, pal.btn]}>
               <CameraFilled height={14} width={14} style={t.atoms.text} />
             </View>
-          </TouchableOpacity>
+          </Pressable>
         )}
       </Menu.Trigger>
-      <Menu.Outer showCancel>
+      <Menu.Outer showCancel Portal={Portal}>
         <Menu.Group>
           {isNative && (
             <Menu.Item
diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx
index 622cb2129..98ff19b5d 100644
--- a/src/view/com/util/UserBanner.tsx
+++ b/src/view/com/util/UserBanner.tsx
@@ -1,5 +1,5 @@
 import React from 'react'
-import {StyleSheet, TouchableOpacity, View} from 'react-native'
+import {Pressable, StyleSheet, View} from 'react-native'
 import {Image as RNImage} from 'react-native-image-crop-picker'
 import {Image} from 'expo-image'
 import {ModerationUI} from '@atproto/api'
@@ -25,6 +25,7 @@ import {
 import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive'
 import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
 import * as Menu from '#/components/Menu'
+import {PortalComponent} from '#/components/Portal'
 import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
 
 export function UserBanner({
@@ -32,11 +33,13 @@ export function UserBanner({
   banner,
   moderation,
   onSelectNewBanner,
+  Portal,
 }: {
   type?: 'labeler' | 'default'
   banner?: string | null
   moderation?: ModerationUI
   onSelectNewBanner?: (img: RNImage | null) => void
+  Portal?: PortalComponent
 }) {
   const pal = usePalette('default')
   const theme = useTheme()
@@ -90,14 +93,11 @@ export function UserBanner({
 
   // setUserBanner is only passed as prop on the EditProfile component
   return onSelectNewBanner ? (
-    <EventStopper onKeyDown={false}>
+    <EventStopper onKeyDown={true}>
       <Menu.Root>
         <Menu.Trigger label={_(msg`Edit avatar`)}>
           {({props}) => (
-            <TouchableOpacity
-              {...props}
-              activeOpacity={0.8}
-              testID="changeBannerBtn">
+            <Pressable {...props} testID="changeBannerBtn">
               {banner ? (
                 <Image
                   testID="userBannerImage"
@@ -115,10 +115,10 @@ export function UserBanner({
               <View style={[styles.editButtonContainer, pal.btn]}>
                 <CameraFilled height={14} width={14} style={t.atoms.text} />
               </View>
-            </TouchableOpacity>
+            </Pressable>
           )}
         </Menu.Trigger>
-        <Menu.Outer showCancel>
+        <Menu.Outer showCancel Portal={Portal}>
           <Menu.Group>
             {isNative && (
               <Menu.Item