Skip to content

Commit fa2519b

Browse files
feat: message composer (#2669)
### 🎯 Goal Provide a message composition API supported by reactive state layer from stream-chat. The message composition logic has been moved to stream-chat. The logic kept in stream-chat-react is related only to the browser event handling. Depends on: - GetStream/stream-chat-js#1495 - GetStream/stream-chat-css#328 ### 🛠 Implementation details The message composition now relies on `MessageComposer `instance. The instance is available for the channel message list, thread message list and for editing a specific message. The `MessageComposer` instance should be accessed via `useMessageComposer` hook, that identifies the correct context (channel, thread, message). ### 🎨 UI Changes No changes BREAKING CHANGE: `Channel` props `dragAndDropWindow` & `optionalMessageInputProps` have been removed, use `WithDragAndDropUpload` component instead (#2688) BREAKING CHANGE: Attachment identity functions moved to stream-chat-js (e.g. isFileAttachment...) BREAKING CHANGE: Remove ChatAutoComplete, AutoCompleteTextarea, DefaultSuggestionList, DefaultSuggestionListItem and introduce TextareaComposer, SuggestionList, SuggestionListItem BREAKING CHANGE: Remove defaultScrollToItem function previously used by SuggestionList BREAKING CHANGE: Removed DefaultTriggerProvider component BREAKING CHANGE: Remove from Channel props - acceptedFiles, enrichURLForPreview, enrichURLForPreviewConfig, maxNumberOfFiles, multipleUploads, TriggerProvider BREAKING CHANGE: Removal of acceptedFiles, debounceURLEnrichmentMs, enrichURLForPreview, findURLFn, multipleUploads, onLinkPreviewDismissed, quotedMessage from ChannelStateContext BREAKING CHANGE: Changed signature for functions sendMessage and editMessage in ChannelActionContext BREAKING CHANGE: Changed signature for handleSubmit BREAKING CHANGE: Removed setQuotedMessage from ChannelActionContext BREAKING CHANGE: Removed types MessageToSend, StreamMessage, UpdatedMessage in favor of LocalMessage or RenderedMessage BREAKING CHANGE: Removed Trigger generics from ChannelProps BREAKING CHANGE: Message input state as well as the API is now kept within MessageComposer instead of MessageInputContext BREAKING CHANGE: Renamed useMessageInputState to useMessageInputControls as it does not handle the composition state anymore BREAKING CHANGE: Removed from MessageInputProps - disabled, disableMentions, doFileUploadRequest, doImageUploadRequest, errorHandler, getDefaultValue, mentionAllAppUsers, mentionQueryParams, message, noFiles, urlEnrichmentConfig, useMentionsTransliteration, additionalTextareaProps do not expect default value anymore BREAKING CHANGE: Changed the signature of MessageInput prop overrideSubmitHandler BREAKING CHANGE: Local attachment and link preview types moved to stream-chat BREAKING CHANGE: The SuggestionListItem UI components for TextareaComposer receive tokenizedDisplayName instead of itemNameParts BREAKING CHANGE: Removed duplicate types SendMessageOptions, UpdateMessageOptions which should be imported from stream-chat instead BREAKING CHANGE: Removed type LinkPreviewListProps - LinkPreviewList does not have any props anymore --------- Co-authored-by: Anton Arnautov <[email protected]>
1 parent a9cb4e0 commit fa2519b

File tree

177 files changed

+6660
-9806
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

177 files changed

+6660
-9806
lines changed

.lintstagedrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"src/**/*.{js,ts,tsx,md}": "eslint --max-warnings 0",
2+
"src/**/*.{js,ts,tsx,md}": "eslint --max-warnings 0 --no-warn-ignored",
33
"**/*.{js,mjs,ts,mts,jsx,tsx,md,json,yml}": "prettier --list-different",
44
"src/i18n/*.json": "yarn run validate-translations"
55
}

examples/vite/src/App.tsx

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { ChannelFilters, ChannelOptions, ChannelSort } from 'stream-chat';
1+
import { useEffect } from 'react';
2+
import {
3+
ChannelFilters,
4+
ChannelOptions,
5+
ChannelSort,
6+
LocalMessage,
7+
TextComposerMiddleware,
8+
} from 'stream-chat';
29
import {
310
AIStateIndicator,
411
Channel,
@@ -8,13 +15,19 @@ import {
815
Chat,
916
ChatView,
1017
MessageInput,
11-
StreamMessage,
18+
SendButtonProps,
1219
Thread,
1320
ThreadList,
1421
useCreateChatClient,
22+
useMessageComposer,
1523
VirtualizedMessageList as MessageList,
1624
Window,
1725
} from 'stream-chat-react';
26+
import { createTextComposerEmojiMiddleware } from 'stream-chat-react/emojis';
27+
import { init, SearchIndex } from 'emoji-mart';
28+
import data from '@emoji-mart/data';
29+
30+
init({ data });
1831

1932
const params = new Proxy(new URLSearchParams(window.location.search), {
2033
get: (searchParams, property) => searchParams.get(property as string),
@@ -40,7 +53,8 @@ const filters: ChannelFilters = {
4053
const options: ChannelOptions = { limit: 5, presence: true, state: true };
4154
const sort: ChannelSort = { pinned_at: 1, last_message_at: -1, updated_at: -1 };
4255

43-
const isMessageAIGenerated = (message: StreamMessage) => !!message?.ai_generated;
56+
// @ts-ignore
57+
const isMessageAIGenerated = (message: LocalMessage) => !!message?.ai_generated;
4458

4559
const App = () => {
4660
const chatClient = useCreateChatClient({
@@ -49,6 +63,20 @@ const App = () => {
4963
userData: { id: userId },
5064
});
5165

66+
useEffect(() => {
67+
if (!chatClient) return;
68+
69+
chatClient.setMessageComposerSetupFunction(({ composer }) => {
70+
composer.textComposer.middlewareExecutor.insert({
71+
middleware: [
72+
createTextComposerEmojiMiddleware(SearchIndex) as TextComposerMiddleware,
73+
],
74+
position: { before: 'stream-io/text-composer/mentions-middleware' },
75+
unique: true,
76+
});
77+
});
78+
}, [chatClient]);
79+
5280
if (!chatClient) return <>Loading...</>;
5381

5482
return (
@@ -64,12 +92,12 @@ const App = () => {
6492
showChannelSearch
6593
additionalChannelSearchProps={{ searchForChannels: true }}
6694
/>
67-
<Channel>
95+
<Channel emojiSearchIndex={SearchIndex}>
6896
<Window>
6997
<ChannelHeader Avatar={ChannelAvatar} />
7098
<MessageList returnAllReadData />
7199
<AIStateIndicator />
72-
<MessageInput focus />
100+
<MessageInput focus audioRecordingEnabled />
73101
</Window>
74102
<Thread virtualized />
75103
</Channel>

0 commit comments

Comments
 (0)