@@ -6,7 +6,7 @@ import React, {
6
6
useContext ,
7
7
useEffect ,
8
8
useMemo ,
9
- useState ,
9
+ useRef ,
10
10
} from 'react' ;
11
11
import {
12
12
MessageInputContextValue ,
@@ -18,34 +18,27 @@ import { useDropzone } from 'react-dropzone';
18
18
import clsx from 'clsx' ;
19
19
20
20
const DragAndDropUploadContext = React . createContext < {
21
- fileQueue : File [ ] ;
22
- addFilesToQueue : ( ( files : File [ ] ) => void ) | null ;
23
- removeFilesFromQueue : ( ( files : File [ ] ) => void ) | null ;
21
+ subscribeToDrop : ( ( fn : ( files : File [ ] ) => void ) => ( ) => void ) | null ;
24
22
} > ( {
25
- addFilesToQueue : null ,
26
- fileQueue : [ ] ,
27
- removeFilesFromQueue : null ,
23
+ subscribeToDrop : null ,
28
24
} ) ;
29
25
30
26
export const useDragAndDropUploadContext = ( ) => useContext ( DragAndDropUploadContext ) ;
31
27
32
28
/**
33
- * @private To maintain top -> bottom data flow, the drag-and-drop functionality allows dragging any files to the queue - the closest
34
- * `MessageInputProvider` will be notified through `DragAndDropUploadContext.fileQueue` and starts the upload with `uploadNewAttachments`,
35
- * forwarded files are removed from the queue immediately after.
29
+ * @private This hook should be used only once directly in the `MessageInputProvider` to
30
+ * register `uploadNewFiles` functions of the rendered `MessageInputs`. Each `MessageInput`
31
+ * will then be notified when the drop event occurs from within the `WithDragAndDropUpload`
32
+ * component.
36
33
*/
37
- export const useHandleDragAndDropQueuedFiles = ( {
38
- uploadNewFiles,
39
- } : MessageInputContextValue ) => {
40
- const { fileQueue, removeFilesFromQueue } = useDragAndDropUploadContext ( ) ;
34
+ export const useRegisterDropHandlers = ( { uploadNewFiles } : MessageInputContextValue ) => {
35
+ const { subscribeToDrop } = useDragAndDropUploadContext ( ) ;
41
36
42
37
useEffect ( ( ) => {
43
- if ( ! removeFilesFromQueue ) return ;
38
+ const unsubscribe = subscribeToDrop ?. ( uploadNewFiles ) ;
44
39
45
- uploadNewFiles ( fileQueue ) ;
46
-
47
- removeFilesFromQueue ( fileQueue ) ;
48
- } , [ fileQueue , removeFilesFromQueue , uploadNewFiles ] ) ;
40
+ return unsubscribe ;
41
+ } , [ subscribeToDrop , uploadNewFiles ] ) ;
49
42
} ;
50
43
51
44
/**
@@ -78,7 +71,7 @@ export const WithDragAndDropUpload = ({
78
71
className ?: string ;
79
72
style ?: CSSProperties ;
80
73
} > ) => {
81
- const [ files , setFiles ] = useState < File [ ] > ( [ ] ) ;
74
+ const dropHandlersRef = useRef < Set < ( f : File [ ] ) => void > > ( new Set ( ) ) ;
82
75
const { acceptedFiles = [ ] , multipleUploads } = useChannelStateContext ( ) ;
83
76
const { t } = useTranslationContext ( ) ;
84
77
@@ -98,13 +91,16 @@ export const WithDragAndDropUpload = ({
98
91
[ acceptedFiles ] ,
99
92
) ;
100
93
101
- const addFilesToQueue = useCallback ( ( files : File [ ] ) => {
102
- setFiles ( ( cv ) => cv . concat ( files ) ) ;
94
+ const subscribeToDrop = useCallback ( ( fn : ( files : File [ ] ) => void ) => {
95
+ dropHandlersRef . current . add ( fn ) ;
96
+
97
+ return ( ) => {
98
+ dropHandlersRef . current . delete ( fn ) ;
99
+ } ;
103
100
} , [ ] ) ;
104
101
105
- const removeFilesFromQueue = useCallback ( ( files : File [ ] ) => {
106
- if ( ! files . length ) return ;
107
- setFiles ( ( cv ) => cv . filter ( ( f ) => files . indexOf ( f ) === - 1 ) ) ;
102
+ const handleDrop = useCallback ( ( files : File [ ] ) => {
103
+ dropHandlersRef . current . forEach ( ( fn ) => fn ( files ) ) ;
108
104
} , [ ] ) ;
109
105
110
106
const { getRootProps, isDragActive, isDragReject } = useDropzone ( {
@@ -116,20 +112,20 @@ export const WithDragAndDropUpload = ({
116
112
: false ,
117
113
multiple : multipleUploads ,
118
114
noClick : true ,
119
- onDrop : isWithinMessageInputContext
120
- ? messageInputContext . uploadNewFiles
121
- : addFilesToQueue ,
115
+ onDrop : isWithinMessageInputContext ? messageInputContext . uploadNewFiles : handleDrop ,
122
116
} ) ;
123
117
124
118
// nested WithDragAndDropUpload components render wrappers without functionality
125
119
// (MessageInputFlat has a default WithDragAndDropUpload)
126
- if ( dragAndDropUploadContext . removeFilesFromQueue !== null ) {
120
+ if ( dragAndDropUploadContext . subscribeToDrop !== null ) {
127
121
return < Component className = { className } > { children } </ Component > ;
128
122
}
129
123
130
124
return (
131
125
< DragAndDropUploadContext . Provider
132
- value = { { addFilesToQueue, fileQueue : files , removeFilesFromQueue } }
126
+ value = { {
127
+ subscribeToDrop,
128
+ } }
133
129
>
134
130
< Component { ...getRootProps ( { className, style } ) } >
135
131
{ /* TODO: could be a replaceable component */ }
0 commit comments