Focus composer input when editable (#10982)
This commit is contained in:
@@ -615,6 +615,8 @@ export function Outer({
|
||||
label?: string
|
||||
style?: StyleProp<ViewStyle>
|
||||
align?: 'left' | 'right'
|
||||
/** Web only. Native restores focus differently. */
|
||||
onCloseAutoFocus?: (event: Event) => void
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const context = useContextMenuContext()
|
||||
|
||||
@@ -34,14 +34,16 @@ export function Outer({
|
||||
children,
|
||||
label,
|
||||
style,
|
||||
onCloseAutoFocus,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
label?: string
|
||||
style?: StyleProp<ViewStyle>
|
||||
onCloseAutoFocus?: (event: Event) => void
|
||||
}) {
|
||||
const t = useTheme()
|
||||
return (
|
||||
<Menu.Outer style={style}>
|
||||
<Menu.Outer style={style} onCloseAutoFocus={onCloseAutoFocus}>
|
||||
{label ? (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
|
||||
@@ -60,6 +60,20 @@ export let MessageContextMenu = ({
|
||||
const langPrefs = useLanguagePrefs()
|
||||
const translate = useGoogleTranslate()
|
||||
|
||||
const onReply = useCallback(() => {
|
||||
setReply(message)
|
||||
}, [setReply, message])
|
||||
// On web, the menu is a Radix dropdown that restores focus to the trigger on
|
||||
// close. When Reply moves focus to the composer, don't let Radix steal it
|
||||
// back. Checking activeElement (rather than tracking reply intent) also
|
||||
// handles re-replying to the same message, where the composer's focus effect
|
||||
// bails on an unchanged reply target and focus should stay on the trigger.
|
||||
const onCloseAutoFocus = useCallback((event: Event) => {
|
||||
if (document.activeElement && document.activeElement !== document.body) {
|
||||
event.preventDefault()
|
||||
}
|
||||
}, [])
|
||||
|
||||
const isFromSelf = message.sender?.did === currentAccount?.did
|
||||
const isGroupChatEnabled = !ax.features.enabled(ax.features.GroupChatsDisable)
|
||||
|
||||
@@ -161,11 +175,12 @@ export let MessageContextMenu = ({
|
||||
label={l`Sent at ${i18n.date(new Date(message.sentAt), {
|
||||
timeStyle: 'short',
|
||||
})}`}
|
||||
style={[isFromSelf && isGroupChatEnabled ? null : a.ml_sm]}>
|
||||
style={[isFromSelf && isGroupChatEnabled ? null : a.ml_sm]}
|
||||
onCloseAutoFocus={onCloseAutoFocus}>
|
||||
<ContextMenu.Item
|
||||
testID="messageDropdownReplyBtn"
|
||||
label={l`Reply`}
|
||||
onPress={() => setReply(message)}>
|
||||
onPress={onReply}>
|
||||
<ContextMenu.ItemIcon icon={ReplyIcon} position="left" />
|
||||
<ContextMenu.ItemText>{l`Reply`}</ContextMenu.ItemText>
|
||||
</ContextMenu.Item>
|
||||
|
||||
@@ -77,6 +77,15 @@ export function MessageComposer({
|
||||
composerInternalApiRef.current?.input?.focus()
|
||||
}, [replyTo, composerInternalApiRef])
|
||||
|
||||
// On web, focus the input once the conversation is ready. The composer also
|
||||
// mounts during the loading state (when it isn't editable), so a mount-time
|
||||
// autoFocus would fire too early to land focus.
|
||||
useEffect(() => {
|
||||
if (IS_WEB && editable) {
|
||||
composerInternalApiRef.current?.input?.focus()
|
||||
}
|
||||
}, [editable, composerInternalApiRef])
|
||||
|
||||
// Android interactive dismiss sometimes doesn't blur the input
|
||||
const blur = useNonReactiveCallback(() => {
|
||||
composerInternalApiRef.current?.input?.blur()
|
||||
@@ -249,7 +258,6 @@ export function MessageComposer({
|
||||
internalApiRef={composerInternalApiRef}
|
||||
defaultValue={text}
|
||||
editable={editable}
|
||||
autoFocus={IS_WEB}
|
||||
maxRows={12}
|
||||
outerStyle={[a.flex_1]}
|
||||
contentTextStyle={[a.text_md, a.leading_snug]}
|
||||
|
||||
Reference in New Issue
Block a user