FIx anchorRef handling

This commit is contained in:
Eric Bailey
2026-04-05 16:36:19 -05:00
parent facb0d36d8
commit 274eec8cc2
4 changed files with 20 additions and 17 deletions
+1 -1
View File
@@ -88,7 +88,7 @@
"@bsky.app/expo-image-crop-tool": "^0.5.0", "@bsky.app/expo-image-crop-tool": "^0.5.0",
"@bsky.app/expo-translate-text": "^0.2.9", "@bsky.app/expo-translate-text": "^0.2.9",
"@bsky.app/react-native-mmkv": "2.12.5", "@bsky.app/react-native-mmkv": "2.12.5",
"@bsky.app/sift": "^0.2.8", "@bsky.app/sift": "^0.2.9",
"@bsky.app/tapper": "^0.4.2", "@bsky.app/tapper": "^0.4.2",
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
"@emoji-mart/data": "^1.2.1", "@emoji-mart/data": "^1.2.1",
+10 -6
View File
@@ -69,7 +69,6 @@ export type ComposerInternalApi = {
input?: ReturnType<typeof useTapper>['input'] input?: ReturnType<typeof useTapper>['input']
clear: () => void clear: () => void
insert(text: string): void insert(text: string): void
setAnchorRef(ref: View | null): void
} }
export function useComposerInternalApiRef() { export function useComposerInternalApiRef() {
@@ -91,7 +90,8 @@ export type ComposerProps = Omit<
| 'onSubmitEditing' | 'onSubmitEditing'
> & { > & {
label: string label: string
ref?: React.Ref<TextInput> ref?: React.RefObject<TextInput>
autocompleteAnchorRef?: React.RefObject<View | null>
internalApiRef?: React.Ref<ComposerInternalApi> internalApiRef?: React.Ref<ComposerInternalApi>
outerStyle?: ViewStyleProp['style'] outerStyle?: ViewStyleProp['style']
contentTextStyle?: TextStyleProp['style'] contentTextStyle?: TextStyleProp['style']
@@ -116,6 +116,7 @@ export function Composer({
label, label,
ref, ref,
internalApiRef, internalApiRef,
autocompleteAnchorRef,
outerStyle, outerStyle,
contentTextStyle, contentTextStyle,
contentPaddingStyle, contentPaddingStyle,
@@ -173,13 +174,16 @@ export function Composer({
inputScrollSharedValue.value = 0 inputScrollSharedValue.value = 0
}, },
insert: tapper.insert, insert: tapper.insert,
setAnchorRef: (ref: View | null) => {
sift.refs.setAnchor(ref)
},
}), }),
[tapper.input, tapper.insert, inputScrollSharedValue, sift.refs], [tapper.input, tapper.insert, inputScrollSharedValue],
) )
useEffect(() => {
if (autocompleteAnchorRef) {
sift.refs.setAnchor(autocompleteAnchorRef.current)
}
}, [sift.refs])
/* /*
* Skip the initial mount to avoid an unnecessary re-render — the parent * Skip the initial mount to avoid an unnecessary re-render — the parent
* already knows the initial value since it passed `initialText`. * already knows the initial value since it passed `initialText`.
@@ -1,4 +1,4 @@
import {useCallback, useEffect, useState} from 'react' import {useCallback, useEffect, useRef, useState} from 'react'
import {Pressable, View} from 'react-native' import {Pressable, View} from 'react-native'
import {useLingui} from '@lingui/react/macro' import {useLingui} from '@lingui/react/macro'
import {countGraphemes} from 'unicode-segmenter/grapheme' import {countGraphemes} from 'unicode-segmenter/grapheme'
@@ -46,6 +46,7 @@ export function MessageComposer({
isOpen: false, isOpen: false,
pos: {top: 0, left: 0, right: 0, bottom: 0, nextFocusRef: null}, pos: {top: 0, left: 0, right: 0, bottom: 0, nextFocusRef: null},
}) })
const anchorRef = useRef<View>(null)
const composerInternalApiRef = useComposerInternalApiRef() const composerInternalApiRef = useComposerInternalApiRef()
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
@@ -109,11 +110,8 @@ export function MessageComposer({
{children} {children}
<View <View
ref={node => { collapsable={false}
if (!IS_WEB && node) { ref={IS_WEB ? undefined : anchorRef}
composerInternalApiRef.current?.setAnchorRef(node)
}
}}
// @ts-expect-error web only // @ts-expect-error web only
onMouseEnter={onHoverIn} onMouseEnter={onHoverIn}
onMouseLeave={onHoverOut} onMouseLeave={onHoverOut}
@@ -173,6 +171,7 @@ export function MessageComposer({
label={l`Message input field`} label={l`Message input field`}
placeholder={l`Write a message`} placeholder={l`Write a message`}
autocompletePlacement="top-start" autocompletePlacement="top-start"
autocompleteAnchorRef={anchorRef}
internalApiRef={composerInternalApiRef} internalApiRef={composerInternalApiRef}
defaultValue={text} defaultValue={text}
editable={editable} editable={editable}
+4 -4
View File
@@ -2413,10 +2413,10 @@
resolved "https://registry.yarnpkg.com/@bsky.app/react-native-mmkv/-/react-native-mmkv-2.12.5.tgz#eb17d31a6158c74393f617a1763ac223ff3f83a6" resolved "https://registry.yarnpkg.com/@bsky.app/react-native-mmkv/-/react-native-mmkv-2.12.5.tgz#eb17d31a6158c74393f617a1763ac223ff3f83a6"
integrity sha512-3vUz1nQY1DiKIPAWRkpp5ZGxH5f2G6Ui0UuQuEYjYv81xx1qFcSzS9KQ2sHcOKYdkOM9amWV2Q8TQCxt1lrAHg== integrity sha512-3vUz1nQY1DiKIPAWRkpp5ZGxH5f2G6Ui0UuQuEYjYv81xx1qFcSzS9KQ2sHcOKYdkOM9amWV2Q8TQCxt1lrAHg==
"@bsky.app/sift@^0.2.8": "@bsky.app/sift@^0.2.9":
version "0.2.8" version "0.2.9"
resolved "https://registry.yarnpkg.com/@bsky.app/sift/-/sift-0.2.8.tgz#58cb8ed82e6402061a1e2315a03e1aaec66e6718" resolved "https://registry.yarnpkg.com/@bsky.app/sift/-/sift-0.2.9.tgz#517710b850551846482e68c201750d1dfd549792"
integrity sha512-CVBo0fp8kpSPhiGYO1H0J8aaEREQ87fzoXdL2qaH64GgX+tqFJT9BlS4EvEyhJoyMHdRWinGgTTubf4Gkvcg/Q== integrity sha512-6eQzQ+xKkc0HcGzs96HaadKx+YfaCQwWO52S5VReyxuSii4Xz+bFZ4pjtHnH0NU/lB9W3llMLmjrV+Y5hGozhA==
"@bsky.app/tapper@^0.4.2": "@bsky.app/tapper@^0.4.2":
version "0.4.2" version "0.4.2"