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.
zio/stable
Paul Frazee 2023-08-17 13:39:59 -07:00 committed by GitHub
parent 5e63d3164b
commit 4a59178cd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 15 deletions

View File

@ -70,6 +70,7 @@
"base64-js": "^1.5.1",
"bcp-47-match": "^2.0.3",
"email-validator": "^2.0.4",
"eventemitter3": "^5.0.1",
"expo": "~48.0.18",
"expo-application": "~5.1.1",
"expo-build-properties": "~0.5.1",

View File

@ -151,7 +151,7 @@ export const ComposePost = observer(function ComposePost({
[gallery, track],
)
const onPressPublish = async (rt: RichText) => {
const onPressPublish = async () => {
if (isProcessing || graphemeLength > MAX_GRAPHEME_LENGTH) {
return
}
@ -161,7 +161,7 @@ export const ComposePost = observer(function ComposePost({
setError('')
if (rt.text.trim().length === 0 && gallery.isEmpty) {
if (richtext.text.trim().length === 0 && gallery.isEmpty) {
setError('Did you want to say anything?')
return
}
@ -170,7 +170,7 @@ export const ComposePost = observer(function ComposePost({
try {
await apilib.post(store, {
rawText: rt.text,
rawText: richtext.text,
replyTo: replyTo?.uri,
images: gallery.images,
quote,
@ -245,9 +245,7 @@ export const ComposePost = observer(function ComposePost({
) : canPost ? (
<TouchableOpacity
testID="composerPublishBtn"
onPress={() => {
onPressPublish(richtext)
}}
onPress={onPressPublish}
accessibilityRole="button"
accessibilityLabel={replyTo ? 'Publish reply' : 'Publish post'}
accessibilityHint={

View File

@ -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, () => ({

View File

@ -10150,6 +10150,11 @@ eventemitter3@^4.0.0, eventemitter3@^4.0.4:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
eventemitter3@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
events@3.3.0, events@^3.2.0, events@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"