diff --git a/src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx b/src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx index 18532b280..61a587e26 100644 --- a/src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx +++ b/src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx @@ -20,9 +20,9 @@ import { useAtomValue } from 'jotai'; import { nicknamesAtom } from '$state/nicknames'; import { createMentionElement, + mentionNameForUserAutocomplete, moveCursor, replaceWithElement, - resolveUserMentionName, } from '$components/editor/utils'; import { getMxIdServer } from '$utils/mxIdHelper'; import { AutocompleteMenu } from './AutocompleteMenu'; @@ -115,11 +115,13 @@ export function UserMentionAutocomplete({ else resetSearch(); }, [query.text, search, resetSearch]); - const handleAutocomplete: MentionAutoCompleteHandler = (uId) => { + const handleAutocomplete: MentionAutoCompleteHandler = (id, displayName) => { + const isRoomPing = displayName === '@room'; + const isCurrentRoom = roomId === id || room.getCanonicalAlias() === id || roomAliasOrId === id; const mentionEl = createMentionElement( - uId, - resolveUserMentionName(uId, { room, nicknames }), - mx.getUserId() === uId || roomAliasOrId === uId + id, + mentionNameForUserAutocomplete(id, displayName, { room, nicknames }), + isRoomPing ? isCurrentRoom : mx.getUserId() === id || isCurrentRoom ); replaceWithElement(editor, query.range, mentionEl); moveCursor(editor, true); diff --git a/src/app/components/editor/mentionResolve.test.ts b/src/app/components/editor/mentionResolve.test.ts index 925e835f7..24595efec 100644 --- a/src/app/components/editor/mentionResolve.test.ts +++ b/src/app/components/editor/mentionResolve.test.ts @@ -3,6 +3,7 @@ import type { Room } from '$types/matrix-sdk'; import { formatMentionElementDisplayName, formatUserMentionDisplayName, + mentionNameForUserAutocomplete, resolveUserMentionName, } from './utils'; import { BlockType } from './types'; @@ -34,4 +35,11 @@ describe('mention resolve', () => { it('formatUserMentionDisplayName is idempotent for names that already include @', () => { expect(formatUserMentionDisplayName('@Alice')).toBe('@Alice'); }); + + it('mentionNameForUserAutocomplete keeps @room for room pings', () => { + expect(mentionNameForUserAutocomplete('!room:example.org', '@room')).toBe('@room'); + expect(mentionNameForUserAutocomplete('!room:example.org', '@room')).not.toBe( + '@!room:example.org' + ); + }); }); diff --git a/src/app/components/editor/utils.ts b/src/app/components/editor/utils.ts index bc228dc2d..a50420acf 100644 --- a/src/app/components/editor/utils.ts +++ b/src/app/components/editor/utils.ts @@ -31,6 +31,16 @@ export const resolveUserMentionName = (userId: string, options?: MentionResolveO return formatUserMentionDisplayName(base); }; +/** {@link UserMentionAutocomplete} passes a display label, @room must stay literal, not resolved as a user. */ +export const mentionNameForUserAutocomplete = ( + id: string, + displayName: string, + options?: MentionResolveOptions +): string => { + if (displayName === '@room') return '@room'; + return resolveUserMentionName(id, options); +}; + /** Same #-prefix rule as {@link RoomMentionAutocomplete}. */ export const formatRoomMentionDisplayName = (name: string): string => { if (name === '@room') return '@room';