From c1dc0b7ee0f15134578d50a3d344ab4bdad1119f Mon Sep 17 00:00:00 2001
From: Hailey <153161762+haileyok@users.noreply.github.com>
Date: Tue, 2 Jan 2024 12:16:28 -0800
Subject: emoji picker improvements (#2392)
* rework emoji picker
* dynamic position
* always prefer the left if it will fit
* add accessibility label
* Update EmojiPicker.web.tsx
oops. remove accessibility from fake button
---
.../composer/text-input/web/EmojiPicker.web.tsx | 140 ++++++++++++---------
1 file changed, 83 insertions(+), 57 deletions(-)
(limited to 'src/view/com/composer/text-input/web/EmojiPicker.web.tsx')
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 f4b2d99b0..6d16403ff 100644
--- a/src/view/com/composer/text-input/web/EmojiPicker.web.tsx
+++ b/src/view/com/composer/text-input/web/EmojiPicker.web.tsx
@@ -1,11 +1,17 @@
import React from 'react'
import Picker from '@emoji-mart/react'
-import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native'
-import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
+import {
+ StyleSheet,
+ TouchableWithoutFeedback,
+ useWindowDimensions,
+ View,
+} from 'react-native'
import {textInputWebEmitter} from '../TextInput.web'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useMediaQuery} from 'react-responsive'
+
+const HEIGHT_OFFSET = 40
+const WIDTH_OFFSET = 100
+const PICKER_HEIGHT = 435 + HEIGHT_OFFSET
+const PICKER_WIDTH = 350 + WIDTH_OFFSET
export type Emoji = {
aliases?: string[]
@@ -18,59 +24,87 @@ export type Emoji = {
unified: string
}
-export function EmojiPickerButton() {
- const pal = usePalette('default')
- const [open, setOpen] = React.useState(false)
- const onOpenChange = (o: boolean) => {
- setOpen(o)
- }
- const close = () => {
- setOpen(false)
- }
+export interface EmojiPickerState {
+ isOpen: boolean
+ pos: {top: number; left: number; right: number; bottom: number}
+}
- return (
-
-
-
-
-
-
-
-
-
- )
+interface IProps {
+ state: EmojiPickerState
+ close: () => void
}
-export function EmojiPicker({close}: {close: () => void}) {
+export function EmojiPicker({state, close}: IProps) {
+ const {height, width} = useWindowDimensions()
+
+ const isShiftDown = React.useRef(false)
+
+ const position = React.useMemo(() => {
+ const fitsBelow = state.pos.top + PICKER_HEIGHT < height
+ const fitsAbove = PICKER_HEIGHT < state.pos.top
+ const placeOnLeft = PICKER_WIDTH < state.pos.left
+ const screenYMiddle = height / 2 - PICKER_HEIGHT / 2
+
+ if (fitsBelow) {
+ return {
+ top: state.pos.top + HEIGHT_OFFSET,
+ }
+ } else if (fitsAbove) {
+ return {
+ bottom: height - state.pos.bottom + HEIGHT_OFFSET,
+ }
+ } else {
+ return {
+ top: screenYMiddle,
+ left: placeOnLeft ? state.pos.left - PICKER_WIDTH : undefined,
+ right: !placeOnLeft
+ ? width - state.pos.right - PICKER_WIDTH
+ : undefined,
+ }
+ }
+ }, [state.pos, height, width])
+
+ React.useEffect(() => {
+ if (!state.isOpen) return
+
+ const onKeyDown = (e: KeyboardEvent) => {
+ if (e.key === 'Shift') {
+ isShiftDown.current = true
+ }
+ }
+ const onKeyUp = (e: KeyboardEvent) => {
+ if (e.key === 'Shift') {
+ isShiftDown.current = false
+ }
+ }
+ window.addEventListener('keydown', onKeyDown, true)
+ window.addEventListener('keyup', onKeyUp, true)
+
+ return () => {
+ window.removeEventListener('keydown', onKeyDown, true)
+ window.removeEventListener('keyup', onKeyUp, true)
+ }
+ }, [state.isOpen])
+
const onInsert = (emoji: Emoji) => {
textInputWebEmitter.emit('emoji-inserted', emoji)
- close()
+
+ if (!isShiftDown.current) {
+ close()
+ }
}
- const reducedPadding = useMediaQuery({query: '(max-height: 750px)'})
- const noPadding = useMediaQuery({query: '(max-height: 550px)'})
- const noPicker = useMediaQuery({query: '(max-height: 350px)'})
+
+ if (!state.isOpen) return null
return (
- // eslint-disable-next-line react-native-a11y/has-valid-accessibility-descriptors
-
+
{/* eslint-disable-next-line react-native-a11y/has-valid-accessibility-descriptors */}
- {
- e.stopPropagation() // prevent event from bubbling up to the mask
- }}>
-
+ e.stopPropagation()}>
+
{
return (await import('./EmojiPickerData.json')).default
@@ -93,15 +127,7 @@ const styles = StyleSheet.create({
right: 0,
width: '100%',
height: '100%',
- },
- trigger: {
- backgroundColor: 'transparent',
- // @ts-ignore web only -prf
- border: 'none',
- paddingTop: 4,
- paddingLeft: 12,
- paddingRight: 12,
- cursor: 'pointer',
+ alignItems: 'center',
},
picker: {
marginHorizontal: 'auto',
--
cgit 1.4.1