1- // @ts -check
21import {
32 useReducer ,
43 useEffect ,
@@ -62,7 +61,7 @@ function initState(message) {
6261 } ;
6362 }
6463
65- // if message prop is defined, get imageuploads, fileuploads , text, etc. from it
64+ // if message prop is defined, get image uploads, file uploads , text, etc. from it
6665 const imageUploads =
6766 message . attachments
6867 ?. filter ( ( { type } ) => type === 'image' )
@@ -212,24 +211,29 @@ function messageInputReducer(state, action) {
212211 */
213212export default function useMessageInput ( props ) {
214213 const {
214+ additionalTextareaProps,
215+ clearEditingState,
215216 doImageUploadRequest,
216217 doFileUploadRequest,
218+ errorHandler,
217219 focus,
218220 message,
219- clearEditingState ,
221+ noFiles ,
220222 overrideSubmitHandler,
221223 parent,
222- noFiles,
223- errorHandler,
224224 publishTypingEvent,
225225 } = props ;
226226
227+ const {
228+ channel,
229+ editMessage,
230+ maxNumberOfFiles,
231+ multipleUploads,
232+ sendMessage,
233+ } = useContext ( ChannelContext ) ;
234+
227235 const [ state , dispatch ] = useReducer ( messageInputReducer , message , initState ) ;
228- const textareaRef = useRef (
229- /** @type {HTMLTextAreaElement | undefined } */ ( undefined ) ,
230- ) ;
231- const emojiPickerRef = useRef ( /** @type {HTMLDivElement | null } */ ( null ) ) ;
232- const channelContext = useContext ( ChannelContext ) ;
236+
233237 const {
234238 text,
235239 imageOrder,
@@ -240,10 +244,13 @@ export default function useMessageInput(props) {
240244 numberOfUploads,
241245 mentioned_users,
242246 } = state ;
243- const { channel, editMessage, sendMessage } = channelContext ;
244247
245- // Focus
248+ const textareaRef = useRef (
249+ /** @type {HTMLTextAreaElement | undefined } */ ( undefined ) ,
250+ ) ;
251+ const emojiPickerRef = useRef ( /** @type {HTMLDivElement | null } */ ( null ) ) ;
246252
253+ // Focus
247254 useEffect ( ( ) => {
248255 if ( focus && textareaRef . current ) {
249256 textareaRef . current . focus ( ) ;
@@ -252,28 +259,45 @@ export default function useMessageInput(props) {
252259
253260 // Text + cursor position
254261 const newCursorPosition = useRef ( /** @type {number | null } */ ( null ) ) ;
262+
255263 const insertText = useCallback (
256264 ( textToInsert ) => {
265+ const { maxLength } = additionalTextareaProps ;
266+
257267 if ( ! textareaRef . current ) {
258268 dispatch ( {
259269 type : 'setText' ,
260- getNewText : ( t ) => t + textToInsert ,
270+ getNewText : ( t ) => {
271+ const updatedText = t + textToInsert ;
272+ if ( updatedText . length > maxLength ) {
273+ return updatedText . slice ( 0 , maxLength ) ;
274+ }
275+ return updatedText ;
276+ } ,
261277 } ) ;
262278 return ;
263279 }
264280
265- const textareaElement = textareaRef . current ;
266- const { selectionStart, selectionEnd } = textareaElement ;
281+ const { selectionStart, selectionEnd } = textareaRef . current ;
267282 newCursorPosition . current = selectionStart + textToInsert . length ;
283+
268284 dispatch ( {
269285 type : 'setText' ,
270- getNewText : ( prevText ) =>
271- prevText . slice ( 0 , selectionStart ) +
272- textToInsert +
273- prevText . slice ( selectionEnd ) ,
286+ getNewText : ( prevText ) => {
287+ const updatedText =
288+ prevText . slice ( 0 , selectionStart ) +
289+ textToInsert +
290+ prevText . slice ( selectionEnd ) ;
291+
292+ if ( updatedText . length > maxLength ) {
293+ return updatedText . slice ( 0 , maxLength ) ;
294+ }
295+
296+ return updatedText ;
297+ } ,
274298 } ) ;
275299 } ,
276- [ textareaRef , newCursorPosition ] ,
300+ [ additionalTextareaProps , newCursorPosition , textareaRef ] ,
277301 ) ;
278302
279303 useEffect ( ( ) => {
@@ -524,7 +548,7 @@ export default function useMessageInput(props) {
524548 dispatch ( { type : 'setFileUpload' , id, state : 'failed' } ) ;
525549 }
526550 if ( ! alreadyRemoved && errorHandler ) {
527- // TODO: verify if the paramaters passed to the error handler actually make sense
551+ // TODO: verify if the parameters passed to the error handler actually make sense
528552 errorHandler ( e , 'upload-file' , file ) ;
529553 }
530554 return ;
@@ -579,7 +603,7 @@ export default function useMessageInput(props) {
579603 dispatch ( { type : 'setImageUpload' , id, state : 'failed' } ) ;
580604 }
581605 if ( ! alreadyRemoved && errorHandler ) {
582- // TODO: verify if the paramaters passed to the error handler actually make sense
606+ // TODO: verify if the parameters passed to the error handler actually make sense
583607 errorHandler ( e , 'upload-image' , {
584608 id,
585609 file,
@@ -639,12 +663,12 @@ export default function useMessageInput(props) {
639663 // Number of files that the user can still add. Should never be more than the amount allowed by the API.
640664 // If multipleUploads is false, we only want to allow a single upload.
641665 const maxFilesAllowed = useMemo ( ( ) => {
642- if ( ! channelContext . multipleUploads ) return 1 ;
643- if ( channelContext . maxNumberOfFiles === undefined ) {
666+ if ( ! multipleUploads ) return 1 ;
667+ if ( maxNumberOfFiles === undefined ) {
644668 return apiMaxNumberOfFiles ;
645669 }
646- return channelContext . maxNumberOfFiles ;
647- } , [ channelContext . maxNumberOfFiles , channelContext . multipleUploads ] ) ;
670+ return maxNumberOfFiles ;
671+ } , [ maxNumberOfFiles , multipleUploads ] ) ;
648672
649673 const maxFilesLeft = maxFilesAllowed - numberOfUploads ;
650674
@@ -673,9 +697,7 @@ export default function useMessageInput(props) {
673697 ( async ( event ) => {
674698 // TODO: Move this handler to package with ImageDropzone
675699 const { items } = event . clipboardData ;
676- if ( ! dataTransferItemsHaveFiles ( items ) ) {
677- return ;
678- }
700+ if ( ! dataTransferItemsHaveFiles ( items ) ) return ;
679701
680702 event . preventDefault ( ) ;
681703 // Get a promise for the plain text in case no files are
@@ -686,6 +708,7 @@ export default function useMessageInput(props) {
686708 const plainTextItem = [ ...items ] . find (
687709 ( { kind, type } ) => kind === 'string' && type === 'text/plain' ,
688710 ) ;
711+
689712 if ( plainTextItem ) {
690713 plainTextPromise = new Promise ( ( resolve ) => {
691714 plainTextItem . getAsString ( ( s ) => {
@@ -699,14 +722,15 @@ export default function useMessageInput(props) {
699722 uploadNewFiles ( fileLikes ) ;
700723 return ;
701724 }
725+
702726 // fallback to regular text paste
703727 if ( plainTextPromise ) {
704- const s = await plainTextPromise ;
705- insertText ( s ) ;
728+ const pastedText = await plainTextPromise ;
729+ insertText ( pastedText ) ;
706730 }
707731 } ) ( e ) ;
708732 } ,
709- [ uploadNewFiles , insertText ] ,
733+ [ insertText , uploadNewFiles ] ,
710734 ) ;
711735
712736 const isUploadEnabled = channel ?. getConfig ?. ( ) ?. uploads !== false ;
0 commit comments