about summary refs log tree commit diff
path: root/src/screens/Messages/components/MessageInput.web.tsx
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-12-20 13:59:33 -0600
committerGitHub <noreply@github.com>2024-12-20 19:59:33 +0000
commit8116d12c15495fa192e92f5bfb75cb561bb16402 (patch)
treed8291bc888d6423ccb7f242877c9293283156e83 /src/screens/Messages/components/MessageInput.web.tsx
parent8a3dfcb9d0860eb8f8112a84dcf32ae522f77069 (diff)
downloadvoidsky-8116d12c15495fa192e92f5bfb75cb561bb16402.tar.zst
Fix Emoji picker focus (#7217)
* Only portal the emoji picker where needed

* Add optional portal prop to emoji picker

* Use FocusScope to our advantage

* Pare back, add guards, fix focus trap

* Don't return focus to emoji button

* Set DM input position on emoji insert

* Let the caller determine next focus node

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Diffstat (limited to 'src/screens/Messages/components/MessageInput.web.tsx')
-rw-r--r--src/screens/Messages/components/MessageInput.web.tsx28
1 files changed, 22 insertions, 6 deletions
diff --git a/src/screens/Messages/components/MessageInput.web.tsx b/src/screens/Messages/components/MessageInput.web.tsx
index 72e0382a9..bac163685 100644
--- a/src/screens/Messages/components/MessageInput.web.tsx
+++ b/src/screens/Messages/components/MessageInput.web.tsx
@@ -3,6 +3,7 @@ import {Pressable, StyleSheet, View} from 'react-native'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import Graphemer from 'graphemer'
+import {flushSync} from 'react-dom'
 import TextareaAutosize from 'react-textarea-autosize'
 
 import {isSafari, isTouchDevice} from '#/lib/browser'
@@ -106,11 +107,19 @@ export function MessageInput({
 
   const onEmojiInserted = React.useCallback(
     (emoji: Emoji) => {
-      const position = textAreaRef.current?.selectionStart ?? 0
-      setMessage(
-        message =>
-          message.slice(0, position) + emoji.native + message.slice(position),
-      )
+      if (!textAreaRef.current) {
+        return
+      }
+      const position = textAreaRef.current.selectionStart ?? 0
+      textAreaRef.current.focus()
+      flushSync(() => {
+        setMessage(
+          message =>
+            message.slice(0, position) + emoji.native + message.slice(position),
+        )
+      })
+      textAreaRef.current.selectionStart = position + emoji.native.length
+      textAreaRef.current.selectionEnd = position + emoji.native.length
     },
     [setMessage],
   )
@@ -148,7 +157,14 @@ export function MessageInput({
         <Button
           onPress={e => {
             e.currentTarget.measure((_fx, _fy, _width, _height, px, py) => {
-              openEmojiPicker?.({top: py, left: px, right: px, bottom: py})
+              openEmojiPicker?.({
+                top: py,
+                left: px,
+                right: px,
+                bottom: py,
+                nextFocusRef:
+                  textAreaRef as unknown as React.MutableRefObject<HTMLElement>,
+              })
             })
           }}
           style={[