@carbon/ai-chat 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/docs/carbon-chat-docs.js +1 -1
  2. package/dist/docs/carbon-chat.html +1 -1
  3. package/dist/es/AppContainer.js +7 -7
  4. package/dist/es/Avatar.js +90 -0
  5. package/dist/es/BodyAndFooterPanelComponent.js +118 -0
  6. package/dist/es/BrandingOverlay.js +108 -0
  7. package/dist/es/Carousel.js +2 -2
  8. package/dist/es/CatastrophicError.js +153 -0
  9. package/dist/es/Chat.js +2288 -0
  10. package/dist/es/Disclaimer.js +213 -0
  11. package/dist/es/GenesysMessengerServiceDesk.js +2 -2
  12. package/dist/es/HomeScreenContainer.js +180 -0
  13. package/dist/es/HumanAgentServiceImpl.js +2 -2
  14. package/dist/es/IFrameComponent.js +91 -0
  15. package/dist/es/IFramePanel.js +75 -0
  16. package/dist/es/InlineError.js +41 -0
  17. package/dist/es/Input.js +537 -0
  18. package/dist/es/MessageTypeComponent.js +6492 -0
  19. package/dist/es/NiceDFOServiceDesk.js +2 -2
  20. package/dist/es/PDFViewerContainer.js +2 -2
  21. package/dist/es/ReactPlayer.js +2 -2
  22. package/dist/es/RichText.js +24801 -0
  23. package/dist/es/SFServiceDesk.js +2 -2
  24. package/dist/es/SearchResultBody.js +142 -0
  25. package/dist/es/ServiceDeskImpl.js +2 -2
  26. package/dist/es/TourContainer.js +429 -0
  27. package/dist/es/VideoComponent.js +241 -0
  28. package/dist/es/ViewSourcePanel.js +85 -0
  29. package/dist/es/ZendeskServiceDesk.js +2 -2
  30. package/dist/es/_node-resolve_empty.js +2 -2
  31. package/dist/es/aiChatEntry.js +2 -2
  32. package/dist/es/ar-dz.js +2 -2
  33. package/dist/es/ar-kw.js +2 -2
  34. package/dist/es/ar-ly.js +2 -2
  35. package/dist/es/ar-ma.js +2 -2
  36. package/dist/es/ar-sa.js +2 -2
  37. package/dist/es/ar-tn.js +2 -2
  38. package/dist/es/ar.js +2 -2
  39. package/dist/es/ar2.js +2 -2
  40. package/dist/es/cds-aichat-code.js +103 -0
  41. package/dist/es/cds-aichat-container.js +3 -3
  42. package/dist/es/cds-aichat-custom-element.js +2 -2
  43. package/dist/es/common.js +15342 -0
  44. package/dist/es/cs.js +2 -2
  45. package/dist/es/cs2.js +2 -2
  46. package/dist/es/customElement.js +2 -2
  47. package/dist/es/de-at.js +2 -2
  48. package/dist/es/de-ch.js +2 -2
  49. package/dist/es/de.js +2 -2
  50. package/dist/es/de2.js +2 -2
  51. package/dist/es/decode.js +561 -0
  52. package/dist/es/en-au.js +2 -2
  53. package/dist/es/en-ca.js +2 -2
  54. package/dist/es/en-gb.js +2 -2
  55. package/dist/es/en-ie.js +2 -2
  56. package/dist/es/en-il.js +2 -2
  57. package/dist/es/en-nz.js +2 -2
  58. package/dist/es/es-do.js +2 -2
  59. package/dist/es/es-us.js +2 -2
  60. package/dist/es/es.js +2 -2
  61. package/dist/es/es2.js +2 -2
  62. package/dist/es/export.carbon.js +2 -2
  63. package/dist/es/export.js +3 -3
  64. package/dist/es/export.legacy.carbon.js +2 -2
  65. package/dist/es/export.legacy.js +3 -3
  66. package/dist/es/fr-ca.js +2 -2
  67. package/dist/es/fr-ch.js +2 -2
  68. package/dist/es/fr.js +2 -2
  69. package/dist/es/fr2.js +2 -2
  70. package/dist/es/it-ch.js +2 -2
  71. package/dist/es/it.js +2 -2
  72. package/dist/es/it2.js +2 -2
  73. package/dist/es/ja.js +2 -2
  74. package/dist/es/ja2.js +2 -2
  75. package/dist/es/ko.js +2 -2
  76. package/dist/es/ko2.js +2 -2
  77. package/dist/es/markdown.js +9323 -0
  78. package/dist/es/markdown.worker.js +66 -0
  79. package/dist/es/mockServiceDesk.js +2 -2
  80. package/dist/es/moduleFederationPluginUtils.js +159 -0
  81. package/dist/es/nl.js +2 -2
  82. package/dist/es/nl2.js +2 -2
  83. package/dist/es/pt-br.js +2 -2
  84. package/dist/es/pt-br2.js +2 -2
  85. package/dist/es/pt.js +2 -2
  86. package/dist/es/scriptRender.js +2 -2
  87. package/dist/es/tokenTree.js +143 -0
  88. package/dist/es/useCounter.js +37 -0
  89. package/dist/es/useWindowSize.js +30 -0
  90. package/dist/es/zh-cn.js +2 -2
  91. package/dist/es/zh-tw.js +2 -2
  92. package/dist/es/zh-tw2.js +2 -2
  93. package/dist/es/zh.js +2 -2
  94. package/package.json +1 -1
@@ -0,0 +1,537 @@
1
+ /**
2
+ * @license
3
+ *
4
+ * (C) Copyright IBM Corp. 2017, 2025. All Rights Reserved.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7
+ * in compliance with the License. You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
12
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13
+ * or implied. See the License for the specific language governing permissions and limitations under
14
+ * the License.
15
+ *
16
+ * @carbon/ai-chat 0.3.2
17
+ *
18
+ * Built: Jul 9 2025 11:10 am -04:00
19
+ *
20
+ *
21
+ */
22
+
23
+ import Attachment from '@carbon/icons-react/es/Attachment.js';
24
+ import Send from '@carbon/icons-react/es/Send.js';
25
+ import SendFilled from '@carbon/icons-react/es/SendFilled.js';
26
+ import { Tag, FileUploaderItem, Button } from '@carbon/react';
27
+ import { aR as CSS_CLASS_PREFIX, aE as ButtonKindEnum, aH as ButtonSizeEnum, aS as bind_1, aa as doFocusRef, Z as cx, aT as TagSize, w as actions, aU as isEnterKey, j as consoleError, ax as IS_MOBILE, aV as selectIsInputToAgent, aQ as uuid, aW as UUIDType, aX as isValidForUpload, aY as doScrollElementIntoView } from './AppContainer.js';
28
+ import React__default, { PureComponent, forwardRef, useState, useRef, useImperativeHandle } from 'react';
29
+ import { _ as __decorate, c as carbonElement, o, i as FileStatusValue } from './customElement.js';
30
+ import '@carbon/web-components/es-custom/components/icon-button/index.js';
31
+ import { toString } from '@carbon/icon-helpers';
32
+ import StopFilled16 from '@carbon/icons/es/stop--filled/16.js';
33
+ import { html, LitElement, css, unsafeCSS } from 'lit';
34
+ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
35
+ import { property } from 'lit/decorators.js';
36
+ import { u as useCounter } from './useCounter.js';
37
+
38
+ const StopFilled16svg = toString(StopFilled16);
39
+ function stopStreamingButtonTemplate({ label, disabled, tooltipAlignment, onClick, }) {
40
+ return html `
41
+ <cds-custom-icon-button
42
+ class="${CSS_CLASS_PREFIX}-stop-streaming-button"
43
+ align="${tooltipAlignment}"
44
+ kind="${ButtonKindEnum.GHOST}"
45
+ size="${ButtonSizeEnum.SMALL}"
46
+ ?disabled=${disabled}
47
+ @click="${onClick}"
48
+ >
49
+ <span class="${disabled ? `${CSS_CLASS_PREFIX}-stop-icon` : ''}" slot="icon">${unsafeSVG(StopFilled16svg)}</span>
50
+ <span slot="tooltip-content">${label}</span>
51
+ </cds-custom-icon-button>
52
+ `;
53
+ }
54
+
55
+ var css_248z = ".cds--aichat-stop-icon svg{fill:var(--cds-icon-disabled,hsla(0,0%,9%,.25))}";
56
+
57
+ class StopStreamingButtonElement extends LitElement {
58
+ static { this.styles = css `
59
+ ${unsafeCSS(css_248z)}
60
+ `; }
61
+ /**
62
+ * Called when the user clicks the stop streaming button.
63
+ */
64
+ _handleOnClick() {
65
+ this.onClick();
66
+ }
67
+ }
68
+ __decorate([
69
+ property({ type: String, attribute: 'label' })
70
+ ], StopStreamingButtonElement.prototype, "label", void 0);
71
+ __decorate([
72
+ property({ type: String, attribute: 'tooltip-alignment' })
73
+ ], StopStreamingButtonElement.prototype, "tooltipAlignment", void 0);
74
+ __decorate([
75
+ property({ type: Boolean, attribute: 'disabled' })
76
+ ], StopStreamingButtonElement.prototype, "disabled", void 0);
77
+ __decorate([
78
+ property({ type: Object })
79
+ ], StopStreamingButtonElement.prototype, "onClick", void 0);
80
+ __decorate([
81
+ bind_1
82
+ ], StopStreamingButtonElement.prototype, "_handleOnClick", null);
83
+
84
+ const STOP_STREAMING_BUTTON_TAG_NAME = 'cds-aichat-stop-streaming-button';
85
+ /**
86
+ * Constructed class functionality for the stop streaming button.
87
+ */
88
+ let CDSChatStopStreamingButtonElement = class CDSChatStopStreamingButtonElement extends StopStreamingButtonElement {
89
+ render() {
90
+ return stopStreamingButtonTemplate(this);
91
+ }
92
+ };
93
+ CDSChatStopStreamingButtonElement = __decorate([
94
+ carbonElement(STOP_STREAMING_BUTTON_TAG_NAME)
95
+ ], CDSChatStopStreamingButtonElement);
96
+ var CDSChatStopStreamingButtonElement$1 = CDSChatStopStreamingButtonElement;
97
+
98
+ const StopStreamingButton = o({
99
+ tagName: 'cds-aichat-stop-streaming-button',
100
+ elementClass: CDSChatStopStreamingButtonElement$1,
101
+ react: React__default,
102
+ });
103
+
104
+ /**
105
+ * A simple class that can track a set of listeners and then fire them when needed.
106
+ */
107
+ class ListenerList {
108
+ constructor() {
109
+ /**
110
+ * The current set of listeners.
111
+ */
112
+ this.listeners = [];
113
+ }
114
+ /**
115
+ * Adds the given listener to the list.
116
+ */
117
+ addListener(listenerToAdd) {
118
+ this.listeners = [...this.listeners, listenerToAdd];
119
+ }
120
+ /**
121
+ * Removes all occurrences of the given listener from the list.
122
+ */
123
+ removeListener(listenerToRemove) {
124
+ this.listeners = this.listeners.filter(listener => listener !== listenerToRemove);
125
+ }
126
+ /**
127
+ * Calls all the listeners in the list passing each the given arguments.
128
+ */
129
+ fireListeners(...args) {
130
+ if (this.listeners.length) {
131
+ this.listeners.forEach(listener => listener(...args));
132
+ }
133
+ }
134
+ }
135
+
136
+ class TextArea extends PureComponent {
137
+ constructor() {
138
+ super(...arguments);
139
+ /**
140
+ * A React ref to the TextArea component.
141
+ */
142
+ this.textAreaRef = React__default.createRef();
143
+ }
144
+ static { this.defaultProps = {
145
+ // Default value for whether input in the text area is required before form submission.
146
+ isRequired: false,
147
+ // Default max character length for a text area is 10,000 characters.
148
+ maxLength: 10000,
149
+ }; }
150
+ /**
151
+ * Returns the HTML element.
152
+ */
153
+ getHTMLElement() {
154
+ return this.textAreaRef.current;
155
+ }
156
+ /**
157
+ * Instructs this component to put focus into the input text area.
158
+ */
159
+ takeFocus() {
160
+ doFocusRef(this.textAreaRef, false, true);
161
+ }
162
+ /**
163
+ * Causes the text area to blur.
164
+ */
165
+ doBlur() {
166
+ this.textAreaRef.current.blur();
167
+ }
168
+ render() {
169
+ const { isRequired, name, id, onFocus, onBlur, onClick, onChange, onKeyDown, rows, value, autoSize, maxLength, disabled, placeholder, ariaLabel, testId, onSelect, } = this.props;
170
+ // The extra ' ' in the sizer div below makes sure there's at least a space in the area to ensure that we get a
171
+ // min-height of one line of text.
172
+ return (React__default.createElement("div", { className: cx('WAC__TextArea', { 'WAC__TextArea--autoSize': autoSize, 'WAC__TextArea--disabled': disabled }) },
173
+ React__default.createElement("textarea", { ref: this.textAreaRef, "aria-label": ariaLabel, "aria-required": isRequired, className: "WAC__TextArea-textarea", disabled: disabled, id: id, maxLength: maxLength, name: name, onFocus: onFocus, onBlur: onBlur, onClick: onClick, onChange: onChange, onKeyDown: onKeyDown, onSelect: onSelect, placeholder: placeholder, rows: rows, value: value || '', "data-enable-grammarly": false, "data-test-id": testId }),
174
+ autoSize && React__default.createElement("div", { className: "WAC__TextArea-sizer" }, value || placeholder || ' ')));
175
+ }
176
+ }
177
+
178
+ /**
179
+ * The size of the gap between input changes before we indicate that the user has stopped typing.
180
+ */
181
+ const STOP_TYPING_PERIOD = 5000;
182
+ /**
183
+ * The maximum number of characters to all the user to enter into the input field. The number was chosen to match
184
+ * the limit imposed by the API.
185
+ */
186
+ const INPUT_MAX_CHARS = 2048;
187
+ function Input(props, ref) {
188
+ const { inputType, isInputVisible, placeholder, disableInput, disableSend, disableUploadButton, pendingUploads, allowedFileUploadTypes, allowMultipleFileUploads, showUploadButton, onFilesSelectedForUpload, onSendInput, blurOnSend, serviceManager, onUserTyping, languagePack, inputCustomizations, isStopStreamingButtonVisible, isStopStreamingButtonDisabled, } = props;
189
+ const { onBeforeSend, getCompletions, onCompletionSelected } = inputCustomizations || {};
190
+ const inputID = `${serviceManager.namespace.suffix}-${useCounter()}`;
191
+ // Indicates if the text area currently has focus.
192
+ const [textAreaHasFocus, setTextAreaHasFocus] = useState(false);
193
+ // The current controlled value of the text area.
194
+ const [inputValue, setInputValue] = useState('');
195
+ // Indicates if handling of the enter key is enabled or not. If it's enabled, this component will call the
196
+ // onSendInput prop when a press of the enter key is detected.
197
+ const enterKeyEnabled = useRef(true);
198
+ // Indicates the user is currently typing.
199
+ const isTypingTimeout = useRef(null);
200
+ // A React ref to the TextArea component.
201
+ const textAreaRef = useRef();
202
+ // A React ref to the file Input element.
203
+ const fileInputRef = useRef();
204
+ // An array of functions that will be called when the text value changes.
205
+ const changeListeners = useRef(new ListenerList());
206
+ // The last text value that was sent to the change listeners.
207
+ const lastValue = useRef('');
208
+ // The reusable {@link InstanceInputElement} object that allows access and control over the input.
209
+ const instanceInputElement = useRef(createInstanceInputElement());
210
+ // A ref to the last completion Promise that was made.
211
+ const lastCompletion = useRef(null);
212
+ // A ref to the list box for the completions popup.
213
+ const completionsPopupRef = useRef(null);
214
+ // The current list of completions to display in the completions popup.
215
+ const [completionResults, setCompletionResults] = useState(null);
216
+ // The index of the currently highlighted completion. A value of -1 means none.
217
+ const [highlightedCompletion, setHighlightedCompletion] = useState(-1);
218
+ /**
219
+ * Scrolls the completion at the given index into view.
220
+ */
221
+ function scrollCompletion(index) {
222
+ const element = completionsPopupRef.current?.querySelector(`.WACInputCompletion:nth-child(${index + 1})`);
223
+ doScrollElementIntoView(element);
224
+ }
225
+ /**
226
+ * Closes the completion list and cancels any outstanding request.
227
+ */
228
+ function closeCompletions() {
229
+ if (completionResults) {
230
+ setCompletionResults(null);
231
+ setHighlightedCompletion(-1);
232
+ }
233
+ if (lastCompletion.current) {
234
+ lastCompletion.current.cancelled = true;
235
+ lastCompletion.current = null;
236
+ }
237
+ }
238
+ /**
239
+ * This is called when we have detected that the user has stopped typing.
240
+ */
241
+ function doTypingStopped() {
242
+ if (isTypingTimeout.current) {
243
+ clearTimeout(isTypingTimeout.current);
244
+ isTypingTimeout.current = null;
245
+ onUserTyping?.(false);
246
+ }
247
+ }
248
+ function doCompletionSelected(completionResults, index) {
249
+ const { completionStart, completionEnd, completions } = completionResults;
250
+ const completion = completions[index];
251
+ const { targetValue } = completion;
252
+ const newInput = inputValue.substring(0, completionStart) + targetValue + inputValue.substring(completionEnd, inputValue.length);
253
+ closeCompletions();
254
+ setInputValue(newInput);
255
+ onCompletionSelected?.(completion);
256
+ // Move the cursor to the end up the completion we just inserted.
257
+ setTimeout(() => {
258
+ const cursorPosition = completionStart + targetValue.length;
259
+ textAreaRef.current.getHTMLElement().setSelectionRange(cursorPosition, cursorPosition);
260
+ });
261
+ }
262
+ /**
263
+ * This is a callback which is called on each keydown event that occurs on the text area. This is used to capture
264
+ * the enter key, so we can send the entered text to the server.
265
+ */
266
+ function onKeyDown(event) {
267
+ if (isEnterKey(event)) {
268
+ if (highlightedCompletion !== -1) {
269
+ doCompletionSelected(completionResults, highlightedCompletion);
270
+ event.preventDefault();
271
+ }
272
+ else if (disableSend || !enterKeyEnabled.current) {
273
+ // If sending is disabled, stop the field from inserting a newline into the field.
274
+ event.preventDefault();
275
+ }
276
+ else {
277
+ send(event);
278
+ }
279
+ }
280
+ else if (completionResults) {
281
+ switch (event.key) {
282
+ case 'ArrowUp': {
283
+ setHighlightedCompletion(currentValue => {
284
+ const newValue = currentValue <= 0 ? completionResults.completions.length - 1 : currentValue - 1;
285
+ scrollCompletion(newValue);
286
+ return newValue;
287
+ });
288
+ event.preventDefault();
289
+ break;
290
+ }
291
+ case 'ArrowDown': {
292
+ setHighlightedCompletion(currentValue => {
293
+ const newValue = currentValue >= completionResults.completions.length - 1 ? 0 : currentValue + 1;
294
+ scrollCompletion(newValue);
295
+ return newValue;
296
+ });
297
+ event.preventDefault();
298
+ break;
299
+ }
300
+ case 'ArrowLeft':
301
+ case 'ArrowRight':
302
+ case 'Home':
303
+ case 'End':
304
+ case 'Escape': {
305
+ // If the user tries to move the cursor or presses escape, close the completions. We close on changes to
306
+ // the cursor since it can be a little awkward if the user moves the cursor but then selects a value from
307
+ // the completions list which will not be inserted where the cursor is. This also happens if a click
308
+ // occurs on the input field.
309
+ closeCompletions();
310
+ break;
311
+ }
312
+ }
313
+ }
314
+ }
315
+ /**
316
+ * This is a callback which is called when a change event occurs on the textarea inside this input.
317
+ */
318
+ function onChange(event) {
319
+ const inputText = event.target.value;
320
+ if (onUserTyping) {
321
+ if (!isTypingTimeout.current) {
322
+ onUserTyping(true);
323
+ }
324
+ else {
325
+ clearTimeout(isTypingTimeout.current);
326
+ }
327
+ isTypingTimeout.current = setTimeout(doTypingStopped, STOP_TYPING_PERIOD);
328
+ }
329
+ if (getCompletions) {
330
+ closeCompletions();
331
+ handleCompletions(inputText).catch(error => consoleError('Error handling completions', error));
332
+ }
333
+ setInputValue(inputText);
334
+ }
335
+ /**
336
+ * Each time the text in the field changes, this will handle any possible completions that may need to be displayed.
337
+ */
338
+ async function handleCompletions(inputText) {
339
+ const { selectionStart } = textAreaRef.current.getHTMLElement();
340
+ // If a completion is currently running, then cancel it.
341
+ if (lastCompletion.current) {
342
+ lastCompletion.current.cancelled = true;
343
+ }
344
+ const completionPromise = getCompletions?.(inputText, selectionStart);
345
+ const cancelable = { cancelled: false, item: completionPromise };
346
+ lastCompletion.current = cancelable;
347
+ const result = await cancelable.item;
348
+ if (!cancelable.cancelled) {
349
+ if (!result?.completions?.length) {
350
+ setCompletionResults(null);
351
+ }
352
+ else {
353
+ setCompletionResults(result);
354
+ }
355
+ setHighlightedCompletion(-1);
356
+ }
357
+ }
358
+ function send(event) {
359
+ if (doHasValidInput()) {
360
+ event.preventDefault();
361
+ doTypingStopped();
362
+ closeCompletions();
363
+ const text = inputValue.trim();
364
+ const payload = onBeforeSend?.();
365
+ onSendInput(text, payload);
366
+ // Reset the value of the field.
367
+ setInputValue('');
368
+ if (blurOnSend) {
369
+ textAreaRef.current.doBlur();
370
+ }
371
+ else {
372
+ textAreaRef.current.takeFocus();
373
+ }
374
+ }
375
+ }
376
+ /**
377
+ * Called when the input field gets focus.
378
+ */
379
+ function onInputFocus() {
380
+ setTextAreaHasFocus(true);
381
+ }
382
+ /**
383
+ * Called when the input field loses focus.
384
+ */
385
+ function onInputBlur() {
386
+ setTextAreaHasFocus(false);
387
+ }
388
+ /**
389
+ * Instructs this component to put focus into the input text area. This only applies to desktop devices.
390
+ */
391
+ function takeFocus() {
392
+ if (!IS_MOBILE && isInputVisible) {
393
+ textAreaRef.current.takeFocus();
394
+ }
395
+ }
396
+ /**
397
+ * Creates an instance of {@link InstanceInputElement}.
398
+ */
399
+ function createInstanceInputElement() {
400
+ return {
401
+ getHTMLElement: () => textAreaRef?.current?.getHTMLElement(),
402
+ setValue: (value) => setInputValue(value),
403
+ setEnableEnterKey: (isEnabled) => {
404
+ enterKeyEnabled.current = isEnabled;
405
+ },
406
+ addChangeListener: (listener) => changeListeners.current.addListener(listener),
407
+ removeChangeListener: (listener) => changeListeners.current.removeListener(listener),
408
+ };
409
+ }
410
+ /**
411
+ * Given a base string, add modifiers to an element id to ensure it is unique based off of context.
412
+ */
413
+ function getElementId(baseId, isTestingId) {
414
+ const elementID = baseId;
415
+ const withInputType = inputType ? `--${inputType}` : '';
416
+ const withNamespace = isTestingId ? '' : serviceManager.namespace.suffix;
417
+ return `${elementID}${withInputType}${withNamespace}`;
418
+ }
419
+ /**
420
+ * The callback that is called when the user removes a file from the upload area.
421
+ */
422
+ function onRemoveFile(fileID) {
423
+ const isInputToAgent = selectIsInputToAgent(serviceManager.store.getState());
424
+ serviceManager.store.dispatch(actions.removeFileUpload(fileID, isInputToAgent));
425
+ // After we remove the file, we need to move focus back to the input field.
426
+ textAreaRef.current.takeFocus();
427
+ }
428
+ /**
429
+ * The callback that is called when the user selects a file using the file input.
430
+ */
431
+ function onFileChange(event) {
432
+ const isInputToAgent = selectIsInputToAgent(serviceManager.store.getState());
433
+ const { dispatch } = serviceManager.store;
434
+ const { files } = event.target;
435
+ const newFiles = [];
436
+ for (let index = 0; index < files.length; index++) {
437
+ const newFile = { id: uuid(UUIDType.FILE), status: FileStatusValue.EDIT, file: files[index] };
438
+ newFiles.push(newFile);
439
+ dispatch(actions.addInputFile(newFile, isInputToAgent));
440
+ }
441
+ onFilesSelectedForUpload?.(newFiles);
442
+ // Clear the file input. We're controlling the file list.
443
+ fileInputRef.current.value = null;
444
+ }
445
+ /**
446
+ * Determines if there is anything valid that the user could send.
447
+ */
448
+ function doHasValidInput() {
449
+ const hasUploads = Boolean(pendingUploads?.length);
450
+ if (hasUploads) {
451
+ if (pendingUploads.find(upload => !isValidForUpload(upload))) {
452
+ // If there are any files that are in error, the user cannot send the message.
453
+ return false;
454
+ }
455
+ }
456
+ return Boolean(inputValue.trim()) || hasUploads;
457
+ }
458
+ // If the input field becomes disabled, we don't get a blur event so make sure to remove the focus indicator.
459
+ if (textAreaHasFocus && disableInput) {
460
+ setTextAreaHasFocus(false);
461
+ }
462
+ // If the input field loses focus, close the completions.
463
+ if (!textAreaHasFocus && completionResults) {
464
+ closeCompletions();
465
+ }
466
+ useImperativeHandle(ref, () => ({
467
+ takeFocus,
468
+ getMessageInput: () => instanceInputElement.current,
469
+ }));
470
+ const { input_buttonLabel, input_placeholder, input_ariaLabel, input_uploadButtonLabel, input_stopResponse } = languagePack;
471
+ const useInputValue = disableInput ? '' : inputValue;
472
+ const hasValidInput = doHasValidInput();
473
+ const showDisabledSend = !hasValidInput || disableInput || disableSend;
474
+ const showUploadButtonDisabled = disableUploadButton || disableInput;
475
+ const uploadButtonID = `WACInputContainer__UploadInput-${inputID}`;
476
+ const isRTL = document.dir === 'rtl';
477
+ // If the input field is disabled, don't show a placeholder (unless one is provided).
478
+ const usePlaceHolder = placeholder || (disableInput ? undefined : input_placeholder);
479
+ if (lastValue.current !== inputValue) {
480
+ lastValue.current = inputValue;
481
+ changeListeners.current.fireListeners(inputValue);
482
+ }
483
+ return (isInputVisible && (React__default.createElement("div", { className: cx('WACInputAndCompletions', {
484
+ 'WACInputAndCompletions--completionsOpen': completionResults,
485
+ }) },
486
+ completionResults && (React__default.createElement("div", { className: "WACInputCompletions" },
487
+ React__default.createElement("ul", { ref: completionsPopupRef, className: "WACInputCompletions__Menu cds--list-box__menu" }, completionResults.completions.map((completion, index) => {
488
+ return (
489
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions
490
+ React__default.createElement("li", {
491
+ // eslint-disable-next-line react/no-array-index-key
492
+ key: index, className: cx('WACInputCompletion cds--list-box__menu-item', {
493
+ 'WACInputCompletion--selected': index === highlightedCompletion,
494
+ 'WACInputCompletion--afterSelected': index === highlightedCompletion + 1,
495
+ }), onClick: () => doCompletionSelected(completionResults, index),
496
+ // This onMouseDown prevents the browser from moving focus away from the input field.
497
+ onMouseDown: event => event.preventDefault() },
498
+ React__default.createElement("div", { className: "WACInputCompletions__MenuItem cds--list-box__menu-item__option" },
499
+ React__default.createElement("div", { className: "WACInputCompletions__MenuItemLabel" }, completion.label),
500
+ completion.tag && (React__default.createElement(Tag, { className: "WACInputCompletions__MenuItemTag", type: completion.tag.type, size: TagSize.SMALL }, completion.tag.label)))));
501
+ })))),
502
+ React__default.createElement("div", { className: cx('WACInputContainer', {
503
+ 'WACInputContainer--hasFocus': textAreaHasFocus,
504
+ 'WACInputContainer--showUploadButton': showUploadButton,
505
+ }) },
506
+ React__default.createElement("div", { className: "WACInputContainer__LeftContainer" },
507
+ React__default.createElement("div", { className: "WACInputContainer__TextAndUpload" },
508
+ showUploadButton && (React__default.createElement("div", { className: "WACInputContainer__UploadButtonContainer" },
509
+ React__default.createElement("input", { ref: fileInputRef, accept: allowedFileUploadTypes, id: uploadButtonID, className: "WACVisuallyHidden WACInputContainer__UploadInput", type: "file", "aria-label": input_uploadButtonLabel, onChange: onFileChange, multiple: allowMultipleFileUploads, disabled: showUploadButtonDisabled }),
510
+ React__default.createElement("label", { className: cx('WACInputContainer__UploadButton', {
511
+ 'WACInputContainer__UploadButton--disabled': showUploadButtonDisabled,
512
+ }), htmlFor: uploadButtonID },
513
+ React__default.createElement(Attachment, null)))),
514
+ React__default.createElement(TextArea, { autoSize: true, ariaLabel: input_ariaLabel, disabled: disableInput, maxLength: INPUT_MAX_CHARS, onChange: onChange, onKeyDown: onKeyDown, onClick: closeCompletions, placeholder: usePlaceHolder, value: useInputValue, ref: textAreaRef, onFocus: onInputFocus, onBlur: onInputBlur, id: getElementId('WACInputContainer-TextArea'), testId: getElementId('WACInputContainer-TextArea', true) })),
515
+ Boolean(pendingUploads?.length) && (React__default.createElement("div", { className: "WACInputContainer__FilesContainer" }, pendingUploads.map((fileUpload, index) => {
516
+ return (React__default.createElement(FileUploaderItem
517
+ // eslint-disable-next-line react/no-array-index-key
518
+ , {
519
+ // eslint-disable-next-line react/no-array-index-key
520
+ key: index, iconDescription: languagePack.fileSharing_removeButtonTitle, name: fileUpload.file.name, status: FileStatusValue.EDIT, errorSubject: fileUpload.errorMessage, invalid: fileUpload.isError, size: ButtonSizeEnum.SMALL, onDelete: () => onRemoveFile(fileUpload.id) }));
521
+ })))),
522
+ React__default.createElement("div", { className: "WACInputContainer__SendButtonContainer" },
523
+ isStopStreamingButtonVisible && (React__default.createElement(StopStreamingButton, { label: input_stopResponse, disabled: isStopStreamingButtonDisabled, tooltipAlignment: "top", onClick: () => {
524
+ const { store } = serviceManager;
525
+ const { currentStreamID } = store.getState().botInputState.stopStreamingButtonState;
526
+ store.dispatch(actions.setStopStreamingButtonDisabled(true));
527
+ serviceManager.fire({ type: "stopStreaming" /* BusEventType.STOP_STREAMING */ });
528
+ // If we have an assistant stream ID, then tell the message service to stop the stream.
529
+ if (currentStreamID) {
530
+ serviceManager.messageService.stopStreaming(currentStreamID);
531
+ }
532
+ } })),
533
+ React__default.createElement(Button, { className: "WACInputContainer__SendButton", kind: ButtonKindEnum.GHOST, size: ButtonSizeEnum.SMALL, id: getElementId('WACInputContainer__SendButton'), type: "button", onClick: send, "aria-label": input_buttonLabel, disabled: showDisabledSend, renderIcon: hasValidInput ? SendFilled : Send, iconDescription: input_buttonLabel, tooltipAlignment: isRTL ? 'start' : 'end', tooltipPosition: "top", hasIconOnly: true }))))));
534
+ }
535
+ const InputExport = React__default.memo(forwardRef(Input));
536
+
537
+ export { InputExport as I };