11import { consume } from '@lit/context' ;
22import { html , LitElement , nothing } from 'lit' ;
33import { query , state } from 'lit/decorators.js' ;
4+ import { ifDefined } from 'lit/directives/if-defined.js' ;
5+ import { createRef , ref } from 'lit/directives/ref.js' ;
46import { addThemingController } from '../../theming/theming-controller.js' ;
57import IgcIconButtonComponent from '../button/icon-button.js' ;
68import IgcChipComponent from '../chip/chip.js' ;
@@ -19,6 +21,7 @@ import {
1921 attachmentIcon ,
2022 fileDocumentIcon ,
2123 fileImageIcon ,
24+ type IgcMessageAttachment ,
2225 sendButtonIcon ,
2326 starIcon ,
2427} from './types.js' ;
@@ -76,6 +79,8 @@ export default class IgcChatInputComponent extends LitElement {
7679
7780 @query ( '#input_attachments' )
7881 protected _inputAttachmentsButton ! : IgcIconButtonComponent ;
82+ // private readonly _textAreaRef = createRef<IgcTextareaComponent>();
83+ private readonly _attachmentsButtonInputRef = createRef < HTMLInputElement > ( ) ;
7984
8085 // private readonly _textAreaRef = createRef<IgcTextareaComponent>();
8186
@@ -187,24 +192,131 @@ export default class IgcChatInputComponent extends LitElement {
187192 this . requestUpdate ( ) ;
188193 }
189194
195+ /**
196+ * Handles input text changes.
197+ * Updates internal inputValue and emits 'igcInputChange' event.
198+ * @param e Input event from the text area
199+ */
200+ private handleInput = ( { detail } : CustomEvent < string > ) => {
201+ if ( detail === this . _chatState ?. inputValue ) return ;
202+
203+ this . _chatState . inputValue = detail ;
204+ this . _chatState ?. emitEvent ( 'igcInputChange' , { detail : { value : detail } } ) ;
205+ } ;
206+
207+ private handleFileUpload = ( e : Event ) => {
208+ const input = e . target as HTMLInputElement ;
209+ if ( ! input . files || input . files . length === 0 ) return ;
210+
211+ const files = Array . from ( input . files ) ;
212+ this . _chatState ?. attachFiles ( files ) ;
213+ } ;
214+ /**
215+ * Default attachments area template used when no custom template is provided.
216+ * Renders the list of input attachments as chips.
217+ * @returns TemplateResult containing the attachments area
218+ */
219+ private renderAttachmentsArea ( attachments : IgcMessageAttachment [ ] ) {
220+ return html `${ attachments ?. map (
221+ ( attachment , index ) => html `
222+ < div part ="attachment-wrapper " role ="listitem ">
223+ < igc-chip
224+ removable
225+ @igcRemove =${ ( ) => this . _chatState ?. removeAttachment ( index ) }
226+ >
227+ < igc-icon
228+ slot ="prefix "
229+ name =${ this . _chatState ?. getIconName (
230+ attachment . file ?. type ?? attachment . type
231+ ) }
232+ collection ="material"
233+ > </ igc-icon >
234+ < span part ="attachment-name "> ${ attachment . name } </ span >
235+ </ igc-chip >
236+ </ div >
237+ `
238+ ) } `;
239+ }
240+
241+ /**
242+ * Default text area template used when no custom template is provided.
243+ * Renders a text area for user input.
244+ * @returns TemplateResult containing the text area
245+ */
246+ private renderTextArea ( ) {
247+ return html ` < igc-textarea
248+ part ="text-input "
249+ .placeholder =${ this . _chatState ?. options ?. inputPlaceholder }
250+ resize ="auto"
251+ rows="1"
252+ .value=${ this . _chatState ?. inputValue }
253+ @igcInput=${ this . handleInput }
254+ @focus=${ ( ) => this . _chatState ?. emitEvent ( 'igcInputFocus' ) }
255+ @blur=${ ( ) => this . _chatState ?. emitEvent ( 'igcInputBlur' ) }
256+ > </ igc-textarea > ` ;
257+ }
258+
259+ /**
260+ * Default file upload button template used when no custom template is provided.
261+ * Renders a file input for attaching files.
262+ * @returns TemplateResult containing the file upload button
263+ */
264+ private renderFileUploadButton ( ) {
265+ if ( this . _chatState ?. options ?. disableInputAttachments ) return html `` ;
266+ return html `
267+ < label for ="input_attachments " part ="upload-button ">
268+ < igc-icon-button
269+ variant ="flat "
270+ name ="attachment "
271+ collection ="material "
272+ @click =${ ( ) => this . _attachmentsButtonInputRef ?. value ?. click ( ) }
273+ > </ igc-icon-button >
274+ < input
275+ type ="file "
276+ id ="input_attachments "
277+ name ="input_attachments "
278+ ${ ref ( this . _attachmentsButtonInputRef ) }
279+ multiple
280+ accept =${ ifDefined ( this . _chatState ?. options ?. acceptedFiles === '' ? undefined : this . _chatState ?. options ?. acceptedFiles ) }
281+ @change =${ this . handleFileUpload } >
282+ </ input >
283+ </ label >
284+ ` ;
285+ }
286+
287+ /**
288+ * Default send button template used when no custom template is provided.
289+ * Renders a send button that submits the current input value and attachments.
290+ * @returns TemplateResult containing the send button
291+ */
292+ private renderSendButton ( ) {
293+ return html ` < igc-icon-button
294+ aria-label ="Send message "
295+ name ="send-message "
296+ collection ="material "
297+ variant ="contained "
298+ part ="send-button "
299+ ?disabled =${ ! this . _chatState ?. inputValue . trim ( ) &&
300+ this . _chatState ?. inputAttachments . length === 0 }
301+ @click =${ this . _chatState ?. sendMessage }
302+ > </ igc-icon-button > ` ;
303+ }
304+
305+ private renderActionsArea ( ) {
306+ return html ` ${ this . renderFileUploadButton ( ) } ${ this . renderSendButton ( ) } ` ;
307+ }
308+
190309 protected override render ( ) {
191- const templates = this . _chatState . mergedTemplates ;
192310 return html `
193311 < div part ="${ this . containerPart } ">
194312 ${ this . _chatState . inputAttachments &&
195313 this . _chatState . inputAttachments . length > 0
196314 ? html ` < div part ="attachments " role ="list " aria-label ="Attachments ">
197- ${ templates ?. textAreaAttachmentsTemplate (
198- this . _chatState . inputAttachments
199- ) }
315+ ${ this . renderAttachmentsArea ( this . _chatState . inputAttachments ) }
200316 </ div > `
201317 : nothing }
202- < div part ="input-wrapper ">
203- ${ templates ?. textInputTemplate ( this . _chatState . inputValue ?? '' ) }
204- </ div >
205- < div part ="buttons-container ">
206- ${ templates ?. textAreaActionsTemplate ( ) }
207- </ div >
318+ < div part ="input-wrapper "> ${ this . renderTextArea ( ) } </ div >
319+ < div part ="buttons-container "> ${ this . renderActionsArea ( ) } </ div >
208320 </ div >
209321 ` ;
210322 }
0 commit comments