1- import React , { useEffect , useState } from 'react' ;
2- import { I18nManager , StyleSheet , TextInput , TextInputProps } from 'react-native' ;
1+ import React , { useCallback , useEffect , useMemo , useState } from 'react' ;
2+ import {
3+ I18nManager ,
4+ NativeSyntheticEvent ,
5+ StyleSheet ,
6+ TextInput ,
7+ TextInputContentSizeChangeEventData ,
8+ TextInputSelectionChangeEventData ,
9+ } from 'react-native' ;
310
411import { TextComposerState } from 'stream-chat' ;
512
@@ -34,6 +41,7 @@ type AutoCompleteInputPropsWithContext = Pick<
3441 | 'giphyEnabled'
3542 | 'maxMessageLength'
3643 | 'numberOfLines'
44+ | 'onChangeText'
3745 | 'setGiphyActive'
3846 | 'setInputBoxRef'
3947> &
@@ -59,44 +67,70 @@ const AutoCompleteInputWithContext = (props: AutoCompleteInputPropsWithContext)
5967 giphyEnabled,
6068 maxMessageLength,
6169 numberOfLines,
70+ onChangeText,
6271 setGiphyActive,
6372 setInputBoxRef,
6473 t,
6574 } = props ;
6675 const [ localText , setLocalText ] = useState ( '' ) ;
6776 const [ selection , setSelection ] = useState ( { end : 0 , start : 0 } ) ;
77+ const [ textHeight , setTextHeight ] = useState ( 0 ) ;
6878 const messageComposer = useMessageComposer ( ) ;
79+ const { textComposer } = messageComposer ;
6980
70- const { text } = useStateStore ( messageComposer . textComposer . state , messageComposerStateSelector ) ;
81+ const { text } = useStateStore ( textComposer . state , messageComposerStateSelector ) ;
7182
7283 useEffect ( ( ) => {
7384 setLocalText ( text ) ;
7485 } , [ text ] ) ;
7586
76- const handleSelectionChange : TextInputProps [ 'onSelectionChange' ] = ( {
77- nativeEvent : { selection } ,
78- } ) => {
79- setSelection ( selection ) ;
80- } ;
81-
82- const onTextChangeHandler = async ( newText : string ) => {
83- setLocalText ( newText ) ;
84- const isGiphy = giphyEnabled && newText && newText . startsWith ( '/giphy ' ) ;
85-
86- if ( isGiphy ) {
87- setGiphyActive ( true ) ;
88- }
89-
90- await messageComposer . textComposer . handleChange ( {
91- selection : {
92- end : selection . end + 1 ,
93- start : selection . start + 1 ,
94- } ,
95- text : isGiphy ? newText . slice ( 7 ) : newText ,
96- } ) ;
97- } ;
87+ const handleSelectionChange = useCallback (
88+ ( e : NativeSyntheticEvent < TextInputSelectionChangeEventData > ) => {
89+ const { selection } = e . nativeEvent ;
90+ if ( additionalTextInputProps ?. onSelectionChange ) {
91+ additionalTextInputProps . onSelectionChange ( e ) ;
92+ return ;
93+ }
94+ setSelection ( selection ) ;
95+ } ,
96+ [ additionalTextInputProps ] ,
97+ ) ;
9898
99- const [ textHeight , setTextHeight ] = useState ( 0 ) ;
99+ const onTextChangeHandler = useCallback (
100+ async ( newText : string ) => {
101+ if ( onChangeText ) {
102+ onChangeText ( newText ) ;
103+ return ;
104+ }
105+ if ( additionalTextInputProps ?. onChangeText ) {
106+ additionalTextInputProps . onChangeText ( newText ) ;
107+ return ;
108+ }
109+ setLocalText ( newText ) ;
110+ const isGiphy = giphyEnabled && newText && newText . startsWith ( '/giphy ' ) ;
111+
112+ if ( isGiphy ) {
113+ setGiphyActive ( true ) ;
114+ }
115+
116+ await textComposer . handleChange ( {
117+ selection : {
118+ end : selection . end + 1 ,
119+ start : selection . start + 1 ,
120+ } ,
121+ text : isGiphy ? newText . slice ( 7 ) : newText ,
122+ } ) ;
123+ } ,
124+ [
125+ additionalTextInputProps ,
126+ giphyEnabled ,
127+ onChangeText ,
128+ textComposer ,
129+ selection . end ,
130+ selection . start ,
131+ setGiphyActive ,
132+ ] ,
133+ ) ;
100134
101135 const {
102136 theme : {
@@ -105,27 +139,30 @@ const AutoCompleteInputWithContext = (props: AutoCompleteInputPropsWithContext)
105139 } ,
106140 } = useTheme ( ) ;
107141
108- const placeholderText = giphyActive
109- ? t ( 'Search GIFs' )
110- : cooldownActive
111- ? t ( 'Slow mode ON' )
112- : t ( 'Send a message' ) ;
142+ const placeholderText = useMemo ( ( ) => {
143+ return giphyActive
144+ ? t ( 'Search GIFs' )
145+ : cooldownActive
146+ ? t ( 'Slow mode ON' )
147+ : t ( 'Send a message' ) ;
148+ } , [ cooldownActive , giphyActive , t ] ) ;
149+
150+ const handleContentSizeChange = useCallback (
151+ ( {
152+ nativeEvent : { contentSize } ,
153+ } : NativeSyntheticEvent < TextInputContentSizeChangeEventData > ) => {
154+ setTextHeight ( contentSize . height ) ;
155+ } ,
156+ [ ] ,
157+ ) ;
113158
114159 return (
115160 < TextInput
116161 autoFocus = { giphyActive }
117162 maxLength = { maxMessageLength }
118163 multiline
119164 onChangeText = { onTextChangeHandler }
120- onContentSizeChange = { ( {
121- nativeEvent : {
122- contentSize : { height } ,
123- } ,
124- } ) => {
125- if ( ! textHeight ) {
126- setTextHeight ( height ) ;
127- }
128- } }
165+ onContentSizeChange = { handleContentSizeChange }
129166 onSelectionChange = { handleSelectionChange }
130167 placeholder = { placeholderText }
131168 placeholderTextColor = { grey }
@@ -183,6 +220,7 @@ export const AutoCompleteInput = (props: AutoCompleteInputProps) => {
183220 giphyActive,
184221 maxMessageLength,
185222 numberOfLines,
223+ onChangeText,
186224 setGiphyActive,
187225 setInputBoxRef,
188226 } = useMessageInputContext ( ) ;
@@ -196,6 +234,7 @@ export const AutoCompleteInput = (props: AutoCompleteInputProps) => {
196234 giphyEnabled,
197235 maxMessageLength,
198236 numberOfLines,
237+ onChangeText,
199238 setGiphyActive,
200239 setInputBoxRef,
201240 t,
0 commit comments