diff options
Diffstat (limited to 'src/view/com/composer/text-input')
-rw-r--r-- | src/view/com/composer/text-input/web/EmojiPicker.web.tsx | 87 |
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> ) } |