diff --git a/web/src/ui/composer/Autocompleter.tsx b/web/src/ui/composer/Autocompleter.tsx
index f312066..1c510bd 100644
--- a/web/src/ui/composer/Autocompleter.tsx
+++ b/web/src/ui/composer/Autocompleter.tsx
@@ -13,7 +13,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-import { JSX, use, useEffect } from "react"
+import { JSX, RefObject, use, useEffect } from "react"
import { getAvatarURL, getMediaURL } from "@/api/media.ts"
import { RoomStateStore, useCustomEmojis } from "@/api/statestore"
import { Emoji, emojiToMarkdown, useSortedAndFilteredEmojis } from "@/util/emoji"
@@ -37,6 +37,7 @@ export interface AutocompleteQuery {
export interface AutocompleterProps {
setState: (state: Partial) => void
setAutocomplete: (params: AutocompleteQuery | null) => void
+ textInput: RefObject
state: ComposerState
params: AutocompleteQuery
room: RoomStateStore
@@ -52,7 +53,7 @@ interface InnerAutocompleterProps extends AutocompleterProps {
}
function useAutocompleter({
- params, state, setState, setAutocomplete,
+ params, state, setState, setAutocomplete, textInput,
items, getText, getKey, render,
}: InnerAutocompleterProps) {
const onSelect = useEvent((index: number) => {
@@ -61,12 +62,20 @@ function useAutocompleter({
}
index = positiveMod(index, items.length)
const replacementText = getText(items[index])
+ const newText = state.text.slice(0, params.startPos) + replacementText + state.text.slice(params.endPos)
+ const endPos = params.startPos + replacementText.length
+ if (textInput.current) {
+ // React messes up the selection when changing the value for some reason,
+ // so bypass react here to avoid the caret jumping to the end and closing the autocompleter
+ textInput.current.value = newText
+ textInput.current.setSelectionRange(endPos, endPos)
+ }
setState({
- text: state.text.slice(0, params.startPos) + replacementText + state.text.slice(params.endPos),
+ text: newText,
})
setAutocomplete({
...params,
- endPos: params.startPos + replacementText.length,
+ endPos,
frozenQuery: params.frozenQuery ?? params.query,
})
document.querySelector(`div.autocompletion-item[data-index='${index}']`)?.scrollIntoView({ block: "nearest" })
diff --git a/web/src/ui/composer/MessageComposer.tsx b/web/src/ui/composer/MessageComposer.tsx
index e7a42d1..5371e89 100644
--- a/web/src/ui/composer/MessageComposer.tsx
+++ b/web/src/ui/composer/MessageComposer.tsx
@@ -393,6 +393,7 @@ const MessageComposer = () => {
state={state}
setState={setState}
setAutocomplete={setAutocomplete}
+ textInput={textInput}
/>}
{replyToEvt &&