Skip to content

Commit 5aec7bf

Browse files
Merge branch 'master' of github.com:GetStream/stream-chat-react into rc
2 parents a88e145 + d0c32e3 commit 5aec7bf

File tree

8 files changed

+224
-114
lines changed

8 files changed

+224
-114
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
"@playwright/test": "^1.42.1",
187187
"@semantic-release/changelog": "^6.0.3",
188188
"@semantic-release/git": "^10.0.1",
189-
"@stream-io/stream-chat-css": "^5.8.0",
189+
"@stream-io/stream-chat-css": "^5.8.1",
190190
"@testing-library/dom": "^10.4.0",
191191
"@testing-library/jest-dom": "^6.6.3",
192192
"@testing-library/react": "^16.2.0",

src/components/Channel/Channel.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,10 @@ export type ChannelProps<V extends CustomTrigger = CustomTrigger> =
201201
updatedMessage: UpdatedMessage,
202202
options?: UpdateMessageOptions,
203203
) => ReturnType<StreamChat['updateMessage']>;
204-
/** If true, chat users will be able to drag and drop file uploads to the entire channel window */
204+
/**
205+
* @deprecated Use `WithDragAndDropUpload` instead (wrap draggable-to elements with this component).
206+
* @description If true, chat users will be able to drag and drop file uploads to the entire channel window
207+
*/
205208
dragAndDropWindow?: boolean;
206209
/** Custom UI component to be shown if no active channel is set, defaults to null and skips rendering the Channel component */
207210
EmptyPlaceholder?: React.ReactElement;
@@ -235,7 +238,10 @@ export type ChannelProps<V extends CustomTrigger = CustomTrigger> =
235238
onMentionsClick?: OnMentionAction;
236239
/** Custom action handler function to run on hover of an @mention in a message */
237240
onMentionsHover?: OnMentionAction;
238-
/** If `dragAndDropWindow` prop is true, the props to pass to the MessageInput component (overrides props placed directly on MessageInput) */
241+
/**
242+
* @deprecated Use `WithDragAndDropUpload` instead (wrap draggable-to elements with this component).
243+
* @description If `dragAndDropWindow` prop is `true`, the props to pass to the `MessageInput` component (overrides props placed directly on `MessageInput`)
244+
*/
239245
optionalMessageInputProps?: MessageInputProps<V>;
240246
/** You can turn on/off thumbnail generation for video attachments */
241247
shouldGenerateVideoThumbnail?: boolean;

src/components/MessageInput/MessageInput.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import type { MessageToSend } from '../../context/ChannelActionContext';
2121
import type { CustomTrigger, SendMessageOptions, UnknownType } from '../../types/types';
2222
import type { URLEnrichmentConfig } from './hooks/useLinkPreviews';
2323
import type { CustomAudioRecordingConfig } from '../MediaRecorder';
24+
import { useHandleDragAndDropQueuedFiles } from './WithDragAndDropUpload';
2425

2526
export type EmojiSearchIndexResult = {
2627
id: string;
@@ -140,6 +141,8 @@ const MessageInputProvider = <V extends CustomTrigger = CustomTrigger>(
140141
emojiSearchIndex: props.emojiSearchIndex ?? emojiSearchIndex,
141142
});
142143

144+
useHandleDragAndDropQueuedFiles(messageInputContextValue);
145+
143146
return (
144147
<MessageInputContextProvider<V> value={messageInputContextValue}>
145148
{props.children}
Lines changed: 63 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import React, { useCallback, useEffect, useMemo, useState } from 'react';
22
import type { Event } from 'stream-chat';
3-
import clsx from 'clsx';
4-
import { useDropzone } from 'react-dropzone';
53
import {
64
AttachmentSelector as DefaultAttachmentSelector,
75
SimpleAttachmentSelector,
@@ -28,14 +26,13 @@ import { RecordingAttachmentType } from '../MediaRecorder/classes';
2826
import { useChatContext } from '../../context/ChatContext';
2927
import { useChannelActionContext } from '../../context/ChannelActionContext';
3028
import { useChannelStateContext } from '../../context/ChannelStateContext';
31-
import { useTranslationContext } from '../../context/TranslationContext';
3229
import { useMessageInputContext } from '../../context/MessageInputContext';
3330
import { useComponentContext } from '../../context/ComponentContext';
3431

3532
import { AIStates, useAIState } from '../AIStateIndicator';
33+
import { WithDragAndDropUpload } from './WithDragAndDropUpload';
3634

3735
export const MessageInputFlat = () => {
38-
const { t } = useTranslationContext('MessageInputFlat');
3936
const {
4037
asyncMessagesMultiSendEnabled,
4138
attachments,
@@ -45,14 +42,12 @@ export const MessageInputFlat = () => {
4542
hideSendButton,
4643
isUploadEnabled,
4744
linkPreviews,
48-
maxFilesLeft,
4945
message,
5046
numberOfUploads,
5147
parent,
5248
recordingController,
5349
setCooldownRemaining,
5450
text,
55-
uploadNewFiles,
5651
} = useMessageInputContext('MessageInputFlat');
5752

5853
const {
@@ -68,11 +63,7 @@ export const MessageInputFlat = () => {
6863
StartRecordingAudioButton = DefaultStartRecordingAudioButton,
6964
StopAIGenerationButton: StopAIGenerationButtonOverride,
7065
} = useComponentContext('MessageInputFlat');
71-
const {
72-
acceptedFiles = [],
73-
multipleUploads,
74-
quotedMessage,
75-
} = useChannelStateContext('MessageInputFlat');
66+
const { quotedMessage } = useChannelStateContext('MessageInputFlat');
7667
const { setQuotedMessage } = useChannelActionContext('MessageInputFlat');
7768
const { channel } = useChatContext('MessageInputFlat');
7869

@@ -93,23 +84,6 @@ export const MessageInputFlat = () => {
9384
[attachments],
9485
);
9586

96-
const accept = useMemo(
97-
() =>
98-
acceptedFiles.reduce<Record<string, Array<string>>>((mediaTypeMap, mediaType) => {
99-
mediaTypeMap[mediaType] ??= [];
100-
return mediaTypeMap;
101-
}, {}),
102-
[acceptedFiles],
103-
);
104-
105-
const { getRootProps, isDragActive, isDragReject } = useDropzone({
106-
accept,
107-
disabled: !isUploadEnabled || maxFilesLeft === 0,
108-
multiple: multipleUploads,
109-
noClick: true,
110-
onDrop: uploadNewFiles,
111-
});
112-
11387
useEffect(() => {
11488
const handleQuotedMessageUpdate = (e: Event) => {
11589
if (e.message?.id !== quotedMessage?.id) return;
@@ -153,90 +127,76 @@ export const MessageInputFlat = () => {
153127
!!StopAIGenerationButton;
154128

155129
return (
156-
<>
157-
<div {...getRootProps({ className: 'str-chat__message-input' })}>
158-
{recordingEnabled &&
159-
recordingController.permissionState === 'denied' &&
160-
showRecordingPermissionDeniedNotification && (
161-
<RecordingPermissionDeniedNotification
162-
onClose={closePermissionDeniedNotification}
163-
permissionName={RecordingPermission.MIC}
164-
/>
165-
)}
166-
{findAndEnqueueURLsToEnrich && (
167-
<LinkPreviewList linkPreviews={Array.from(linkPreviews.values())} />
168-
)}
169-
{isDragActive && (
170-
<div
171-
className={clsx('str-chat__dropzone-container', {
172-
'str-chat__dropzone-container--not-accepted': isDragReject,
173-
})}
174-
>
175-
{!isDragReject && <p>{t<string>('Drag your files here')}</p>}
176-
{isDragReject && <p>{t<string>('Some of the files will not be accepted')}</p>}
177-
</div>
130+
<WithDragAndDropUpload className='str-chat__message-input' component='div'>
131+
{recordingEnabled &&
132+
recordingController.permissionState === 'denied' &&
133+
showRecordingPermissionDeniedNotification && (
134+
<RecordingPermissionDeniedNotification
135+
onClose={closePermissionDeniedNotification}
136+
permissionName={RecordingPermission.MIC}
137+
/>
178138
)}
179-
{displayQuotedMessage && <QuotedMessagePreviewHeader />}
180-
181-
<div className='str-chat__message-input-inner'>
182-
<AttachmentSelector />
183-
<div className='str-chat__message-textarea-container'>
184-
{displayQuotedMessage && (
185-
<QuotedMessagePreview quotedMessage={quotedMessage} />
139+
{findAndEnqueueURLsToEnrich && (
140+
<LinkPreviewList linkPreviews={Array.from(linkPreviews.values())} />
141+
)}
142+
{displayQuotedMessage && <QuotedMessagePreviewHeader />}
143+
144+
<div className='str-chat__message-input-inner'>
145+
<AttachmentSelector />
146+
<div className='str-chat__message-textarea-container'>
147+
{displayQuotedMessage && <QuotedMessagePreview quotedMessage={quotedMessage} />}
148+
{isUploadEnabled &&
149+
!!(numberOfUploads + failedUploadsCount || attachments.length > 0) && (
150+
<AttachmentPreviewList />
186151
)}
187-
{isUploadEnabled &&
188-
!!(numberOfUploads + failedUploadsCount || attachments.length > 0) && (
189-
<AttachmentPreviewList />
190-
)}
191152

192-
<div className='str-chat__message-textarea-with-emoji-picker'>
193-
<ChatAutoComplete />
153+
<div className='str-chat__message-textarea-with-emoji-picker'>
154+
<ChatAutoComplete />
194155

195-
{EmojiPicker && <EmojiPicker />}
196-
</div>
156+
{EmojiPicker && <EmojiPicker />}
197157
</div>
198-
{shouldDisplayStopAIGeneration ? (
199-
<StopAIGenerationButton onClick={stopGenerating} />
200-
) : (
201-
!hideSendButton && (
202-
<>
203-
{cooldownRemaining ? (
204-
<CooldownTimer
205-
cooldownInterval={cooldownRemaining}
206-
setCooldownRemaining={setCooldownRemaining}
158+
</div>
159+
{shouldDisplayStopAIGeneration ? (
160+
<StopAIGenerationButton onClick={stopGenerating} />
161+
) : (
162+
!hideSendButton && (
163+
<>
164+
{cooldownRemaining ? (
165+
<CooldownTimer
166+
cooldownInterval={cooldownRemaining}
167+
setCooldownRemaining={setCooldownRemaining}
168+
/>
169+
) : (
170+
<>
171+
<SendButton
172+
disabled={
173+
!numberOfUploads &&
174+
!text.length &&
175+
attachments.length - failedUploadsCount === 0
176+
}
177+
sendMessage={handleSubmit}
207178
/>
208-
) : (
209-
<>
210-
<SendButton
179+
{recordingEnabled && (
180+
<StartRecordingAudioButton
211181
disabled={
212-
!numberOfUploads &&
213-
!text.length &&
214-
attachments.length - failedUploadsCount === 0
182+
isRecording ||
183+
(!asyncMessagesMultiSendEnabled &&
184+
attachments.some(
185+
(a) => a.type === RecordingAttachmentType.VOICE_RECORDING,
186+
))
215187
}
216-
sendMessage={handleSubmit}
188+
onClick={() => {
189+
recordingController.recorder?.start();
190+
setShowRecordingPermissionDeniedNotification(true);
191+
}}
217192
/>
218-
{recordingEnabled && (
219-
<StartRecordingAudioButton
220-
disabled={
221-
isRecording ||
222-
(!asyncMessagesMultiSendEnabled &&
223-
attachments.some(
224-
(a) => a.type === RecordingAttachmentType.VOICE_RECORDING,
225-
))
226-
}
227-
onClick={() => {
228-
recordingController.recorder?.start();
229-
setShowRecordingPermissionDeniedNotification(true);
230-
}}
231-
/>
232-
)}
233-
</>
234-
)}
235-
</>
236-
)
237-
)}
238-
</div>
193+
)}
194+
</>
195+
)}
196+
</>
197+
)
198+
)}
239199
</div>
240-
</>
200+
</WithDragAndDropUpload>
241201
);
242202
};

0 commit comments

Comments
 (0)