about summary refs log tree commit diff
path: root/src/view/com/composer/text-input/web/EmojiPicker.web.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/composer/text-input/web/EmojiPicker.web.tsx')
-rw-r--r--src/view/com/composer/text-input/web/EmojiPicker.web.tsx87
1 files changed, 51 insertions, 36 deletions
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 c72172902..f5e6a987c 100644
--- a/src/view/com/composer/text-input/web/EmojiPicker.web.tsx
+++ b/src/view/com/composer/text-input/web/EmojiPicker.web.tsx
@@ -1,15 +1,13 @@
 import React from 'react'
-import {
-  GestureResponderEvent,
-  TouchableWithoutFeedback,
-  useWindowDimensions,
-  View,
-} from 'react-native'
+import {Pressable, useWindowDimensions, View} from 'react-native'
 import Picker from '@emoji-mart/react'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 import {DismissableLayer} from '@radix-ui/react-dismissable-layer'
+import {FocusScope} from '@radix-ui/react-focus-scope'
 
 import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEmitter'
-import {atoms as a} from '#/alf'
+import {atoms as a, flatten} from '#/alf'
 import {Portal} from '#/components/Portal'
 
 const HEIGHT_OFFSET = 40
@@ -33,6 +31,7 @@ export interface EmojiPickerPosition {
   left: number
   right: number
   bottom: number
+  nextFocusRef: React.MutableRefObject<HTMLElement> | null
 }
 
 export interface EmojiPickerState {
@@ -51,6 +50,7 @@ interface IProps {
 }
 
 export function EmojiPicker({state, close, pinToTop}: IProps) {
+  const {_} = useLingui()
   const {height, width} = useWindowDimensions()
 
   const isShiftDown = React.useRef(false)
@@ -119,48 +119,63 @@ export function EmojiPicker({state, close, pinToTop}: IProps) {
 
   if (!state.isOpen) return null
 
-  const onPressBackdrop = (e: GestureResponderEvent) => {
-    // @ts-ignore web only
-    if (e.nativeEvent?.pointerId === -1) return
-    close()
-  }
-
   return (
     <Portal>
-      <TouchableWithoutFeedback
-        accessibilityRole="button"
-        onPress={onPressBackdrop}
-        accessibilityViewIsModal>
+      <FocusScope
+        loop
+        trapped
+        onUnmountAutoFocus={e => {
+          const nextFocusRef = state.pos.nextFocusRef
+          const node = nextFocusRef?.current
+          if (node) {
+            e.preventDefault()
+            node.focus()
+          }
+        }}>
+        <Pressable
+          accessible
+          accessibilityLabel={_(msg`Close emoji picker`)}
+          accessibilityHint={_(msg`Tap to close the emoji picker`)}
+          onPress={close}
+          style={[a.fixed, a.inset_0]}
+        />
+
         <View
-          style={[
+          style={flatten([
             a.fixed,
             a.w_full,
             a.h_full,
             a.align_center,
+            a.z_10,
             {
               top: 0,
               left: 0,
               right: 0,
             },
-          ]}>
-          {/* eslint-disable-next-line react-native-a11y/has-valid-accessibility-descriptors */}
-          <TouchableWithoutFeedback onPress={e => e.stopPropagation()}>
-            <View style={[{position: 'absolute'}, position]}>
-              <DismissableLayer
-                onFocusOutside={evt => evt.preventDefault()}
-                onDismiss={close}>
-                <Picker
-                  data={async () => {
-                    return (await import('./EmojiPickerData.json')).default
-                  }}
-                  onEmojiSelect={onInsert}
-                  autoFocus={true}
-                />
-              </DismissableLayer>
-            </View>
-          </TouchableWithoutFeedback>
+          ])}>
+          <View style={[{position: 'absolute'}, position]}>
+            <DismissableLayer
+              onFocusOutside={evt => evt.preventDefault()}
+              onDismiss={close}>
+              <Picker
+                data={async () => {
+                  return (await import('./EmojiPickerData.json')).default
+                }}
+                onEmojiSelect={onInsert}
+                autoFocus={true}
+              />
+            </DismissableLayer>
+          </View>
         </View>
-      </TouchableWithoutFeedback>
+
+        <Pressable
+          accessible
+          accessibilityLabel={_(msg`Close emoji picker`)}
+          accessibilityHint={_(msg`Tap to close the emoji picker`)}
+          onPress={close}
+          style={[a.fixed, a.inset_0]}
+        />
+      </FocusScope>
     </Portal>
   )
 }