@@ -2,23 +2,78 @@ import { useEffect, useMemo, useRef, useState } from 'react';
22import { MessageComposer } from 'stream-chat' ;
33import { useThreadContext } from '../../../Threads' ;
44import { useChannelStateContext , useMessageInputContext } from '../../../../context' ;
5- import type { LocalMessage , TextComposerMiddleware } from 'stream-chat' ;
5+ import type { LocalMessage } from 'stream-chat' ;
66import { useLegacyThreadContext } from '../../../Thread' ;
77
8- export type UseMessageComposerParams = {
9- textComposerMiddleware ?: TextComposerMiddleware [ ] ;
10- } ;
8+ class FixedSizeQueueCache < T > {
9+ private elements : Array < T > ;
10+ private size : number ;
11+ constructor ( size : number ) {
12+ if ( ! size ) throw new Error ( 'Size must be greater than 0' ) ;
13+ this . elements = [ ] ;
14+ this . size = size ;
15+ }
16+
17+ add ( ...values : T [ ] ) {
18+ const pushableValues =
19+ values . length > this . size ? values . slice ( values . length - this . size ) : values ;
20+
21+ if ( pushableValues . length === this . size ) {
22+ // this.elements.splice(0, this.size - 1);
23+ this . elements . length = 0 ;
24+ this . elements . push ( ...pushableValues ) ;
25+ } else {
26+ for ( const value of pushableValues ) {
27+ if ( this . elements . length >= this . size ) {
28+ this . elements . shift ( ) ;
29+ }
30+
31+ this . elements . push ( value ) ;
32+ }
33+ }
34+ }
35+
36+ // returns value without shifting it to the end of the array
37+ peek ( predicate : ( element : T ) => boolean ) {
38+ // start searching from the most recent (end of array)
39+ for ( let index = 0 ; index < this . elements . length ; index ++ ) {
40+ const element = this . elements [ this . elements . length - 1 - index ] ;
41+ const predicateResult = predicate ( element ) ;
42+
43+ if ( predicateResult ) return element ;
44+ }
45+
46+ return null ;
47+ }
48+
49+ get ( predicate : ( element : T ) => boolean ) {
50+ const foundElement = this . peek ( predicate ) ;
51+
52+ if ( foundElement && this . elements . indexOf ( foundElement ) !== this . size - 1 ) {
53+ this . elements . splice ( this . elements . indexOf ( foundElement ) , 1 ) ;
54+ this . elements . push ( foundElement ) ;
55+ }
56+
57+ return foundElement ;
58+ }
59+
60+ toArray ( ) {
61+ return [ ...this . elements ] ;
62+ }
63+ }
64+
65+ export type UseMessageComposerParams = unknown ;
1166
12- export const useMessageComposer = ( {
13- textComposerMiddleware ,
14- } : UseMessageComposerParams = { } ) => {
67+ const queueCache = new FixedSizeQueueCache < MessageComposer > ( 64 ) ;
68+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
69+ export const useMessageComposer = ( _unused : UseMessageComposerParams = { } ) => {
1570 const { channel } = useChannelStateContext ( ) ;
1671 const { message : editedMessage } = useMessageInputContext ( ) ;
1772 // legacy thread will receive new composer
1873 const { legacyThread : parentMessage , messageDraft } = useLegacyThreadContext ( ) ;
19- const thread = useThreadContext ( ) ;
74+ const threadInstance = useThreadContext ( ) ;
2075 const detachedMessageComposerRef = useRef < MessageComposer > (
21- new MessageComposer ( { channel } ) ,
76+ new MessageComposer ( { channel, tag : 'detached' } ) ,
2277 ) ;
2378
2479 const [ cachedEditedMessage , setCachedEditedMessage ] = useState <
@@ -42,25 +97,37 @@ export const useMessageComposer = ({
4297
4398 const messageComposer = useMemo ( ( ) => {
4499 if ( cachedEditedMessage ) {
45- const composer = new MessageComposer ( { channel, composition : cachedEditedMessage } ) ;
46- // todo: remove with factory functions introduction
47- if ( textComposerMiddleware ) {
48- composer . textComposer . use ( textComposerMiddleware ) ;
49- }
50- return composer ;
51- } else if ( thread ) {
52- return thread . messageComposer ;
100+ const tag = `edited-message-${ cachedEditedMessage . id } ` ;
101+
102+ const element = queueCache . get ( ( element ) => element . tag === tag ) ;
103+ if ( element ) return element ;
104+
105+ const c = new MessageComposer ( {
106+ channel,
107+ composition : cachedEditedMessage ,
108+ tag,
109+ } ) ;
110+
111+ // FIXME: don't like this side effect here
112+ queueCache . add ( c ) ;
113+ return c ;
114+ } else if ( threadInstance ) {
115+ return threadInstance . messageComposer ;
53116 } else if ( cachedParentMessage ) {
54- const composer = new MessageComposer ( {
117+ const tag = `parent-message-${ cachedParentMessage . id } ` ;
118+
119+ const element = queueCache . get ( ( element ) => element . tag === tag ) ;
120+ if ( element ) return element ;
121+
122+ const c = new MessageComposer ( {
55123 channel,
56124 composition : messageDraft ,
125+ tag,
57126 threadId : cachedParentMessage . id ,
58127 } ) ;
59- // todo: remove with factory functions introduction
60- if ( textComposerMiddleware ) {
61- composer . textComposer . use ( textComposerMiddleware ) ;
62- }
63- return composer ;
128+
129+ queueCache . add ( c ) ;
130+ return c ;
64131 } else if ( channel ) {
65132 return channel . messageComposer ;
66133 } else {
@@ -72,8 +139,7 @@ export const useMessageComposer = ({
72139 cachedParentMessage ,
73140 channel ,
74141 messageDraft , // TODO: set message draft after the fact
75- textComposerMiddleware ,
76- thread ,
142+ threadInstance ,
77143 ] ) ;
78144
79145 useEffect ( ( ) => {
0 commit comments