@@ -21,12 +21,23 @@ import type { SupportedKeys } from '@ts/core/widget/widget';
2121import Widget from '@ts/core/widget/widget' ;
2222import FileUploader from '@ts/ui/file_uploader/file_uploader' ;
2323import type { CancelButtonClickEvent , Properties as FileUploaderProperties } from '@ts/ui/file_uploader/file_uploader.types' ;
24+ import Informer from '@ts/ui/informer/informer' ;
2425import type { TextAreaProperties } from '@ts/ui/m_text_area' ;
2526import TextArea from '@ts/ui/m_text_area' ;
2627
27- export const TEXT_AREA_TOOLBAR = 'dx-textarea-toolbar' ;
28- const TEXT_AREA_ATTACHMENTS = 'dx-textarea-attachments' ;
29- const TEXT_AREA_ATTACH_BUTTON = 'dx-textarea-attach-button' ;
28+ const CHAT_TEXT_AREA_ATTACHMENTS = 'dx-chat-textarea-attachments' ;
29+ export const CHAT_TEXT_AREA_ATTACH_BUTTON = 'dx-chat-textarea-attach-button' ;
30+
31+ export const CHAT_TEXTAREA_CLASS = 'dx-chat-textarea' ;
32+ export const CHAT_TEXT_AREA_TOOLBAR = 'dx-chat-textarea-toolbar' ;
33+
34+ const MAX_ATTACHMENTS_COUNT = 10 ;
35+ const INFORMER_DELAY = 10000 ;
36+
37+ const ERRORS = {
38+ // @ts -expect-error format params should be extended
39+ fileLimit : messageLocalization . format ( 'dxChat-fileLimitReachedWarning' , MAX_ATTACHMENTS_COUNT ) ,
40+ } ;
3041
3142const isMobile = ( ) : boolean => devices . current ( ) . deviceType !== 'desktop' ;
3243
@@ -45,6 +56,11 @@ export type Properties = TextAreaProperties & {
4556} ;
4657
4758class ChatTextArea extends TextArea < Properties > {
59+ // eslint-disable-next-line no-restricted-globals
60+ _informerTimeoutId ?: ReturnType < typeof setTimeout > | undefined ;
61+
62+ _informer ?: Informer | null ;
63+
4864 _$toolbar ?: dxElementWrapper | null ;
4965
5066 _toolbar ?: Toolbar | null ;
@@ -57,7 +73,7 @@ class ChatTextArea extends TextArea<Properties> {
5773
5874 _sendButton ?: Button ;
5975
60- _sendAction ?: ( e : SendEvent ) => void ;
76+ _sendAction ?: ( e : Partial < SendEvent > ) => void ;
6177
6278 getAttachments ( ) : Attachment [ ] | undefined {
6379 if ( ! this . _filesToSend ?. size ) {
@@ -75,8 +91,8 @@ class ChatTextArea extends TextArea<Properties> {
7591 stylingMode : 'outlined' ,
7692 placeholder : messageLocalization . format ( 'dxChat-textareaPlaceholder' ) ,
7793 autoResizeEnabled : true ,
78- maxHeight : '8em' ,
7994 valueChangeEvent : 'input' ,
95+ maxHeight : '16em' ,
8096 fileUploaderOptions : undefined ,
8197 } ;
8298 }
@@ -114,11 +130,7 @@ class ChatTextArea extends TextArea<Properties> {
114130 }
115131
116132 if ( this . _shouldSendMessageOnEnter ( e ) ) {
117- this . _processSendButtonActivation ( {
118- component : this ,
119- element : this . element ( ) ,
120- event : e ,
121- } ) ;
133+ this . _processSendButtonActivation ( { event : e } ) ;
122134 }
123135 }
124136
@@ -136,11 +148,46 @@ class ChatTextArea extends TextArea<Properties> {
136148 }
137149
138150 _initMarkup ( ) : void {
151+ this . $element ( ) . addClass ( CHAT_TEXTAREA_CLASS ) ;
139152 super . _initMarkup ( ) ;
140153 this . _renderToolbar ( ) ;
141154 this . _initFileUploader ( ) ;
142155 }
143156
157+ _showInformer ( text : string ) : void {
158+ if ( this . _informer ) {
159+ this . _informer . option ( { text } ) ;
160+ } else {
161+ this . _renderInformer ( text ) ;
162+ }
163+
164+ this . _updateInformerTimeout ( ) ;
165+ }
166+
167+ _renderInformer ( text : string ) : void {
168+ const $informer = $ ( '<div>' ) . prependTo ( this . $element ( ) ) ;
169+
170+ this . _informer = this . _createComponent (
171+ $informer ,
172+ Informer ,
173+ {
174+ text,
175+ contentAlignment : 'start' ,
176+ icon : 'errorcircle' ,
177+ } ,
178+ ) ;
179+ }
180+
181+ _updateInformerTimeout ( ) : void {
182+ clearTimeout ( this . _informerTimeoutId ) ;
183+
184+ // eslint-disable-next-line no-restricted-globals
185+ this . _informerTimeoutId = setTimeout ( ( ) => {
186+ this . _cleanInformer ( ) ;
187+ this . _updateInputHeight ( ) ;
188+ } , INFORMER_DELAY ) ;
189+ }
190+
144191 _renderToolbar ( ) : void {
145192 const toolbarItems = this . _getToolbarItems ( ) ;
146193
@@ -149,7 +196,7 @@ class ChatTextArea extends TextArea<Properties> {
149196 } ;
150197
151198 this . _$toolbar = $ ( '<div>' )
152- . addClass ( TEXT_AREA_TOOLBAR )
199+ . addClass ( CHAT_TEXT_AREA_TOOLBAR )
153200 . appendTo ( this . $element ( ) ) ;
154201
155202 this . _toolbar = this . _createComponent (
@@ -167,13 +214,13 @@ class ChatTextArea extends TextArea<Properties> {
167214 ] ;
168215
169216 if ( fileUploaderOptions ) {
170- items . push ( this . _getFileUploaderButtonConfig ( ) ) ;
217+ items . push ( this . _getAttachButtonConfig ( ) ) ;
171218 }
172219
173220 return items ;
174221 }
175222
176- _getFileUploaderButtonConfig ( ) : ToolbarItem {
223+ _getAttachButtonConfig ( ) : ToolbarItem {
177224 const {
178225 activeStateEnabled,
179226 focusStateEnabled,
@@ -187,8 +234,12 @@ class ChatTextArea extends TextArea<Properties> {
187234 activeStateEnabled,
188235 focusStateEnabled,
189236 hoverStateEnabled,
190- elementAttr : { class : TEXT_AREA_ATTACH_BUTTON } ,
237+ elementAttr : { class : CHAT_TEXT_AREA_ATTACH_BUTTON } ,
191238 icon : 'attach' ,
239+ onClick : ( ) : void => {
240+ this . _cleanInformer ( ) ;
241+ this . _updateInputHeight ( ) ;
242+ } ,
192243 } ,
193244 } as ToolbarItem ;
194245
@@ -241,7 +292,7 @@ class ChatTextArea extends TextArea<Properties> {
241292
242293 _renderFileUploader ( ) : void {
243294 this . _$fileUploader = $ ( '<div>' )
244- . addClass ( TEXT_AREA_ATTACHMENTS )
295+ . addClass ( CHAT_TEXT_AREA_ATTACHMENTS )
245296 . insertBefore ( this . _$textEditorContainer ) ;
246297
247298 this . _fileUploader = this . _createComponent (
@@ -257,6 +308,7 @@ class ChatTextArea extends TextArea<Properties> {
257308
258309 _getFileUploaderOptions ( ) : FileUploaderProperties {
259310 const { fileUploaderOptions = { } } = this . option ( ) ;
311+
260312 const multiple = fileUploaderOptions . multiple ?? true ;
261313 const visible = this . _shouldHideFileUploader ( fileUploaderOptions . value ) ;
262314
@@ -265,14 +317,16 @@ class ChatTextArea extends TextArea<Properties> {
265317 multiple,
266318 visible,
267319 uploadMode : 'instantly' ,
268- dialogTrigger : this . $element ( ) . find ( `.${ TEXT_AREA_ATTACH_BUTTON } ` ) . get ( 0 ) ,
320+ dialogTrigger : this . $element ( ) . find ( `.${ CHAT_TEXT_AREA_ATTACH_BUTTON } ` ) . get ( 0 ) ,
269321 _hideCancelButtonOnUpload : false ,
270322 _showFileIcon : true ,
271323 _cancelButtonPosition : 'end' ,
324+ _maxFileCount : MAX_ATTACHMENTS_COUNT ,
272325 onValueChanged : ( e ) => this . _fileUploaderOnValueChanged ( e ) ,
273326 onUploadStarted : ( e ) => this . _fileUploaderOnUploadStarted ( e ) ,
274327 onUploaded : ( e ) => this . _fileUploaderOnUploaded ( e ) ,
275328 onCancelButtonClick : ( e ) => this . _fileUploaderOnCancelButtonClick ( e ) ,
329+ onFileLimitReached : ( ) => this . _fileUploaderFileLimitReached ( ) ,
276330 } ;
277331 }
278332
@@ -326,6 +380,11 @@ class ChatTextArea extends TextArea<Properties> {
326380 this . _toggleButtonDisableState ( ) ;
327381 } ;
328382
383+ _fileUploaderFileLimitReached ( ) : void {
384+ this . _showInformer ( ERRORS . fileLimit ) ;
385+ this . _updateInputHeight ( ) ;
386+ }
387+
329388 _toggleButtonDisableState ( state ?: boolean ) : void {
330389 const shouldDisable = state ?? ! this . _isMessageCanBeSent ( ) ;
331390 this . _sendButton ?. option ( 'disabled' , shouldDisable ) ;
@@ -334,12 +393,28 @@ class ChatTextArea extends TextArea<Properties> {
334393 _renderButtonContainers ( ) : void { }
335394
336395 _getHeightDifference ( $input : dxElementWrapper ) : number {
337- const superResult = super . _getHeightDifference ( $input ) ;
338- const toolbarHeight = getOuterHeight ( this . _$toolbar ) ;
396+ const baseDifference = super . _getHeightDifference ( $input ) ;
397+
398+ const gap = parseFloat ( this . $element ( ) . css ( 'gap' ) ?? '0' ) ;
399+
400+ const informerHeight = this . _informer ? getOuterHeight ( this . _informer . $element ( ) ) : 0 ;
339401 const fileUploaderHeight = getOuterHeight ( this . _$fileUploader ) ;
340- const sum : number = superResult + toolbarHeight + fileUploaderHeight ;
402+ const toolbarHeight = getOuterHeight ( this . _$toolbar ) ;
403+
404+ const visibleSections = [
405+ toolbarHeight ,
406+ informerHeight ,
407+ fileUploaderHeight ,
408+ ] . filter ( Boolean ) . length ;
341409
342- return sum ;
410+ const totalExtraHeight = toolbarHeight
411+ + informerHeight
412+ + fileUploaderHeight
413+ + visibleSections * gap ;
414+
415+ const difference : number = baseDifference + totalExtraHeight ;
416+
417+ return difference ;
343418 }
344419
345420 _keyPressHandler ( e : InputEvent ) : void {
@@ -348,7 +423,7 @@ class ChatTextArea extends TextArea<Properties> {
348423 this . _toggleButtonDisableState ( ) ;
349424 }
350425
351- _processSendButtonActivation ( e : SendEvent ) : void {
426+ _processSendButtonActivation ( e : Partial < SendEvent > ) : void {
352427 this . _sendAction ?.( e ) ;
353428 this . reset ( ) ;
354429 this . _fileUploader ?. reset ( ) ;
@@ -437,6 +512,23 @@ class ChatTextArea extends TextArea<Properties> {
437512 this . _$fileUploader = null ;
438513 }
439514
515+ _cleanInformer ( ) : void {
516+ this . _clearInformerTimeout ( ) ;
517+ this . _removeInformer ( ) ;
518+ }
519+
520+ _removeInformer ( ) : void {
521+ this . _informer ?. dispose ( ) ;
522+ this . _informer ?. $element ( ) . remove ( ) ;
523+ this . _informer = null ;
524+ }
525+
526+ _clearInformerTimeout ( ) : void {
527+ clearTimeout ( this . _informerTimeoutId ) ;
528+
529+ this . _informerTimeoutId = undefined ;
530+ }
531+
440532 _cleanToolbar ( ) : void {
441533 this . _toolbar ?. dispose ( ) ;
442534 this . _$toolbar ?. remove ( ) ;
@@ -447,6 +539,7 @@ class ChatTextArea extends TextArea<Properties> {
447539 _dispose ( ) : void {
448540 this . _cleanFileUploader ( ) ;
449541 this . _cleanToolbar ( ) ;
542+ this . _cleanInformer ( ) ;
450543 super . _dispose ( ) ;
451544 }
452545}
0 commit comments