bsky-app/src/screens/Messages/Conversation/MessageInput.web.tsx
Hailey 5343910570
[🐴] 🤞 This should be the final message list change - Use dispatchCommand so we don't need to know the content height (#4090)
* handle keyboard scroll more elegantly

simplify

missing `runOnUI`

better naming to avoid confusion

nit

remove unused function

use `dispatchCommand` in `onContentSizeChanged` as well

use `dispatchCommand` so we don't need to know the content height

remove `isMomentumScrolling`

* better timing

* nit

* another nit

* handle message input resizes better too

* account for other size changes like emoji keyboard opening

* one last nit

* just adding comments

* account for dragging

* make it easier to read

* add a comment

* 🤦‍♀️

* remove a little bit of that padding at the top
2024-05-18 12:29:23 -07:00

129 lines
3.6 KiB
TypeScript

import React from 'react'
import {Pressable, StyleSheet, View} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import Graphemer from 'graphemer'
import TextareaAutosize from 'react-textarea-autosize'
import {MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants'
import {
useMessageDraft,
useSaveMessageDraft,
} from '#/state/messages/message-drafts'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme} from '#/alf'
import {useSharedInputStyles} from '#/components/forms/TextField'
import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane'
export function MessageInput({
onSendMessage,
}: {
onSendMessage: (message: string) => void
}) {
const {_} = useLingui()
const t = useTheme()
const {getDraft, clearDraft} = useMessageDraft()
const [message, setMessage] = React.useState(getDraft)
const inputStyles = useSharedInputStyles()
const [isFocused, setIsFocused] = React.useState(false)
const [isHovered, setIsHovered] = React.useState(false)
const onSubmit = React.useCallback(() => {
if (message.trim() === '') {
return
}
if (new Graphemer().countGraphemes(message) > MAX_DM_GRAPHEME_LENGTH) {
Toast.show(_(msg`Message is too long`))
return
}
clearDraft()
onSendMessage(message.trimEnd())
setMessage('')
}, [message, onSendMessage, _, clearDraft])
const onKeyDown = React.useCallback(
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter') {
if (e.shiftKey) return
e.preventDefault()
onSubmit()
}
},
[onSubmit],
)
const onChange = React.useCallback(
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
setMessage(e.target.value)
},
[],
)
useSaveMessageDraft(message)
return (
<View style={a.p_sm}>
<View
style={[
a.flex_row,
t.atoms.bg_contrast_25,
{
paddingHorizontal: a.p_sm.padding - 2,
paddingLeft: a.p_md.padding - 2,
borderWidth: 2,
borderRadius: 23,
borderColor: 'transparent',
},
isHovered && inputStyles.chromeHover,
isFocused && inputStyles.chromeFocus,
]}
// @ts-expect-error web only
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}>
<TextareaAutosize
style={StyleSheet.flatten([
a.flex_1,
a.px_sm,
a.border_0,
t.atoms.text,
{
paddingTop: 10,
paddingBottom: 12,
backgroundColor: 'transparent',
resize: 'none',
},
])}
maxRows={12}
placeholder={_(msg`Write a message`)}
defaultValue=""
value={message}
dirName="ltr"
autoFocus={true}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
onChange={onChange}
onKeyDown={onKeyDown}
/>
<Pressable
accessibilityRole="button"
accessibilityLabel={_(msg`Send message`)}
accessibilityHint=""
style={[
a.rounded_full,
a.align_center,
a.justify_center,
{
height: 30,
width: 30,
marginTop: 5,
backgroundColor: t.palette.primary_500,
},
]}
onPress={onSubmit}>
<PaperPlane fill={t.palette.white} style={[a.relative, {left: 1}]} />
</Pressable>
</View>
</View>
)
}