[APP-836] Emoji picker for web (#1254)

* add emoji-mart package for emoji dropdown picker

* remove emoji picker modal

* load emoji mart data not as part of the main bundle

* remove @emoji-mart/data

* setup emoji insertion with events

* get emoji data from local static assets

* close emoji picker after one emoji has been inserted

* Switch emoji picker trigger to an icon

* Update emoji-mart-data.js

* make grabbing emoji data work on more browsers

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
Ansh 2023-08-23 16:29:23 -07:00 committed by GitHub
parent 8ab5eb6583
commit 6487a87542
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 136 additions and 12 deletions

View file

@ -16,6 +16,7 @@ import {UserAutocompleteModel} from 'state/models/discovery/user-autocomplete'
import {createSuggestion} from './web/Autocomplete'
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
import {isUriImage, blobToDataUri} from 'lib/media/util'
import {Emoji} from './web/EmojiPicker.web'
export interface TextInputRef {
focus: () => void
@ -34,6 +35,8 @@ interface TextInputProps {
onError: (err: string) => void
}
export const textInputWebEmitter = new EventEmitter()
export const TextInput = React.forwardRef(
(
{
@ -54,21 +57,18 @@ 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)
textInputWebEmitter.addListener('publish', onPressPublish)
return () => {
emitter.removeListener('publish', onPressPublish)
textInputWebEmitter.removeListener('publish', onPressPublish)
}
}, [emitter, onPressPublish])
}, [onPressPublish])
React.useEffect(() => {
emitter.addListener('photo-pasted', onPhotoPasted)
textInputWebEmitter.addListener('photo-pasted', onPhotoPasted)
return () => {
emitter.removeListener('photo-pasted', onPhotoPasted)
textInputWebEmitter.removeListener('photo-pasted', onPhotoPasted)
}
}, [emitter, onPhotoPasted])
}, [onPhotoPasted])
const editor = useEditor(
{
@ -105,12 +105,12 @@ export const TextInput = React.forwardRef(
}
getImageFromUri(items, (uri: string) => {
emitter.emit('photo-pasted', uri)
textInputWebEmitter.emit('photo-pasted', uri)
})
},
handleKeyDown: (_, event) => {
if ((event.metaKey || event.ctrlKey) && event.code === 'Enter') {
emitter.emit('publish')
textInputWebEmitter.emit('publish')
}
},
},
@ -134,9 +134,22 @@ export const TextInput = React.forwardRef(
}
},
},
[modeClass, emitter],
[modeClass],
)
const onEmojiInserted = React.useCallback(
(emoji: Emoji) => {
editor?.chain().focus('end').insertContent(emoji.native).run()
},
[editor],
)
React.useEffect(() => {
textInputWebEmitter.addListener('emoji-inserted', onEmojiInserted)
return () => {
textInputWebEmitter.removeListener('emoji-inserted', onEmojiInserted)
}
}, [onEmojiInserted])
React.useImperativeHandle(ref, () => ({
focus: () => {}, // TODO
blur: () => {}, // TODO