Skip to content

Commit 2e4f47a

Browse files
committed
Merge remote-tracking branch 'origin/feat/message-composer' into feat/message-composer
2 parents 832e0ad + b9f86ad commit 2e4f47a

File tree

3 files changed

+28
-28
lines changed

3 files changed

+28
-28
lines changed

src/components/MessageInput/DropzoneProvider.tsx

Whitespace-only changes.

src/components/MessageInput/MessageInput.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import type {
2222

2323
import type { SearchQueryParams } from '../ChannelSearch/hooks/useChannelSearch';
2424
import type { CustomAudioRecordingConfig } from '../MediaRecorder';
25-
import { useHandleDragAndDropQueuedFiles } from './WithDragAndDropUpload';
25+
import { useRegisterDropHandlers } from './WithDragAndDropUpload';
2626

2727
export type EmojiSearchIndexResult = {
2828
id: string;
@@ -153,7 +153,7 @@ const MessageInputProvider = (props: PropsWithChildren<MessageInputProps>) => {
153153
});
154154
}, [messageComposer]);
155155

156-
useHandleDragAndDropQueuedFiles();
156+
useRegisterDropHandlers();
157157

158158
return (
159159
<MessageInputContextProvider value={messageInputContextValue}>

src/components/MessageInput/WithDragAndDropUpload.tsx

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
1+
import React, { useCallback, useContext, useEffect, useMemo, useRef } from 'react';
22
import { useDropzone } from 'react-dropzone';
33
import clsx from 'clsx';
44
import type { CSSProperties, ElementType, PropsWithChildren } from 'react';
@@ -13,34 +13,29 @@ import { useAttachmentManagerState, useMessageComposer } from './hooks';
1313
import { useStateStore } from '../../store';
1414

1515
const DragAndDropUploadContext = React.createContext<{
16-
fileQueue: File[];
17-
addFilesToQueue: ((files: File[]) => void) | null;
18-
removeFilesFromQueue: ((files: File[]) => void) | null;
16+
subscribeToDrop: ((fn: (files: File[]) => void) => () => void) | null;
1917
}>({
20-
addFilesToQueue: null,
21-
fileQueue: [],
22-
removeFilesFromQueue: null,
18+
subscribeToDrop: null,
2319
});
2420

2521
export const useDragAndDropUploadContext = () => useContext(DragAndDropUploadContext);
2622

2723
/**
28-
* @private To maintain top -> bottom data flow, the drag-and-drop functionality allows dragging any files to the queue - the closest
29-
* `MessageInputProvider` will be notified through `DragAndDropUploadContext.fileQueue` and starts the upload with `uploadNewAttachments`,
30-
* forwarded files are removed from the queue immediately after.
24+
* @private This hook should be used only once directly in the `MessageInputProvider` to
25+
* register `uploadNewFiles` functions of the rendered `MessageInputs`. Each `MessageInput`
26+
* will then be notified when the drop event occurs from within the `WithDragAndDropUpload`
27+
* component.
3128
*/
32-
export const useHandleDragAndDropQueuedFiles = () => {
33-
const { fileQueue, removeFilesFromQueue } = useDragAndDropUploadContext();
29+
export const useRegisterDropHandlers = () => {
30+
const { subscribeToDrop } = useDragAndDropUploadContext();
3431

3532
const messageComposer = useMessageComposer();
3633

3734
useEffect(() => {
38-
if (!removeFilesFromQueue) return;
35+
const unsubscribe = subscribeToDrop?.(messageComposer.attachmentManager.uploadFiles);
3936

40-
messageComposer.attachmentManager.uploadFiles(fileQueue);
41-
42-
removeFilesFromQueue(fileQueue);
43-
}, [fileQueue, removeFilesFromQueue, messageComposer]);
37+
return unsubscribe;
38+
}, [subscribeToDrop, messageComposer]);
4439
};
4540

4641
const attachmentManagerConfigStateSelector = (state: MessageComposerConfig) => ({
@@ -77,7 +72,7 @@ export const WithDragAndDropUpload = ({
7772
className?: string;
7873
style?: CSSProperties;
7974
}>) => {
80-
const [files, setFiles] = useState<File[]>([]);
75+
const dropHandlersRef = useRef<Set<(f: File[]) => void>>(new Set());
8176
const { acceptedFiles = [] } = useChannelStateContext();
8277
const { t } = useTranslationContext();
8378

@@ -97,13 +92,16 @@ export const WithDragAndDropUpload = ({
9792
[acceptedFiles],
9893
);
9994

100-
const addFilesToQueue = useCallback((files: File[]) => {
101-
setFiles((cv) => cv.concat(files));
95+
const subscribeToDrop = useCallback((fn: (files: File[]) => void) => {
96+
dropHandlersRef.current.add(fn);
97+
98+
return () => {
99+
dropHandlersRef.current.delete(fn);
100+
};
102101
}, []);
103102

104-
const removeFilesFromQueue = useCallback((files: File[]) => {
105-
if (!files.length) return;
106-
setFiles((cv) => cv.filter((f) => files.indexOf(f) === -1));
103+
const handleDrop = useCallback((files: File[]) => {
104+
dropHandlersRef.current.forEach((fn) => fn(files));
107105
}, []);
108106

109107
const { isUploadEnabled } = useAttachmentManagerState();
@@ -123,18 +121,20 @@ export const WithDragAndDropUpload = ({
123121
noClick: true,
124122
onDrop: isWithinMessageInputContext
125123
? messageComposer.attachmentManager.uploadFiles
126-
: addFilesToQueue,
124+
: handleDrop,
127125
});
128126

129127
// nested WithDragAndDropUpload components render wrappers without functionality
130128
// (MessageInputFlat has a default WithDragAndDropUpload)
131-
if (dragAndDropUploadContext.removeFilesFromQueue !== null) {
129+
if (dragAndDropUploadContext.subscribeToDrop !== null) {
132130
return <Component className={className}>{children}</Component>;
133131
}
134132

135133
return (
136134
<DragAndDropUploadContext.Provider
137-
value={{ addFilesToQueue, fileQueue: files, removeFilesFromQueue }}
135+
value={{
136+
subscribeToDrop,
137+
}}
138138
>
139139
<Component {...getRootProps({ className, style })}>
140140
{/* TODO: could be a replaceable component */}

0 commit comments

Comments
 (0)