From f5798d73de6fdb148f7f7737de5a131e8ff11e56 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Thu, 10 Sep 2026 19:17:45 +0530 Subject: [PATCH] fix: allow channel, user and emoji autocomplete after slash command --- .../MessageComposer/MessageComposer.test.tsx | 29 +++++++++++++++++ .../components/ComposerInput.tsx | 32 +++++++++---------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/app/containers/MessageComposer/MessageComposer.test.tsx b/app/containers/MessageComposer/MessageComposer.test.tsx index 8a15b8a2472..5cc4eb5dc0d 100644 --- a/app/containers/MessageComposer/MessageComposer.test.tsx +++ b/app/containers/MessageComposer/MessageComposer.test.tsx @@ -572,6 +572,35 @@ describe('MessageComposer', () => { expect(onSendMessage).toHaveBeenCalledWith('#general', false); }); + test('typing # after a slash command opens channel autocomplete', async () => { + const onSendMessage = jest.fn(); + (searchRemote as unknown as jest.Mock).mockImplementationOnce(() => [{ rid: 'r1', name: 'general', t: 'c' }]); + render(); + + await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); + await fireEvent.changeText(screen.getByTestId('message-composer-input'), '/hello #'); + await fireEvent(screen.getByTestId('message-composer-input'), 'selectionChange', { + nativeEvent: { selection: { start: 8, end: 8 } } + }); + await advanceComposerTimers(); + + await waitFor(() => expect(screen.getByTestId('autocomplete-item-general')).toBeOnTheScreen()); + }); + + test('typing @ after a slash command opens user autocomplete', async () => { + const onSendMessage = jest.fn(); + render(); + + await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); + await fireEvent.changeText(screen.getByTestId('message-composer-input'), '/hello @'); + await fireEvent(screen.getByTestId('message-composer-input'), 'selectionChange', { + nativeEvent: { selection: { start: 8, end: 8 } } + }); + await advanceComposerTimers(); + + await waitFor(() => expect(screen.getByTestId('autocomplete-item-John')).toBeOnTheScreen()); + }); + test('select : emoji inserts emoji and sends, autocomplete hides', async () => { const onSendMessage = jest.fn(); render(); diff --git a/app/containers/MessageComposer/components/ComposerInput.tsx b/app/containers/MessageComposer/components/ComposerInput.tsx index a0547bab0a6..33da53c9e6e 100644 --- a/app/containers/MessageComposer/components/ComposerInput.tsx +++ b/app/containers/MessageComposer/components/ComposerInput.tsx @@ -325,6 +325,22 @@ export const ComposerInput = memo( stopAutocomplete(); return; } + if (lastWord.match(/^#/)) { + setAutocompleteParams({ text: autocompleteText, type: '#' }); + return; + } + if (lastWord.match(/^@/)) { + setAutocompleteParams({ text: autocompleteText, type: '@' }); + return; + } + if (lastWord.match(/^:/)) { + setAutocompleteParams({ text: autocompleteText, type: ':' }); + return; + } + if (lastWord.match(/^!/) && room?.t === 'l') { + setAutocompleteParams({ text: autocompleteText, type: '!' }); + return; + } if (!sharing && text.match(/^\//)) { const commandParameter = text.match(/^\/([a-z0-9._-]+) (.+)/im); if (commandParameter) { @@ -344,22 +360,6 @@ export const ComposerInput = memo( setAutocompleteParams({ text: autocompleteText, type: '/' }); return; } - if (lastWord.match(/^#/)) { - setAutocompleteParams({ text: autocompleteText, type: '#' }); - return; - } - if (lastWord.match(/^@/)) { - setAutocompleteParams({ text: autocompleteText, type: '@' }); - return; - } - if (lastWord.match(/^:/)) { - setAutocompleteParams({ text: autocompleteText, type: ':' }); - return; - } - if (lastWord.match(/^!/) && room?.t === 'l') { - setAutocompleteParams({ text: autocompleteText, type: '!' }); - return; - } stopAutocomplete(); }, textInputDebounceTime);