@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
@@ -13,9 +13,9 @@
13
13
  * or implied. See the License for the specific language governing permissions and limitations under
14
14
  * the License.
15
15
  *
16
- * @carbon/ai-chat 0.3.2
16
+ * @carbon/ai-chat 0.3.3
17
17
  *
18
- * Built: Jun 11 2025 1:30 pm -04:00
18
+ * Built: Jul 11 2025 1:09 pm -04:00
19
19
  *
20
20
  *
21
21
  */
@@ -0,0 +1,142 @@
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 React__default from 'react';
24
+ import { ba as convertToEmptyStringIfStringifiedNull, bI as convertPossibleStringifiedArrayToFirstString } from './AppContainer.js';
25
+
26
+ /**
27
+ * Miscellaneous JavaScript utilities.
28
+ */
29
+ /**
30
+ * Determines if the given value is null or undefined.
31
+ */
32
+ function isNil(value) {
33
+ return value === undefined || value === null;
34
+ }
35
+ /**
36
+ * Determines if a given number is odd.
37
+ */
38
+ function isOdd(value) {
39
+ if (value % 2 !== 1) {
40
+ return true;
41
+ }
42
+ return false;
43
+ }
44
+
45
+ /**
46
+ * Returns a {@link ReactNode} that represents the given text with `<em>` tags in the string replaced with actual
47
+ * JSX elements to form highlighted portions.
48
+ */
49
+ function formatHighlightFields(str) {
50
+ const strArray = str.split(new RegExp('<em>|</em>', 'g'));
51
+ // If there is an odd number of '<em>' separators, then just return the whole string, minus the '<em>' elements.
52
+ if (isOdd(strArray.length)) {
53
+ return [strArray.join('')];
54
+ }
55
+ return strArray.map((strSegment, index) => {
56
+ if (isOdd(index)) {
57
+ return strSegment;
58
+ }
59
+ return (
60
+ // eslint-disable-next-line react/no-array-index-key
61
+ React__default.createElement("em", { key: index, className: "WAC__highlight" }, strSegment));
62
+ });
63
+ }
64
+ function shouldTruncateBody(searchResult, charactersForEllipsis) {
65
+ return searchResult.highlight.body[0].length > charactersForEllipsis;
66
+ }
67
+ function hasSearchResultBody(searchResult) {
68
+ if (searchResult.highlight?.body?.[0]) {
69
+ return Boolean(formatHighlightFields(convertToEmptyStringIfStringifiedNull(searchResult.highlight?.body[0])));
70
+ }
71
+ return false;
72
+ }
73
+ /**
74
+ * Determine which element to render as the body and the amount of text that will be displayed in it.
75
+ * Always use highlight.body, Use body as a fallback based on certain conditions
76
+ * This was driven by https://github.ibm.com/Watson-Discovery/customer-care/issues/660
77
+ * We check the searchResults.highlight.body which should be an array. If that is not set, we fall back to
78
+ * searchResult.body which is either a string OR a stringified array. If it is the latter, we only want the first
79
+ * item in the stringified array. https://github.ibm.com/watson-engagement-advisor/wea-backlog/issues/31262 has an
80
+ * explanation.
81
+ */
82
+ function SearchResultBody({ searchResult }) {
83
+ if (searchResult && 'highlight' in searchResult) {
84
+ if (searchResult.highlight?.body?.[0]) {
85
+ return formatHighlightFields(convertToEmptyStringIfStringifiedNull(searchResult.highlight.body[0]));
86
+ }
87
+ }
88
+ if (searchResult && 'body' in searchResult && searchResult.body) {
89
+ return convertPossibleStringifiedArrayToFirstString(convertToEmptyStringIfStringifiedNull(searchResult.body));
90
+ }
91
+ return null;
92
+ }
93
+ const SearchResultBodyExport = React__default.memo(SearchResultBody);
94
+ /**
95
+ * In conversational search citation panels we show the search result body instead of the citation text or highlight
96
+ * body because it will contain the most context for the user. This will only be used if there is no url or
97
+ * pdf attached to the source, so the assumption is that the data will be nicely formatted from document ingestion
98
+ * instead of a web crawler. We also make sure to highlight the citation text within the search result body to help the
99
+ * user find the citation.
100
+ */
101
+ function SearchResultBodyWithCitationHighlighted({ relatedSearchResult, citationItem, }) {
102
+ const elementsArray = [];
103
+ let searchString;
104
+ let citationString;
105
+ if (relatedSearchResult?.body) {
106
+ const searchStringFromBody = convertPossibleStringifiedArrayToFirstString(convertToEmptyStringIfStringifiedNull(relatedSearchResult.body));
107
+ // Search result body's can contain <em> and </em> tags which need to be removed. After remove the em tags, it
108
+ // should be safe to assume that the citation text is a direct substring of either the search_result body or title.
109
+ searchString = searchStringFromBody.replace('<em>', '').replace('</em>', '');
110
+ }
111
+ if (citationItem?.text) {
112
+ citationString = convertPossibleStringifiedArrayToFirstString(convertToEmptyStringIfStringifiedNull(citationItem.text));
113
+ }
114
+ if (searchString && citationString) {
115
+ const startOfCitation = searchString.indexOf(citationString);
116
+ // If the citation string is not within the search string from the search_result body than the citation was from the
117
+ // search_result title which doesn't get this highlight treatment.
118
+ if (startOfCitation !== -1) {
119
+ // Add the text prior to the citation to the array.
120
+ elementsArray.push(React__default.createElement("span", { key: 1 }, searchString.substring(0, startOfCitation)));
121
+ // Add the highlighted citation text to the array.
122
+ elementsArray.push(React__default.createElement("em", { key: 2, className: "WAC__highlight" }, searchString.substring(startOfCitation, startOfCitation + citationString.length)));
123
+ // Add the text after the citation to the array.
124
+ elementsArray.push(React__default.createElement("span", { key: 3 }, searchString.substring(startOfCitation + citationString.length)));
125
+ }
126
+ }
127
+ if (elementsArray.length) {
128
+ // If we had a search string and a citation string then we were able to form a highlighted search body which should
129
+ // be used.
130
+ return elementsArray;
131
+ }
132
+ if (searchString.length) {
133
+ // If we couldn't form a highlighted search body then just use the search string. This could happen if the citation
134
+ // string was in the title of the search_result instead of in the body.
135
+ return [React__default.createElement("span", null, searchString)];
136
+ }
137
+ // If for some reason we couldn't create a search string then use the citation string.
138
+ return [React__default.createElement("span", null, citationString)];
139
+ }
140
+ const SearchResultBodyWithCitationHighlightedExport = React__default.memo(SearchResultBodyWithCitationHighlighted);
141
+
142
+ export { SearchResultBodyExport as S, SearchResultBodyWithCitationHighlightedExport as a, hasSearchResultBody as h, isNil as i, shouldTruncateBody as s };
@@ -13,9 +13,9 @@
13
13
  * or implied. See the License for the specific language governing permissions and limitations under
14
14
  * the License.
15
15
  *
16
- * @carbon/ai-chat 0.3.2
16
+ * @carbon/ai-chat 0.3.3
17
17
  *
18
- * Built: Jun 11 2025 1:30 pm -04:00
18
+ * Built: Jul 11 2025 1:09 pm -04:00
19
19
  *
20
20
  *
21
21
  */
@@ -0,0 +1,429 @@
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 ErrorFilled from '@carbon/icons-react/es/ErrorFilled.js';
24
+ import Restart from '@carbon/icons-react/es/Restart.js';
25
+ import { Button, InlineNotification } from '@carbon/react';
26
+ import React__default, { useRef, useImperativeHandle, useEffect, useState } from 'react';
27
+ import { useIntl } from 'react-intl';
28
+ import { useSelector } from 'react-redux';
29
+ import { _ as useLanguagePack, aa as doFocusRef, Z as cx, a0 as useServiceManager, bl as useAriaAnnouncer, bm as getMediaDimensions, j as consoleError, bU as formatMessage, bV as HideComponent, a9 as AnnounceOnMountComponentExport, bK as MountChildrenOnDelay, bW as MainWindowOpenReason } from './AppContainer.js';
30
+ import Close from '@carbon/icons-react/es/Close.js';
31
+ import Subtract from '@carbon/icons-react/es/Subtract.js';
32
+ import ArrowLeft from '@carbon/icons-react/es/ArrowLeft.js';
33
+ import ArrowRight from '@carbon/icons-react/es/ArrowRight.js';
34
+ import Chat from '@carbon/icons-react/es/Chat.js';
35
+ import { I as InlineError } from './InlineError.js';
36
+ import { I as ImageExport, V as VideoComponentExport, a as SkeletonPlaceholder } from './VideoComponent.js';
37
+ import { R as RichTextExport } from './RichText.js';
38
+ import { j as MessageResponseTypes, p as ViewType, T as TourEndReason, V as ViewChangeReason } from './customElement.js';
39
+ import '@carbon/icons-react/es/AiLaunch.js';
40
+ import '@carbon/icons-react/es/ArrowUpLeft.js';
41
+ import '@carbon/icons-react/es/ChatLaunch.js';
42
+ import '@carbon/icons-react/es/Information.js';
43
+ import '@carbon/icons-react/es/Home.js';
44
+ import '@carbon/web-components/es-custom/components/slug/index.js';
45
+ import '@carbon/icons-react/es/CloseLarge.js';
46
+ import '@carbon/icons-react/es/DownToBottom.js';
47
+ import '@carbon/icons-react/es/Menu.js';
48
+ import '@carbon/icons-react/es/SidePanelClose.js';
49
+ import '@carbon/icons-react/es/SubtractLarge.js';
50
+ import '@carbon/web-components/es-custom/components/ai-label/defs.js';
51
+ import '@carbon/web-components/es-custom/components/popover/defs.js';
52
+ import '@carbon/web-components/es-custom/components/skeleton-icon/index.js';
53
+ import 'lit';
54
+ import 'lit/decorators.js';
55
+ import '@carbon/web-components/es-custom/components/button/index.js';
56
+ import '@carbon/web-components/es-custom/components/overflow-menu/index.js';
57
+ import '@carbon/icons-react/es/ChevronDown.js';
58
+ import '@carbon/icons-react/es/ChevronUp.js';
59
+ import 'react-dom';
60
+ import '@carbon/web-components/es-custom/components/ai-label/ai-label-action-button.js';
61
+ import '@carbon/web-components/es-custom/components/ai-label/ai-label.js';
62
+ import '@carbon/icons-react/es/Music.js';
63
+ import 'lit/directives/unsafe-html.js';
64
+
65
+ /**
66
+ * This renders the close and minimize buttons for the tour feature.
67
+ */
68
+ function TourCloseMinimizeComponent(props) {
69
+ const { hideMinimizeButton, onMinimizeClick, onCloseClick } = props;
70
+ const { tour_ariaMinimizeButton, tour_ariaCloseButton } = useLanguagePack();
71
+ return (React__default.createElement("div", { className: "WACTour__CloseMinimizeWrapper" },
72
+ !hideMinimizeButton && (React__default.createElement(React__default.Fragment, null,
73
+ React__default.createElement(Button, { className: "WACTour__CloseMinimizeButton WACTour__MinimizeButton", kind: "ghost", hasIconOnly: true, renderIcon: Subtract, iconDescription: tour_ariaMinimizeButton, onClick: onMinimizeClick, "aria-label": tour_ariaMinimizeButton }),
74
+ React__default.createElement("div", { className: "WACTour__CloseMinimizeDivider" }))),
75
+ React__default.createElement(Button, { className: "WACTour__CloseMinimizeButton WACTour__CloseButton", kind: "ghost", hasIconOnly: true, renderIcon: Close, iconDescription: tour_ariaCloseButton, onClick: onCloseClick, "aria-label": tour_ariaCloseButton })));
76
+ }
77
+
78
+ /**
79
+ * This renders the buttons to open the main window, progress forward and back through the steps, and end the tour once
80
+ * on the last step.
81
+ */
82
+ function TourControlsComponent(props, ref) {
83
+ const { reservePreviousButtonSpace, hidePreviousButton, renderDoneButton, disableNextButton, hideButtons, hideChatButton, onOpenMainWindowClick, onNextClick, onPreviousClick, onDoneClick, } = props;
84
+ const { tour_ariaChatButton, tour_ariaNextButton, tour_ariaPreviousButton, tour_doneButton } = useLanguagePack();
85
+ const nextButtonRef = useRef();
86
+ const doneButtonRef = useRef();
87
+ useImperativeHandle(ref, () => ({
88
+ requestFocus: () => {
89
+ setTimeout(() => {
90
+ if (doneButtonRef.current) {
91
+ doFocusRef(doneButtonRef);
92
+ }
93
+ else {
94
+ doFocusRef(nextButtonRef);
95
+ }
96
+ });
97
+ },
98
+ }));
99
+ return (React__default.createElement("div", { className: cx('WACTour__Controls', { 'WACTour__Controls--empty': hideButtons }) },
100
+ !hideChatButton && (React__default.createElement("div", { className: "WACTour__ControlsButton" },
101
+ React__default.createElement(Button, { className: "WACTour__MainWindowButton", kind: "ghost", size: "md", hasIconOnly: true, renderIcon: props => React__default.createElement(Chat, { ...props }), iconDescription: tour_ariaChatButton, onClick: onOpenMainWindowClick, "aria-label": tour_ariaChatButton }))),
102
+ reservePreviousButtonSpace && (React__default.createElement("div", { className: "WACTour__ControlsButton" },
103
+ React__default.createElement(Button, { className: cx('WACTour__PreviousButton', {
104
+ 'WACTour__ControlsButton--hidden': hidePreviousButton,
105
+ }), kind: "ghost", size: "md", hasIconOnly: true, renderIcon: props => React__default.createElement(ArrowLeft, { ...props }), iconDescription: tour_ariaPreviousButton, onClick: onPreviousClick, "aria-label": tour_ariaPreviousButton }))),
106
+ renderDoneButton && (React__default.createElement("div", { className: "WACTour__ControlsButton" },
107
+ React__default.createElement(Button, { ref: doneButtonRef, className: "WACTour__DoneButton", size: "md", onClick: onDoneClick }, tour_doneButton))),
108
+ !renderDoneButton && (React__default.createElement("div", { className: "WACTour__ControlsButton" },
109
+ React__default.createElement(Button, { ref: nextButtonRef, className: "WACTour__NextButton", size: "md", hasIconOnly: true, renderIcon: props => React__default.createElement(ArrowRight, { ...props }), iconDescription: tour_ariaNextButton, onClick: onNextClick, disabled: disableNextButton, "aria-label": tour_ariaNextButton })))));
110
+ }
111
+ const TourControlsComponentExport = React__default.forwardRef(TourControlsComponent);
112
+
113
+ /**
114
+ * This renders the content for a particular step within the tour.
115
+ */
116
+ function TourStepContentComponent(props) {
117
+ const { stepGenericItem, isCurrentStep } = props;
118
+ const serviceManager = useServiceManager();
119
+ const ariaAnnouncer = useAriaAnnouncer();
120
+ const rootRef = useRef();
121
+ /**
122
+ * Determine if a border should be shown between the step content and the tour controls.
123
+ */
124
+ function showBottomBorder() {
125
+ const responseType = stepGenericItem.response_type;
126
+ switch (responseType) {
127
+ case MessageResponseTypes.TEXT:
128
+ // For a text step we want to show a border between the text and the tour controls.
129
+ return true;
130
+ case MessageResponseTypes.IMAGE:
131
+ // If the Image is going to have a description then we want to show a border between the description and the
132
+ // tour controls.
133
+ return stepGenericItem?.description;
134
+ case MessageResponseTypes.VIDEO:
135
+ // If the Video is going to have a description then we want to show a border between the description and the
136
+ // tour controls.
137
+ return stepGenericItem?.description;
138
+ default:
139
+ // For an unsupported step we want to show a border between the error and the tour controls.
140
+ return true;
141
+ }
142
+ }
143
+ /**
144
+ * Render the appropriate component for the given message responseType.
145
+ */
146
+ function renderStepContent() {
147
+ const responseType = stepGenericItem.response_type;
148
+ switch (responseType) {
149
+ case MessageResponseTypes.TEXT:
150
+ return React__default.createElement(StepContentText, { messageItem: stepGenericItem });
151
+ case MessageResponseTypes.IMAGE:
152
+ return React__default.createElement(StepContentImage, { messageItem: stepGenericItem });
153
+ case MessageResponseTypes.VIDEO:
154
+ return React__default.createElement(StepContentVideo, { messageItem: stepGenericItem, isCurrentStep: isCurrentStep });
155
+ default:
156
+ // If the responseType is not one of the three supported types for tours then render an inline error.
157
+ return React__default.createElement(StepContentUnsupportedError, { messageItem: stepGenericItem, isCurrentStep: isCurrentStep });
158
+ }
159
+ }
160
+ // If this is the current step then send an event and track the type of response being shown.
161
+ useEffect(() => {
162
+ if (isCurrentStep) {
163
+ serviceManager.trackService.track({
164
+ eventName: 'Tour interaction',
165
+ eventDescription: 'Tour step shown.',
166
+ type: stepGenericItem.response_type,
167
+ });
168
+ // Announce the content of the current step. The announcement is handled in setTimeout so that it doesn't prevent
169
+ // the initial announcement from being heard when the tour is open.
170
+ setTimeout(() => ariaAnnouncer(rootRef.current));
171
+ }
172
+ }, [isCurrentStep, serviceManager.trackService, stepGenericItem.response_type, ariaAnnouncer]);
173
+ return (React__default.createElement("div", { className: "WACTourStep__Wrapper", ref: rootRef },
174
+ React__default.createElement("div", { className: cx('WACTourStep', 'WAC__message', {
175
+ 'WACTourStep--hidden': !isCurrentStep,
176
+ WACTourStep__BottomBorder: showBottomBorder(),
177
+ }) }, renderStepContent())));
178
+ }
179
+ /**
180
+ * Given a TextItem return a RichText component containing the text from the message.
181
+ */
182
+ function StepContentText(props) {
183
+ const { messageItem } = props;
184
+ const { text } = messageItem;
185
+ // For text provided by the assistant, pass it through some HTML formatting before displaying it.
186
+ return (React__default.createElement("div", { className: "WACTourStep__Text" },
187
+ React__default.createElement(RichTextExport, { text: text })));
188
+ }
189
+ /**
190
+ * Given an ImageItem return an Image component containing the image from the message.
191
+ */
192
+ function StepContentImage(props) {
193
+ const { messageItem } = props;
194
+ const { source, description, alt_text } = messageItem;
195
+ const languagePack = useLanguagePack();
196
+ return (
197
+ // Don't pass the title to the Image component since tours only support descriptions.
198
+ React__default.createElement(ImageExport, { imageError: languagePack.errors_imageSource, source: source, description: description, altText: alt_text, hideIconAndTitle: true }));
199
+ }
200
+ /**
201
+ * Given a VideoItem return a VideoComponent containing the video from the message.
202
+ */
203
+ function StepContentVideo(props) {
204
+ const { messageItem, isCurrentStep } = props;
205
+ const { source, description, alt_text } = messageItem;
206
+ const { viewState } = useSelector((state) => state.persistedToBrowserStorage.launcherState);
207
+ const [isVideoPlaying, setIsVideoPlaying] = useState(false);
208
+ // If this isn't the current step or the tour isn't visible then the video needs to be paused.
209
+ useEffect(() => {
210
+ if (!isCurrentStep || !viewState.tour) {
211
+ setIsVideoPlaying(false);
212
+ }
213
+ }, [isCurrentStep, viewState.tour]);
214
+ return (
215
+ // Don't pass the title to the VideoComponent since tours only support descriptions.
216
+ React__default.createElement(VideoComponentExport, { source: source, description: description, baseHeight: getMediaDimensions(messageItem)?.base_height, ariaLabel: alt_text, playing: isVideoPlaying, onPlay: () => setIsVideoPlaying(true), onPause: () => setIsVideoPlaying(false), hideIconAndTitle: true }));
217
+ }
218
+ /**
219
+ * If the responseType is not one of the three supported types for tours then render an inline error.
220
+ */
221
+ function StepContentUnsupportedError(props) {
222
+ const { messageItem, isCurrentStep } = props;
223
+ const languagePack = useLanguagePack();
224
+ // If the current response type isn't a supported response type then log an error.
225
+ useEffect(() => {
226
+ if (isCurrentStep) {
227
+ consoleError(`The response type you tried to use "${messageItem.response_type}" is not valid within a tour step. The supported response types in tour steps are text, video, and image.`);
228
+ }
229
+ }, [isCurrentStep, messageItem.response_type]);
230
+ return (React__default.createElement("div", { className: "WACTourStep__UnsupportedResponse" },
231
+ React__default.createElement(InlineError, { text: languagePack.errors_generalContent })));
232
+ }
233
+ const TourStepContentComponentExport = React__default.memo(TourStepContentComponent);
234
+
235
+ /**
236
+ * This renders the skeleton of a step within the tour.
237
+ */
238
+ function TourStepSkeletonComponent() {
239
+ return (React__default.createElement("div", { className: "WACTourStep WACTourStep__Skeleton" },
240
+ React__default.createElement(SkeletonPlaceholder, { className: "WACTourStep__SkeletonPlaceholder" })));
241
+ }
242
+
243
+ /**
244
+ * This manages the tour feature controls and renders the tour content before passing both to either a mobile or desktop
245
+ * container depending.
246
+ */
247
+ function TourContainer(props, ref) {
248
+ const languagePack = useLanguagePack();
249
+ const serviceManager = useServiceManager();
250
+ const ariaAnnouncer = useAriaAnnouncer();
251
+ const intl = useIntl();
252
+ const tourConfig = useSelector((state) => state.config.public.tourConfig);
253
+ const { isHydrated } = useSelector((state) => state);
254
+ const { viewState } = useSelector((state) => state.persistedToBrowserStorage.launcherState);
255
+ const { activeTourCurrentStepIndex } = useSelector((state) => state.persistedToBrowserStorage.chatState.persistedTourState);
256
+ const { activeTourStepItems } = useSelector((state) => state.tourState);
257
+ // These three state variables are for future use when dynamic steps are introduced.
258
+ const [renderLoadingBar, setRenderLoadingBar] = useState(false);
259
+ const [renderErrorBanner, setRenderErrorBanner] = useState(false);
260
+ const [renderErrorScreen, setRenderErrorScreen] = useState(false);
261
+ const rootRef = useRef();
262
+ const tourControlsRef = useRef();
263
+ const namespace = serviceManager.namespace.originalName;
264
+ const languageKey = namespace ? 'window_ariaTourRegionNamespace' : 'window_ariaTourRegion';
265
+ const regionLabel = formatMessage(intl, languageKey, { namespace });
266
+ // If we're showing the launcher or main window then hide the tour. We do this instead of unmounting so that we don't
267
+ // lose scroll position, video playback position, etc.
268
+ const hideTour = !viewState.tour;
269
+ // Set default values for the tour controls that match what we want to show during the loading state. These values
270
+ // will be updated when the web chat is hydrated and the activeTourStepItems become available.
271
+ let reservePreviousButtonSpace = true;
272
+ let hidePreviousButton = false;
273
+ let renderDoneButton = false;
274
+ let stepContentComponentsArray = [];
275
+ // Once the web chat is hydrated, and we have the activeTourStepItems, create TourStepContentComponent's for each step
276
+ // and set the correct values for the tour controls properties.
277
+ if (isHydrated && activeTourStepItems) {
278
+ // If there is more than one step in the tour then save space in the tour controls for a previous button.
279
+ // This doesn't guarantee that the previous button will be visible, just that there will be room for it in the
280
+ // controls.
281
+ reservePreviousButtonSpace = activeTourStepItems.length > 1;
282
+ // If there has been space reserved for the previous button then hide it if this is the first step of the tour.
283
+ // Any other step will show the previous button in the space reserved.
284
+ hidePreviousButton = activeTourCurrentStepIndex <= 0;
285
+ // If this is the last step of the tour then show a done button instead of a next button.
286
+ renderDoneButton = activeTourCurrentStepIndex >= activeTourStepItems.length - 1;
287
+ // For each step (GenericItem) in the array of steps, create a TourStepContentComponent, and return it. Assign this
288
+ // new array of TourStepContentComponents to our local array.
289
+ stepContentComponentsArray = activeTourStepItems.map((step, index) => (React__default.createElement(TourStepContentComponentExport
290
+ // eslint-disable-next-line react/no-array-index-key
291
+ , {
292
+ // eslint-disable-next-line react/no-array-index-key
293
+ key: index, stepGenericItem: step, isCurrentStep: index === activeTourCurrentStepIndex })));
294
+ }
295
+ else if (!isHydrated) {
296
+ // If the web chat is not hydrated then show a skeleton component.
297
+ stepContentComponentsArray = [React__default.createElement(TourStepSkeletonComponent, { key: 0 })];
298
+ }
299
+ /**
300
+ * When the user clicks on the main window icon then fire the window open events and switch to the main window.
301
+ */
302
+ async function onOpenMainWindowClick() {
303
+ // Try to open the main window.
304
+ await serviceManager.actions.changeView(ViewType.MAIN_WINDOW, {
305
+ mainWindowOpenReason: MainWindowOpenReason.TOUR_OPENED_OTHER_VIEW,
306
+ });
307
+ // Fire a track event for clicking the open main window button.
308
+ serviceManager.trackService.track({
309
+ eventName: 'Tour interaction',
310
+ eventDescription: 'Tour opened main window.',
311
+ });
312
+ }
313
+ /**
314
+ * When the tour is finished switch to the launcher and clear the tour data. When the launcher is clicked the main
315
+ * window will open.
316
+ */
317
+ async function onDoneClick() {
318
+ // Fire the tour end event before switching to the launcher.
319
+ await serviceManager.eventBus.fire({ type: "tour:end" /* BusEventType.TOUR_END */, reason: TourEndReason.DONE_CLICKED }, serviceManager.instance);
320
+ // Try to open the launcher and clear the tour data from store.
321
+ await serviceManager.actions.endTour({ viewChangeReason: ViewChangeReason.TOUR_DONE });
322
+ // Fire a track event for clicking the done button.
323
+ serviceManager.trackService.track({
324
+ eventName: 'Tour interaction',
325
+ eventDescription: 'Tour completed.',
326
+ });
327
+ }
328
+ /**
329
+ * When the tour is closed switch to the launcher and clear the tour data. When the launcher is clicked the main
330
+ * window will open.
331
+ */
332
+ async function onCloseClick() {
333
+ // Try to open the launcher and clear the tour data from store.
334
+ await serviceManager.actions.endTour({
335
+ viewChangeReason: ViewChangeReason.TOUR_CLOSED,
336
+ });
337
+ // Fire a track event for clicking the close button.
338
+ serviceManager.trackService.track({
339
+ eventName: 'Tour interaction',
340
+ eventDescription: 'Tour closed.',
341
+ });
342
+ }
343
+ /**
344
+ * When the tour is minimized switch to the launcher. When the launcher is clicked the tour will open.
345
+ */
346
+ async function onMinimizeClick() {
347
+ // Try to open the launcher.
348
+ await serviceManager.actions.changeView(ViewType.LAUNCHER, {
349
+ viewChangeReason: ViewChangeReason.TOUR_MINIMIZED,
350
+ });
351
+ // Fire a track event for clicking the minimize button.
352
+ serviceManager.trackService.track({
353
+ eventName: 'Tour interaction',
354
+ eventDescription: 'Tour minimized.',
355
+ });
356
+ }
357
+ /**
358
+ * Now that we have the necessary pieces render the controls for the tour feature.
359
+ */
360
+ function renderTourControlsComponent() {
361
+ return (React__default.createElement(TourControlsComponentExport, { ref: tourControlsRef, hideChatButton: tourConfig?.hideChatButton, reservePreviousButtonSpace: reservePreviousButtonSpace, hidePreviousButton: hidePreviousButton, disableNextButton: renderLoadingBar, hideButtons: !isHydrated, renderDoneButton: renderDoneButton, onNextClick: () => {
362
+ serviceManager.actions.changeStepInTour({ nextStep: true });
363
+ // If the next step is the final step, request focus so that the "done" button has focus.
364
+ if (activeTourCurrentStepIndex + 1 === activeTourStepItems.length - 1) {
365
+ tourControlsRef.current?.requestFocus();
366
+ }
367
+ }, onPreviousClick: () => {
368
+ serviceManager.actions.changeStepInTour({ previousStep: true });
369
+ // If the previous step is the first step, request focus so that the "next" button has focus.
370
+ if (activeTourCurrentStepIndex - 1 === 0) {
371
+ tourControlsRef.current?.requestFocus();
372
+ }
373
+ }, onOpenMainWindowClick: onOpenMainWindowClick, onDoneClick: onDoneClick }));
374
+ }
375
+ function renderTourCloseMinimizeComponent() {
376
+ return (React__default.createElement(TourCloseMinimizeComponent, { hideMinimizeButton: tourConfig?.hideMinimizeButton, onCloseClick: onCloseClick, onMinimizeClick: onMinimizeClick }));
377
+ }
378
+ /**
379
+ * Handles rendering a loading bar or error notification based on the state of the active tour.
380
+ */
381
+ function renderTourStepStatusContainer() {
382
+ return (React__default.createElement("div", { className: "WACTour__StatusContainer" },
383
+ renderErrorBanner && (React__default.createElement(AnnounceOnMountComponentExport, null,
384
+ React__default.createElement(InlineNotification, { kind: "error", title: languagePack.tour_errorFetchingStep, lowContrast: true, hideCloseButton: true, onClick: () => setRenderErrorBanner(false) }))),
385
+ renderLoadingBar && (React__default.createElement(MountChildrenOnDelay, { delay: 500 },
386
+ React__default.createElement("div", { className: "WACLoadingBar__ConnectingAnimation" })))));
387
+ }
388
+ /**
389
+ * The error screen when a tour fails to load.
390
+ */
391
+ function renderTourErrorScreen() {
392
+ return (React__default.createElement(AnnounceOnMountComponentExport, null,
393
+ React__default.createElement("div", { className: "WACTour__ErrorScreen" },
394
+ React__default.createElement("div", { className: "WACTour__ErrorHeader" },
395
+ React__default.createElement(ErrorFilled, { size: 20, className: "WACTour__ErrorIcon" }),
396
+ languagePack.tour_errorTitle),
397
+ React__default.createElement("div", { className: "WACTour__ErrorBody" },
398
+ React__default.createElement("div", { className: "WACTour__ErrorText" }, languagePack.tour_errorBody),
399
+ React__default.createElement(Button, { className: "WACTour__ErrorButton", size: "sm", kind: "tertiary", renderIcon: props => React__default.createElement(Restart, { size: 32, ...props }) }, languagePack.buttons_retry)))));
400
+ }
401
+ useImperativeHandle(ref, () => tourControlsRef.current);
402
+ useEffect(() => {
403
+ if (isHydrated && !hideTour && !renderErrorScreen) {
404
+ const tourInstructionsText = intl.formatMessage({ id: 'tour_instructions' }, { chatButtonText: languagePack.tour_ariaChatButton });
405
+ ariaAnnouncer(tourInstructionsText);
406
+ }
407
+ }, [hideTour, ariaAnnouncer, languagePack, intl, isHydrated, renderErrorScreen]);
408
+ // This effect automatically applies focus to the tour when it hydrates or is opened. Checking for hydration will
409
+ // allow the "done" button do get focus when it renders after hydration.
410
+ useEffect(() => {
411
+ if (isHydrated || !hideTour) {
412
+ tourControlsRef.current?.requestFocus();
413
+ }
414
+ }, [hideTour, isHydrated]);
415
+ return (
416
+ // In the future this hiding may have to be done with visibility: hidden so that dynamic height animations can be
417
+ // preformed.
418
+ React__default.createElement(HideComponent, { hidden: hideTour },
419
+ React__default.createElement("div", { ref: rootRef, className: "WACTour", role: "region", "aria-label": regionLabel },
420
+ renderTourCloseMinimizeComponent(),
421
+ renderErrorScreen && renderTourErrorScreen(),
422
+ !renderErrorScreen && (React__default.createElement(React__default.Fragment, null,
423
+ stepContentComponentsArray,
424
+ renderTourStepStatusContainer(),
425
+ renderTourControlsComponent())))));
426
+ }
427
+ const TourContainerExport = React__default.memo(React__default.forwardRef(TourContainer));
428
+
429
+ export { TourContainerExport as default };