about summary refs log tree commit diff
path: root/src/view/com/composer/text-input/TextInput.web.tsx
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-08-17 13:39:59 -0700
committerGitHub <noreply@github.com>2023-08-17 13:39:59 -0700
commit4a59178cd2d7028e99a977e0ed10193d135e30dd (patch)
treead02636ac1987214843a737df94b48d240427819 /src/view/com/composer/text-input/TextInput.web.tsx
parent5e63d3164b58552f81b597eff83cba991bea958e (diff)
downloadvoidsky-4a59178cd2d7028e99a977e0ed10193d135e30dd.tar.zst
Update the web composer textinput to an emitter (close #1193) (#1205)
The tiptap useEditor() hook creates an awkward challenge for passing
event handlers into its plugins and native events. By introducing a
memoized editor, we should be able to shuttle events out of tiptap
without retriggering the useEditor hook. The emitter can then change
its registered handlers with each state update.
Diffstat (limited to 'src/view/com/composer/text-input/TextInput.web.tsx')
-rw-r--r--src/view/com/composer/text-input/TextInput.web.tsx31
1 files changed, 22 insertions, 9 deletions
diff --git a/src/view/com/composer/text-input/TextInput.web.tsx b/src/view/com/composer/text-input/TextInput.web.tsx
index 152bb50ea..f64880e15 100644
--- a/src/view/com/composer/text-input/TextInput.web.tsx
+++ b/src/view/com/composer/text-input/TextInput.web.tsx
@@ -1,6 +1,7 @@
 import React from 'react'
 import {StyleSheet, View} from 'react-native'
 import {RichText} from '@atproto/api'
+import EventEmitter from 'eventemitter3'
 import {useEditor, EditorContent, JSONContent} from '@tiptap/react'
 import {Document} from '@tiptap/extension-document'
 import History from '@tiptap/extension-history'
@@ -53,6 +54,22 @@ export const TextInput = React.forwardRef(
       'ProseMirror-dark',
     )
 
+    // we use a memoized emitter to propagate events out of tiptap
+    // without triggering re-runs of the useEditor hook
+    const emitter = React.useMemo(() => new EventEmitter(), [])
+    React.useEffect(() => {
+      emitter.addListener('publish', onPressPublish)
+      return () => {
+        emitter.removeListener('publish', onPressPublish)
+      }
+    }, [emitter, onPressPublish])
+    React.useEffect(() => {
+      emitter.addListener('photo-pasted', onPhotoPasted)
+      return () => {
+        emitter.removeListener('photo-pasted', onPhotoPasted)
+      }
+    }, [emitter, onPhotoPasted])
+
     const editor = useEditor(
       {
         extensions: [
@@ -87,17 +104,13 @@ export const TextInput = React.forwardRef(
               return
             }
 
-            getImageFromUri(items, onPhotoPasted)
+            getImageFromUri(items, (uri: string) => {
+              emitter.emit('photo-pasted', uri)
+            })
           },
           handleKeyDown: (_, event) => {
             if ((event.metaKey || event.ctrlKey) && event.code === 'Enter') {
-              // Workaround relying on previous state from `setRichText` to
-              // get the updated text content during editor initialization
-              setRichText((state: RichText) => {
-                onPressPublish(state)
-                return state
-              })
-              return true
+              emitter.emit('publish')
             }
           },
         },
@@ -118,7 +131,7 @@ export const TextInput = React.forwardRef(
           }
         },
       },
-      [modeClass],
+      [modeClass, emitter],
     )
 
     React.useImperativeHandle(ref, () => ({