@microsoft/omnichannel-chat-widget 1.8.4-main.6b93408 → 1.8.4-main.810d050
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.
- package/lib/cjs/common/Constants.js +0 -1
- package/lib/cjs/components/postchatsurveypanestateful/PostChatSurveyPaneStateful.js +1 -0
- package/lib/cjs/components/prechatsurveypanestateful/PreChatSurveyPaneStateful.js +64 -2
- package/lib/cjs/components/webchatcontainerstateful/WebChatContainerStateful.js +47 -17
- package/lib/cjs/components/webchatcontainerstateful/common/defaultProps/defaultWebChatContainerStatefulProps.js +2 -1
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/attachments/AdaptiveCardAccessibilityWrapper.js +15 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentUploadValidatorMiddleware.js +4 -8
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/localizedStringsBotInitialsMiddleware.js +43 -5
- package/lib/esm/common/Constants.js +0 -1
- package/lib/esm/components/postchatsurveypanestateful/PostChatSurveyPaneStateful.js +1 -0
- package/lib/esm/components/prechatsurveypanestateful/PreChatSurveyPaneStateful.js +65 -3
- package/lib/esm/components/webchatcontainerstateful/WebChatContainerStateful.js +48 -18
- package/lib/esm/components/webchatcontainerstateful/common/defaultProps/defaultWebChatContainerStatefulProps.js +2 -1
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/attachments/AdaptiveCardAccessibilityWrapper.js +15 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentUploadValidatorMiddleware.js +5 -9
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/localizedStringsBotInitialsMiddleware.js +43 -5
- package/lib/types/common/Constants.d.ts +0 -1
- package/lib/types/components/webchatcontainerstateful/interfaces/IWebChatContainerStatefulProps.d.ts +7 -0
- package/package.json +4 -4
|
@@ -158,7 +158,6 @@ let HtmlIdNames = /*#__PURE__*/_createClass(function HtmlIdNames() {
|
|
|
158
158
|
});
|
|
159
159
|
exports.HtmlIdNames = HtmlIdNames;
|
|
160
160
|
_defineProperty(HtmlIdNames, "MSLiveChatWidget", "MSLiveChatWidget");
|
|
161
|
-
_defineProperty(HtmlIdNames, "fileSentAnnouncementRegionId", "ms_lcw_file_sent_announcement");
|
|
162
161
|
let HtmlClassNames = /*#__PURE__*/_createClass(function HtmlClassNames() {
|
|
163
162
|
_classCallCheck(this, HtmlClassNames);
|
|
164
163
|
});
|
|
@@ -67,6 +67,7 @@ const PostChatSurveyPaneStateful = props => {
|
|
|
67
67
|
};
|
|
68
68
|
const controlProps = {
|
|
69
69
|
id: "oc-lcw-postchatsurvey-pane",
|
|
70
|
+
title: "Post-chat survey",
|
|
70
71
|
surveyURL: ((_props$controlProps = props.controlProps) === null || _props$controlProps === void 0 ? void 0 : _props$controlProps.surveyURL) ?? surveyInviteLink,
|
|
71
72
|
...props.controlProps
|
|
72
73
|
};
|
|
@@ -20,6 +20,34 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
20
20
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
21
21
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
22
22
|
let uiTimer;
|
|
23
|
+
const getFocusedElementAnnouncement = element => {
|
|
24
|
+
var _element$textContent;
|
|
25
|
+
const ariaLabel = element.getAttribute(_Constants.HtmlAttributeNames.ariaLabel);
|
|
26
|
+
if (ariaLabel) {
|
|
27
|
+
return ariaLabel.trim();
|
|
28
|
+
}
|
|
29
|
+
const ariaLabelledBy = element.getAttribute(_Constants.HtmlAttributeNames.ariaLabelledby);
|
|
30
|
+
if (ariaLabelledBy) {
|
|
31
|
+
const labelledByText = ariaLabelledBy.split(/\s+/).map(id => {
|
|
32
|
+
var _document$getElementB, _document$getElementB2;
|
|
33
|
+
return (_document$getElementB = document.getElementById(id)) === null || _document$getElementB === void 0 ? void 0 : (_document$getElementB2 = _document$getElementB.textContent) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.trim();
|
|
34
|
+
}).filter(Boolean).join(" ");
|
|
35
|
+
if (labelledByText) {
|
|
36
|
+
return labelledByText;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (element.id) {
|
|
40
|
+
const label = Array.from(document.querySelectorAll("label")).find(candidate => candidate.htmlFor === element.id || candidate.getAttribute("for") === element.id);
|
|
41
|
+
if (label !== null && label !== void 0 && label.textContent) {
|
|
42
|
+
return label.textContent.trim();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const parentLabel = element.closest("label");
|
|
46
|
+
if (parentLabel !== null && parentLabel !== void 0 && parentLabel.textContent) {
|
|
47
|
+
return parentLabel.textContent.trim();
|
|
48
|
+
}
|
|
49
|
+
return ((_element$textContent = element.textContent) === null || _element$textContent === void 0 ? void 0 : _element$textContent.trim()) ?? "";
|
|
50
|
+
};
|
|
23
51
|
|
|
24
52
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
53
|
const PreChatSurveyPaneStateful = props => {
|
|
@@ -42,6 +70,8 @@ const PreChatSurveyPaneStateful = props => {
|
|
|
42
70
|
surveyProps,
|
|
43
71
|
initStartChat
|
|
44
72
|
} = props;
|
|
73
|
+
const [preChatFocusAnnouncement, setPreChatFocusAnnouncement] = (0, _react.useState)("");
|
|
74
|
+
const liveRegionUpdateTimeout = (0, _react.useRef)();
|
|
45
75
|
const generalStyleProps = Object.assign({}, _defaultGeneralPreChatSurveyPaneStyleProps.defaultGeneralPreChatSurveyPaneStyleProps, surveyProps === null || surveyProps === void 0 ? void 0 : (_surveyProps$stylePro = surveyProps.styleProps) === null || _surveyProps$stylePro === void 0 ? void 0 : _surveyProps$stylePro.generalStyleProps, {
|
|
46
76
|
display: state.appStates.isMinimized ? "none" : ""
|
|
47
77
|
});
|
|
@@ -128,6 +158,16 @@ const PreChatSurveyPaneStateful = props => {
|
|
|
128
158
|
...(surveyProps === null || surveyProps === void 0 ? void 0 : surveyProps.styleProps),
|
|
129
159
|
generalStyleProps: generalStyleProps
|
|
130
160
|
};
|
|
161
|
+
const announceFocusedElement = event => {
|
|
162
|
+
if (liveRegionUpdateTimeout.current) {
|
|
163
|
+
window.clearTimeout(liveRegionUpdateTimeout.current);
|
|
164
|
+
}
|
|
165
|
+
const announcement = getFocusedElementAnnouncement(event.target);
|
|
166
|
+
setPreChatFocusAnnouncement("");
|
|
167
|
+
liveRegionUpdateTimeout.current = window.setTimeout(() => {
|
|
168
|
+
setPreChatFocusAnnouncement(announcement);
|
|
169
|
+
}, 0);
|
|
170
|
+
};
|
|
131
171
|
(0, _react.useEffect)(() => {
|
|
132
172
|
// Set Aria-Label Attribute for Inputs
|
|
133
173
|
const adaptiveCardElements = document.getElementsByClassName(_Constants.HtmlAttributeNames.adaptiveCardClassName);
|
|
@@ -175,10 +215,32 @@ const PreChatSurveyPaneStateful = props => {
|
|
|
175
215
|
}
|
|
176
216
|
}
|
|
177
217
|
}, [state.appStates.isMinimized]);
|
|
178
|
-
|
|
218
|
+
(0, _react.useEffect)(() => () => {
|
|
219
|
+
if (liveRegionUpdateTimeout.current) {
|
|
220
|
+
window.clearTimeout(liveRegionUpdateTimeout.current);
|
|
221
|
+
}
|
|
222
|
+
}, []);
|
|
223
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
224
|
+
onFocusCapture: announceFocusedElement
|
|
225
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
226
|
+
role: "status",
|
|
227
|
+
"aria-live": "polite",
|
|
228
|
+
"aria-atomic": "true",
|
|
229
|
+
style: {
|
|
230
|
+
position: "absolute",
|
|
231
|
+
width: "1px",
|
|
232
|
+
height: "1px",
|
|
233
|
+
margin: "-1px",
|
|
234
|
+
padding: 0,
|
|
235
|
+
border: 0,
|
|
236
|
+
clip: "rect(0, 0, 0, 0)",
|
|
237
|
+
overflow: "hidden",
|
|
238
|
+
whiteSpace: "nowrap"
|
|
239
|
+
}
|
|
240
|
+
}, preChatFocusAnnouncement), /*#__PURE__*/_react.default.createElement(_omnichannelChatComponents.PreChatSurveyPane, {
|
|
179
241
|
controlProps: controlProps,
|
|
180
242
|
styleProps: styleProps
|
|
181
|
-
});
|
|
243
|
+
}));
|
|
182
244
|
};
|
|
183
245
|
exports.PreChatSurveyPaneStateful = PreChatSurveyPaneStateful;
|
|
184
246
|
var _default = PreChatSurveyPaneStateful;
|
|
@@ -232,6 +232,48 @@ const WebChatContainerStateful = props => {
|
|
|
232
232
|
chatHistoryElement.setAttribute(_Constants.HtmlAttributeNames.ariaLabel, webChatContainerProps.webChatHistoryMobileAccessibilityLabel);
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
|
+
|
|
236
|
+
// internal tracking: WebChats BasicToaster renders a `role="log"` container
|
|
237
|
+
// with no accessible name. When the toaster is empty (typical idle
|
|
238
|
+
// state) screen readers traversing the page announce it as "blank".
|
|
239
|
+
// Inject an aria-label so the region has a meaningful name; the
|
|
240
|
+
// consumer can override via the new
|
|
241
|
+
// `webChatNotificationRegionAccessibilityLabel` prop. The toaster
|
|
242
|
+
// may not be rendered yet when this effect first runs, so observe
|
|
243
|
+
// for it via a MutationObserver scoped to the widget root (or, if
|
|
244
|
+
// not yet mounted, the widget container's parent) so we never fire
|
|
245
|
+
// on host-page mutations outside the widget subtree.
|
|
246
|
+
const toasterLabel = (webChatContainerProps === null || webChatContainerProps === void 0 ? void 0 : webChatContainerProps.webChatNotificationRegionAccessibilityLabel) ?? _defaultWebChatContainerStatefulProps.defaultWebChatContainerStatefulProps.webChatNotificationRegionAccessibilityLabel ?? "Chat notifications";
|
|
247
|
+
const labelToaster = root => {
|
|
248
|
+
const toaster = root.querySelector(".webchat__toaster[role='log']");
|
|
249
|
+
if (toaster && !toaster.getAttribute(_Constants.HtmlAttributeNames.ariaLabel)) {
|
|
250
|
+
toaster.setAttribute(_Constants.HtmlAttributeNames.ariaLabel, toasterLabel);
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
return false;
|
|
254
|
+
};
|
|
255
|
+
// Prefer the widget root; if it is not yet in the DOM, fall back to
|
|
256
|
+
// `document` for the *initial* lookup only, then observe the most
|
|
257
|
+
// specific available scope (widget root if present, otherwise the
|
|
258
|
+
// widget's parent / document.body as a last resort). The observer
|
|
259
|
+
// re-resolves the widget root on every callback so we tighten scope
|
|
260
|
+
// as soon as it mounts.
|
|
261
|
+
let toasterObserver;
|
|
262
|
+
const resolveScope = () => document.getElementById("ms_lcw_webchat_root") ?? document.body;
|
|
263
|
+
if (!labelToaster(resolveScope())) {
|
|
264
|
+
toasterObserver = new MutationObserver(() => {
|
|
265
|
+
const scope = resolveScope();
|
|
266
|
+
if (labelToaster(scope)) {
|
|
267
|
+
var _toasterObserver;
|
|
268
|
+
(_toasterObserver = toasterObserver) === null || _toasterObserver === void 0 ? void 0 : _toasterObserver.disconnect();
|
|
269
|
+
toasterObserver = undefined;
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
toasterObserver.observe(resolveScope(), {
|
|
273
|
+
childList: true,
|
|
274
|
+
subtree: true
|
|
275
|
+
});
|
|
276
|
+
}
|
|
235
277
|
dispatch({
|
|
236
278
|
type: _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_RENDERING_MIDDLEWARE_PROPS,
|
|
237
279
|
payload: webChatContainerProps === null || webChatContainerProps === void 0 ? void 0 : webChatContainerProps.renderingMiddlewareProps
|
|
@@ -256,6 +298,10 @@ const WebChatContainerStateful = props => {
|
|
|
256
298
|
}
|
|
257
299
|
}
|
|
258
300
|
}
|
|
301
|
+
return () => {
|
|
302
|
+
var _toasterObserver2;
|
|
303
|
+
(_toasterObserver2 = toasterObserver) === null || _toasterObserver2 === void 0 ? void 0 : _toasterObserver2.disconnect();
|
|
304
|
+
};
|
|
259
305
|
}, []);
|
|
260
306
|
(0, _react2.useEffect)(() => {
|
|
261
307
|
var _props$webChatContain6, _props$webChatContain7;
|
|
@@ -496,23 +542,7 @@ const WebChatContainerStateful = props => {
|
|
|
496
542
|
height: "100%",
|
|
497
543
|
width: "100%"
|
|
498
544
|
}
|
|
499
|
-
}, shouldLoadPersistentHistoryMessages && /*#__PURE__*/_react2.default.createElement(_WebChatEventSubscribers.default, null), /*#__PURE__*/_react2.default.createElement(BasicWebChat, null))), /*#__PURE__*/_react2.default.createElement(
|
|
500
|
-
id: _Constants.HtmlIdNames.fileSentAnnouncementRegionId,
|
|
501
|
-
role: "alert",
|
|
502
|
-
"aria-live": "assertive",
|
|
503
|
-
"aria-atomic": "true",
|
|
504
|
-
style: {
|
|
505
|
-
position: "absolute",
|
|
506
|
-
width: "1px",
|
|
507
|
-
height: "1px",
|
|
508
|
-
padding: "0",
|
|
509
|
-
margin: "-1px",
|
|
510
|
-
overflow: "hidden",
|
|
511
|
-
clip: "rect(0, 0, 0, 0)",
|
|
512
|
-
whiteSpace: "nowrap",
|
|
513
|
-
border: "0"
|
|
514
|
-
}
|
|
515
|
-
}), citationPaneOpen && /*#__PURE__*/_react2.default.createElement(_CitationPaneStateful.default, {
|
|
545
|
+
}, shouldLoadPersistentHistoryMessages && /*#__PURE__*/_react2.default.createElement(_WebChatEventSubscribers.default, null), /*#__PURE__*/_react2.default.createElement(BasicWebChat, null))), citationPaneOpen && /*#__PURE__*/_react2.default.createElement(_CitationPaneStateful.default, {
|
|
516
546
|
id: ((_props$citationPanePr = props.citationPaneProps) === null || _props$citationPanePr === void 0 ? void 0 : _props$citationPanePr.id) || _Constants.HtmlAttributeNames.ocwCitationPaneClassName,
|
|
517
547
|
title: ((_props$citationPanePr2 = props.citationPaneProps) === null || _props$citationPanePr2 === void 0 ? void 0 : _props$citationPanePr2.title) || _Constants.HtmlAttributeNames.ocwCitationPaneTitle,
|
|
518
548
|
contentHtml: citationPaneText,
|
|
@@ -20,6 +20,7 @@ const defaultWebChatContainerStatefulProps = {
|
|
|
20
20
|
honorsTargetInHTMLLinks: false,
|
|
21
21
|
hyperlinkTextOverride: false,
|
|
22
22
|
directLine: new _mockadapter.default(),
|
|
23
|
-
adaptiveCardStyles: _defaultAdaptiveCardStyles.defaultAdaptiveCardStyles
|
|
23
|
+
adaptiveCardStyles: _defaultAdaptiveCardStyles.defaultAdaptiveCardStyles,
|
|
24
|
+
webChatNotificationRegionAccessibilityLabel: "Chat notifications"
|
|
24
25
|
};
|
|
25
26
|
exports.defaultWebChatContainerStatefulProps = defaultWebChatContainerStatefulProps;
|
|
@@ -32,6 +32,21 @@ const AdaptiveCardAccessibilityWrapper = _ref => {
|
|
|
32
32
|
const container = containerRef.current;
|
|
33
33
|
if (!container) return;
|
|
34
34
|
|
|
35
|
+
// dropdown-double-label: compact Input.ChoiceSet renders as a native
|
|
36
|
+
// <select> with both aria-labelledby and a sibling visible <label for>.
|
|
37
|
+
// Only remove aria-labelledby when it points solely at that same visible
|
|
38
|
+
// label; preserve composite labels that include required/error/context text.
|
|
39
|
+
const compactSelects = container.querySelectorAll(".ac-input-container select.ac-input.ac-multichoiceInput[aria-labelledby]");
|
|
40
|
+
compactSelects.forEach(select => {
|
|
41
|
+
const id = select.id;
|
|
42
|
+
if (!id) return;
|
|
43
|
+
const visibleLabel = container.querySelector(`label[for="${CSS.escape(id)}"]:not([aria-hidden='true'])`);
|
|
44
|
+
const labelledBy = (select.getAttribute("aria-labelledby") || "").trim().split(/\s+/);
|
|
45
|
+
if (visibleLabel !== null && visibleLabel !== void 0 && visibleLabel.id && labelledBy.length === 1 && labelledBy[0] === visibleLabel.id) {
|
|
46
|
+
select.removeAttribute("aria-labelledby");
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
35
50
|
// action-button-toggle / login-button-toggle: submit/login action buttons can be
|
|
36
51
|
// rendered with toggle-only ARIA that causes screen readers to announce them as
|
|
37
52
|
// switches instead of plain push buttons. Preserve Action.ToggleVisibility buttons,
|
|
@@ -18,14 +18,10 @@ var _WebChatActionType = require("../../enums/WebChatActionType");
|
|
|
18
18
|
|
|
19
19
|
const MBtoBRatio = 1000000;
|
|
20
20
|
const announceFileSent = message => {
|
|
21
|
-
// TalkBack on Android WebView reliably announces newly *appended*
|
|
22
|
-
// nodes but often misses text-content updates on existing
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
const region = document.getElementById(_Constants.HtmlIdNames.fileSentAnnouncementRegionId);
|
|
26
|
-
if (region) {
|
|
27
|
-
region.textContent = "";
|
|
28
|
-
}
|
|
21
|
+
// TalkBack on Android WebView reliably announces newly *appended*
|
|
22
|
+
// role="alert" nodes but often misses text-content updates on existing
|
|
23
|
+
// nodes. Wait 500ms for the send-box focus shift to settle, then inject
|
|
24
|
+
// a fresh alert element appended to document.body and remove it after 3s.
|
|
29
25
|
setTimeout(() => {
|
|
30
26
|
const el = document.createElement("div");
|
|
31
27
|
el.setAttribute("role", "alert");
|
|
@@ -16,6 +16,32 @@ let currentAgentName = _defaultWebChatStyles.defaultWebChatStyles.botAvatarIniti
|
|
|
16
16
|
|
|
17
17
|
// Optional external updater (React context dispatch wrapper) set at runtime
|
|
18
18
|
let externalInitialsUpdater;
|
|
19
|
+
const hasTransferTag = activity => {
|
|
20
|
+
var _activity$channelData;
|
|
21
|
+
const tags = [...(Array.isArray(activity === null || activity === void 0 ? void 0 : (_activity$channelData = activity.channelData) === null || _activity$channelData === void 0 ? void 0 : _activity$channelData.tags) ? activity.channelData.tags : []), ...(Array.isArray(activity === null || activity === void 0 ? void 0 : activity.tags) ? activity.tags : [])];
|
|
22
|
+
return tags.some(tag => typeof tag === "string" && tag.toLowerCase().includes("transfer"));
|
|
23
|
+
};
|
|
24
|
+
const isTransferSystemMessage = activity => {
|
|
25
|
+
const text = ((activity === null || activity === void 0 ? void 0 : activity.text) || "").toString();
|
|
26
|
+
return hasTransferTag(activity) || /\btransfer(?:red|ring)?\b/i.test(text);
|
|
27
|
+
};
|
|
28
|
+
const resetCachedAgentName = dispatch => {
|
|
29
|
+
if (currentAgentName !== _defaultWebChatStyles.defaultWebChatStyles.botAvatarInitials || currentAgentInitials !== _defaultWebChatStyles.defaultWebChatStyles.botAvatarInitials) {
|
|
30
|
+
var _externalInitialsUpda;
|
|
31
|
+
currentAgentName = _defaultWebChatStyles.defaultWebChatStyles.botAvatarInitials;
|
|
32
|
+
currentAgentInitials = _defaultWebChatStyles.defaultWebChatStyles.botAvatarInitials;
|
|
33
|
+
(_externalInitialsUpda = externalInitialsUpdater) === null || _externalInitialsUpda === void 0 ? void 0 : _externalInitialsUpda(currentAgentInitials || "");
|
|
34
|
+
_omnichannelChatComponents.BroadcastService.postMessage({
|
|
35
|
+
eventName: "BotAvatarInitialsUpdated",
|
|
36
|
+
payload: {
|
|
37
|
+
initials: currentAgentInitials
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
dispatch({
|
|
41
|
+
type: "__BOT_INITIALS_UPDATED__"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
19
45
|
const localizedStringsBotInitialsMiddleware = onInitialsChange => _ref => {
|
|
20
46
|
let {
|
|
21
47
|
dispatch
|
|
@@ -29,19 +55,31 @@ const localizedStringsBotInitialsMiddleware = onInitialsChange => _ref => {
|
|
|
29
55
|
var _action$payload, _activity$from;
|
|
30
56
|
const activity = (_action$payload = action.payload) === null || _action$payload === void 0 ? void 0 : _action$payload.activity;
|
|
31
57
|
if (activity !== null && activity !== void 0 && (_activity$from = activity.from) !== null && _activity$from !== void 0 && _activity$from.name && activity.from.role !== _Constants.Constants.userMessageTag && activity.from.name !== _Constants.Constants.userMessageTag) {
|
|
32
|
-
var _activity$
|
|
58
|
+
var _activity$channelData2, _activity$channelData3, _activity$tags;
|
|
33
59
|
const agentName = activity.from.name.trim();
|
|
34
|
-
const isSystemMessage = agentName === "__agent__" || agentName.startsWith("__") || ((_activity$
|
|
35
|
-
if (
|
|
60
|
+
const isSystemMessage = agentName === "__agent__" || agentName.startsWith("__") || ((_activity$channelData2 = activity.channelData) === null || _activity$channelData2 === void 0 ? void 0 : (_activity$channelData3 = _activity$channelData2.tags) === null || _activity$channelData3 === void 0 ? void 0 : _activity$channelData3.includes(_Constants.Constants.systemMessageTag)) || ((_activity$tags = activity.tags) === null || _activity$tags === void 0 ? void 0 : _activity$tags.includes(_Constants.Constants.systemMessageTag));
|
|
61
|
+
if (isSystemMessage) {
|
|
62
|
+
// transfer-stale-bot-name: when a transfer system message indicates the
|
|
63
|
+
// conversation has been routed to a different agent, the
|
|
64
|
+
// previously-cached agent name must NOT linger. Otherwise the
|
|
65
|
+
// next non-system activity (e.g. typing indicator, welcome
|
|
66
|
+
// message, or the new agent's first turn before their name
|
|
67
|
+
// is observed) is announced to screen readers as the OLD
|
|
68
|
+
// agent. Reset to defaults so the next observed name takes
|
|
69
|
+
// effect cleanly.
|
|
70
|
+
if (isTransferSystemMessage(activity)) {
|
|
71
|
+
resetCachedAgentName(dispatch);
|
|
72
|
+
}
|
|
73
|
+
} else if (agentName) {
|
|
36
74
|
const newInitials = (0, _utils.getIconText)(agentName) || currentAgentInitials;
|
|
37
75
|
const hasInitialsChanged = newInitials !== currentAgentInitials;
|
|
38
76
|
const hasNameChanged = agentName !== currentAgentName;
|
|
39
77
|
currentAgentName = agentName;
|
|
40
78
|
if (hasInitialsChanged) {
|
|
41
|
-
var
|
|
79
|
+
var _externalInitialsUpda2;
|
|
42
80
|
currentAgentInitials = newInitials;
|
|
43
81
|
// Notify external React context if provided
|
|
44
|
-
(
|
|
82
|
+
(_externalInitialsUpda2 = externalInitialsUpdater) === null || _externalInitialsUpda2 === void 0 ? void 0 : _externalInitialsUpda2(currentAgentInitials || "");
|
|
45
83
|
// Broadcast (optional) for multi-tab sync without forcing consumers
|
|
46
84
|
_omnichannelChatComponents.BroadcastService.postMessage({
|
|
47
85
|
eventName: "BotAvatarInitialsUpdated",
|
|
@@ -149,7 +149,6 @@ export let HtmlIdNames = /*#__PURE__*/_createClass(function HtmlIdNames() {
|
|
|
149
149
|
_classCallCheck(this, HtmlIdNames);
|
|
150
150
|
});
|
|
151
151
|
_defineProperty(HtmlIdNames, "MSLiveChatWidget", "MSLiveChatWidget");
|
|
152
|
-
_defineProperty(HtmlIdNames, "fileSentAnnouncementRegionId", "ms_lcw_file_sent_announcement");
|
|
153
152
|
export let HtmlClassNames = /*#__PURE__*/_createClass(function HtmlClassNames() {
|
|
154
153
|
_classCallCheck(this, HtmlClassNames);
|
|
155
154
|
});
|
|
@@ -58,6 +58,7 @@ export const PostChatSurveyPaneStateful = props => {
|
|
|
58
58
|
};
|
|
59
59
|
const controlProps = {
|
|
60
60
|
id: "oc-lcw-postchatsurvey-pane",
|
|
61
|
+
title: "Post-chat survey",
|
|
61
62
|
surveyURL: ((_props$controlProps = props.controlProps) === null || _props$controlProps === void 0 ? void 0 : _props$controlProps.surveyURL) ?? surveyInviteLink,
|
|
62
63
|
...props.controlProps
|
|
63
64
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HtmlAttributeNames, Regex } from "../../common/Constants";
|
|
2
2
|
import { ConversationStage, LogLevel, TelemetryEvent } from "../../common/telemetry/TelemetryConstants";
|
|
3
|
-
import React, { useEffect } from "react";
|
|
3
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
4
4
|
import { createTimer, extractPreChatSurveyResponseValues, findAllFocusableElement, getStateFromCache, getWidgetCacheId, isUndefinedOrEmpty, parseAdaptiveCardPayload } from "../../common/utils";
|
|
5
5
|
import { ConversationState } from "../../contexts/common/ConversationState";
|
|
6
6
|
import { LiveChatWidgetActionType } from "../../contexts/common/LiveChatWidgetActionType";
|
|
@@ -11,6 +11,34 @@ import { defaultGeneralPreChatSurveyPaneStyleProps } from "./common/defaultStyle
|
|
|
11
11
|
import { defaultPreChatSurveyLocalizedTexts } from "./common/defaultProps/defaultPreChatSurveyLocalizedTexts";
|
|
12
12
|
import useChatContextStore from "../../hooks/useChatContextStore";
|
|
13
13
|
let uiTimer;
|
|
14
|
+
const getFocusedElementAnnouncement = element => {
|
|
15
|
+
var _element$textContent;
|
|
16
|
+
const ariaLabel = element.getAttribute(HtmlAttributeNames.ariaLabel);
|
|
17
|
+
if (ariaLabel) {
|
|
18
|
+
return ariaLabel.trim();
|
|
19
|
+
}
|
|
20
|
+
const ariaLabelledBy = element.getAttribute(HtmlAttributeNames.ariaLabelledby);
|
|
21
|
+
if (ariaLabelledBy) {
|
|
22
|
+
const labelledByText = ariaLabelledBy.split(/\s+/).map(id => {
|
|
23
|
+
var _document$getElementB, _document$getElementB2;
|
|
24
|
+
return (_document$getElementB = document.getElementById(id)) === null || _document$getElementB === void 0 ? void 0 : (_document$getElementB2 = _document$getElementB.textContent) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.trim();
|
|
25
|
+
}).filter(Boolean).join(" ");
|
|
26
|
+
if (labelledByText) {
|
|
27
|
+
return labelledByText;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (element.id) {
|
|
31
|
+
const label = Array.from(document.querySelectorAll("label")).find(candidate => candidate.htmlFor === element.id || candidate.getAttribute("for") === element.id);
|
|
32
|
+
if (label !== null && label !== void 0 && label.textContent) {
|
|
33
|
+
return label.textContent.trim();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const parentLabel = element.closest("label");
|
|
37
|
+
if (parentLabel !== null && parentLabel !== void 0 && parentLabel.textContent) {
|
|
38
|
+
return parentLabel.textContent.trim();
|
|
39
|
+
}
|
|
40
|
+
return ((_element$textContent = element.textContent) === null || _element$textContent === void 0 ? void 0 : _element$textContent.trim()) ?? "";
|
|
41
|
+
};
|
|
14
42
|
|
|
15
43
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
44
|
export const PreChatSurveyPaneStateful = props => {
|
|
@@ -33,6 +61,8 @@ export const PreChatSurveyPaneStateful = props => {
|
|
|
33
61
|
surveyProps,
|
|
34
62
|
initStartChat
|
|
35
63
|
} = props;
|
|
64
|
+
const [preChatFocusAnnouncement, setPreChatFocusAnnouncement] = useState("");
|
|
65
|
+
const liveRegionUpdateTimeout = useRef();
|
|
36
66
|
const generalStyleProps = Object.assign({}, defaultGeneralPreChatSurveyPaneStyleProps, surveyProps === null || surveyProps === void 0 ? void 0 : (_surveyProps$stylePro = surveyProps.styleProps) === null || _surveyProps$stylePro === void 0 ? void 0 : _surveyProps$stylePro.generalStyleProps, {
|
|
37
67
|
display: state.appStates.isMinimized ? "none" : ""
|
|
38
68
|
});
|
|
@@ -119,6 +149,16 @@ export const PreChatSurveyPaneStateful = props => {
|
|
|
119
149
|
...(surveyProps === null || surveyProps === void 0 ? void 0 : surveyProps.styleProps),
|
|
120
150
|
generalStyleProps: generalStyleProps
|
|
121
151
|
};
|
|
152
|
+
const announceFocusedElement = event => {
|
|
153
|
+
if (liveRegionUpdateTimeout.current) {
|
|
154
|
+
window.clearTimeout(liveRegionUpdateTimeout.current);
|
|
155
|
+
}
|
|
156
|
+
const announcement = getFocusedElementAnnouncement(event.target);
|
|
157
|
+
setPreChatFocusAnnouncement("");
|
|
158
|
+
liveRegionUpdateTimeout.current = window.setTimeout(() => {
|
|
159
|
+
setPreChatFocusAnnouncement(announcement);
|
|
160
|
+
}, 0);
|
|
161
|
+
};
|
|
122
162
|
useEffect(() => {
|
|
123
163
|
// Set Aria-Label Attribute for Inputs
|
|
124
164
|
const adaptiveCardElements = document.getElementsByClassName(HtmlAttributeNames.adaptiveCardClassName);
|
|
@@ -166,9 +206,31 @@ export const PreChatSurveyPaneStateful = props => {
|
|
|
166
206
|
}
|
|
167
207
|
}
|
|
168
208
|
}, [state.appStates.isMinimized]);
|
|
169
|
-
|
|
209
|
+
useEffect(() => () => {
|
|
210
|
+
if (liveRegionUpdateTimeout.current) {
|
|
211
|
+
window.clearTimeout(liveRegionUpdateTimeout.current);
|
|
212
|
+
}
|
|
213
|
+
}, []);
|
|
214
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
215
|
+
onFocusCapture: announceFocusedElement
|
|
216
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
217
|
+
role: "status",
|
|
218
|
+
"aria-live": "polite",
|
|
219
|
+
"aria-atomic": "true",
|
|
220
|
+
style: {
|
|
221
|
+
position: "absolute",
|
|
222
|
+
width: "1px",
|
|
223
|
+
height: "1px",
|
|
224
|
+
margin: "-1px",
|
|
225
|
+
padding: 0,
|
|
226
|
+
border: 0,
|
|
227
|
+
clip: "rect(0, 0, 0, 0)",
|
|
228
|
+
overflow: "hidden",
|
|
229
|
+
whiteSpace: "nowrap"
|
|
230
|
+
}
|
|
231
|
+
}, preChatFocusAnnouncement), /*#__PURE__*/React.createElement(PreChatSurveyPane, {
|
|
170
232
|
controlProps: controlProps,
|
|
171
233
|
styleProps: styleProps
|
|
172
|
-
});
|
|
234
|
+
}));
|
|
173
235
|
};
|
|
174
236
|
export default PreChatSurveyPaneStateful;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Constants, HtmlAttributeNames, HtmlClassNames
|
|
1
|
+
import { Constants, HtmlAttributeNames, HtmlClassNames } from "../../common/Constants";
|
|
2
2
|
import { Stack } from "@fluentui/react";
|
|
3
3
|
import { LogLevel, TelemetryEvent } from "../../common/telemetry/TelemetryConstants";
|
|
4
4
|
import React, { useEffect, useRef, useState } from "react";
|
|
@@ -223,6 +223,48 @@ export const WebChatContainerStateful = props => {
|
|
|
223
223
|
chatHistoryElement.setAttribute(HtmlAttributeNames.ariaLabel, webChatContainerProps.webChatHistoryMobileAccessibilityLabel);
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
+
|
|
227
|
+
// internal tracking: WebChats BasicToaster renders a `role="log"` container
|
|
228
|
+
// with no accessible name. When the toaster is empty (typical idle
|
|
229
|
+
// state) screen readers traversing the page announce it as "blank".
|
|
230
|
+
// Inject an aria-label so the region has a meaningful name; the
|
|
231
|
+
// consumer can override via the new
|
|
232
|
+
// `webChatNotificationRegionAccessibilityLabel` prop. The toaster
|
|
233
|
+
// may not be rendered yet when this effect first runs, so observe
|
|
234
|
+
// for it via a MutationObserver scoped to the widget root (or, if
|
|
235
|
+
// not yet mounted, the widget container's parent) so we never fire
|
|
236
|
+
// on host-page mutations outside the widget subtree.
|
|
237
|
+
const toasterLabel = (webChatContainerProps === null || webChatContainerProps === void 0 ? void 0 : webChatContainerProps.webChatNotificationRegionAccessibilityLabel) ?? defaultWebChatContainerStatefulProps.webChatNotificationRegionAccessibilityLabel ?? "Chat notifications";
|
|
238
|
+
const labelToaster = root => {
|
|
239
|
+
const toaster = root.querySelector(".webchat__toaster[role='log']");
|
|
240
|
+
if (toaster && !toaster.getAttribute(HtmlAttributeNames.ariaLabel)) {
|
|
241
|
+
toaster.setAttribute(HtmlAttributeNames.ariaLabel, toasterLabel);
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
};
|
|
246
|
+
// Prefer the widget root; if it is not yet in the DOM, fall back to
|
|
247
|
+
// `document` for the *initial* lookup only, then observe the most
|
|
248
|
+
// specific available scope (widget root if present, otherwise the
|
|
249
|
+
// widget's parent / document.body as a last resort). The observer
|
|
250
|
+
// re-resolves the widget root on every callback so we tighten scope
|
|
251
|
+
// as soon as it mounts.
|
|
252
|
+
let toasterObserver;
|
|
253
|
+
const resolveScope = () => document.getElementById("ms_lcw_webchat_root") ?? document.body;
|
|
254
|
+
if (!labelToaster(resolveScope())) {
|
|
255
|
+
toasterObserver = new MutationObserver(() => {
|
|
256
|
+
const scope = resolveScope();
|
|
257
|
+
if (labelToaster(scope)) {
|
|
258
|
+
var _toasterObserver;
|
|
259
|
+
(_toasterObserver = toasterObserver) === null || _toasterObserver === void 0 ? void 0 : _toasterObserver.disconnect();
|
|
260
|
+
toasterObserver = undefined;
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
toasterObserver.observe(resolveScope(), {
|
|
264
|
+
childList: true,
|
|
265
|
+
subtree: true
|
|
266
|
+
});
|
|
267
|
+
}
|
|
226
268
|
dispatch({
|
|
227
269
|
type: LiveChatWidgetActionType.SET_RENDERING_MIDDLEWARE_PROPS,
|
|
228
270
|
payload: webChatContainerProps === null || webChatContainerProps === void 0 ? void 0 : webChatContainerProps.renderingMiddlewareProps
|
|
@@ -247,6 +289,10 @@ export const WebChatContainerStateful = props => {
|
|
|
247
289
|
}
|
|
248
290
|
}
|
|
249
291
|
}
|
|
292
|
+
return () => {
|
|
293
|
+
var _toasterObserver2;
|
|
294
|
+
(_toasterObserver2 = toasterObserver) === null || _toasterObserver2 === void 0 ? void 0 : _toasterObserver2.disconnect();
|
|
295
|
+
};
|
|
250
296
|
}, []);
|
|
251
297
|
useEffect(() => {
|
|
252
298
|
var _props$webChatContain6, _props$webChatContain7;
|
|
@@ -487,23 +533,7 @@ export const WebChatContainerStateful = props => {
|
|
|
487
533
|
height: "100%",
|
|
488
534
|
width: "100%"
|
|
489
535
|
}
|
|
490
|
-
}, shouldLoadPersistentHistoryMessages && /*#__PURE__*/React.createElement(WebChatEventSubscribers, null), /*#__PURE__*/React.createElement(BasicWebChat, null))), /*#__PURE__*/React.createElement(
|
|
491
|
-
id: HtmlIdNames.fileSentAnnouncementRegionId,
|
|
492
|
-
role: "alert",
|
|
493
|
-
"aria-live": "assertive",
|
|
494
|
-
"aria-atomic": "true",
|
|
495
|
-
style: {
|
|
496
|
-
position: "absolute",
|
|
497
|
-
width: "1px",
|
|
498
|
-
height: "1px",
|
|
499
|
-
padding: "0",
|
|
500
|
-
margin: "-1px",
|
|
501
|
-
overflow: "hidden",
|
|
502
|
-
clip: "rect(0, 0, 0, 0)",
|
|
503
|
-
whiteSpace: "nowrap",
|
|
504
|
-
border: "0"
|
|
505
|
-
}
|
|
506
|
-
}), citationPaneOpen && /*#__PURE__*/React.createElement(CitationPaneStateful, {
|
|
536
|
+
}, shouldLoadPersistentHistoryMessages && /*#__PURE__*/React.createElement(WebChatEventSubscribers, null), /*#__PURE__*/React.createElement(BasicWebChat, null))), citationPaneOpen && /*#__PURE__*/React.createElement(CitationPaneStateful, {
|
|
507
537
|
id: ((_props$citationPanePr = props.citationPaneProps) === null || _props$citationPanePr === void 0 ? void 0 : _props$citationPanePr.id) || HtmlAttributeNames.ocwCitationPaneClassName,
|
|
508
538
|
title: ((_props$citationPanePr2 = props.citationPaneProps) === null || _props$citationPanePr2 === void 0 ? void 0 : _props$citationPanePr2.title) || HtmlAttributeNames.ocwCitationPaneTitle,
|
|
509
539
|
contentHtml: citationPaneText,
|
|
@@ -13,5 +13,6 @@ export const defaultWebChatContainerStatefulProps = {
|
|
|
13
13
|
honorsTargetInHTMLLinks: false,
|
|
14
14
|
hyperlinkTextOverride: false,
|
|
15
15
|
directLine: new MockAdapter(),
|
|
16
|
-
adaptiveCardStyles: defaultAdaptiveCardStyles
|
|
16
|
+
adaptiveCardStyles: defaultAdaptiveCardStyles,
|
|
17
|
+
webChatNotificationRegionAccessibilityLabel: "Chat notifications"
|
|
17
18
|
};
|
|
@@ -25,6 +25,21 @@ const AdaptiveCardAccessibilityWrapper = _ref => {
|
|
|
25
25
|
const container = containerRef.current;
|
|
26
26
|
if (!container) return;
|
|
27
27
|
|
|
28
|
+
// dropdown-double-label: compact Input.ChoiceSet renders as a native
|
|
29
|
+
// <select> with both aria-labelledby and a sibling visible <label for>.
|
|
30
|
+
// Only remove aria-labelledby when it points solely at that same visible
|
|
31
|
+
// label; preserve composite labels that include required/error/context text.
|
|
32
|
+
const compactSelects = container.querySelectorAll(".ac-input-container select.ac-input.ac-multichoiceInput[aria-labelledby]");
|
|
33
|
+
compactSelects.forEach(select => {
|
|
34
|
+
const id = select.id;
|
|
35
|
+
if (!id) return;
|
|
36
|
+
const visibleLabel = container.querySelector(`label[for="${CSS.escape(id)}"]:not([aria-hidden='true'])`);
|
|
37
|
+
const labelledBy = (select.getAttribute("aria-labelledby") || "").trim().split(/\s+/);
|
|
38
|
+
if (visibleLabel !== null && visibleLabel !== void 0 && visibleLabel.id && labelledBy.length === 1 && labelledBy[0] === visibleLabel.id) {
|
|
39
|
+
select.removeAttribute("aria-labelledby");
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
28
43
|
// action-button-toggle / login-button-toggle: submit/login action buttons can be
|
|
29
44
|
// rendered with toggle-only ARIA that causes screen readers to announce them as
|
|
30
45
|
// switches instead of plain push buttons. Preserve Action.ToggleVisibility buttons,
|
|
@@ -5,21 +5,17 @@
|
|
|
5
5
|
******/
|
|
6
6
|
|
|
7
7
|
import { LogLevel, TelemetryEvent } from "../../../../../common/telemetry/TelemetryConstants";
|
|
8
|
-
import { AMSConstants
|
|
8
|
+
import { AMSConstants } from "../../../../../common/Constants";
|
|
9
9
|
import { NotificationHandler } from "../../notification/NotificationHandler";
|
|
10
10
|
import { NotificationScenarios } from "../../enums/NotificationScenarios";
|
|
11
11
|
import { TelemetryHelper } from "../../../../../common/telemetry/TelemetryHelper";
|
|
12
12
|
import { WebChatActionType } from "../../enums/WebChatActionType";
|
|
13
13
|
const MBtoBRatio = 1000000;
|
|
14
14
|
const announceFileSent = message => {
|
|
15
|
-
// TalkBack on Android WebView reliably announces newly *appended*
|
|
16
|
-
// nodes but often misses text-content updates on existing
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
const region = document.getElementById(HtmlIdNames.fileSentAnnouncementRegionId);
|
|
20
|
-
if (region) {
|
|
21
|
-
region.textContent = "";
|
|
22
|
-
}
|
|
15
|
+
// TalkBack on Android WebView reliably announces newly *appended*
|
|
16
|
+
// role="alert" nodes but often misses text-content updates on existing
|
|
17
|
+
// nodes. Wait 500ms for the send-box focus shift to settle, then inject
|
|
18
|
+
// a fresh alert element appended to document.body and remove it after 3s.
|
|
23
19
|
setTimeout(() => {
|
|
24
20
|
const el = document.createElement("div");
|
|
25
21
|
el.setAttribute("role", "alert");
|
|
@@ -10,6 +10,32 @@ let currentAgentName = defaultWebChatStyles.botAvatarInitials;
|
|
|
10
10
|
|
|
11
11
|
// Optional external updater (React context dispatch wrapper) set at runtime
|
|
12
12
|
let externalInitialsUpdater;
|
|
13
|
+
const hasTransferTag = activity => {
|
|
14
|
+
var _activity$channelData;
|
|
15
|
+
const tags = [...(Array.isArray(activity === null || activity === void 0 ? void 0 : (_activity$channelData = activity.channelData) === null || _activity$channelData === void 0 ? void 0 : _activity$channelData.tags) ? activity.channelData.tags : []), ...(Array.isArray(activity === null || activity === void 0 ? void 0 : activity.tags) ? activity.tags : [])];
|
|
16
|
+
return tags.some(tag => typeof tag === "string" && tag.toLowerCase().includes("transfer"));
|
|
17
|
+
};
|
|
18
|
+
const isTransferSystemMessage = activity => {
|
|
19
|
+
const text = ((activity === null || activity === void 0 ? void 0 : activity.text) || "").toString();
|
|
20
|
+
return hasTransferTag(activity) || /\btransfer(?:red|ring)?\b/i.test(text);
|
|
21
|
+
};
|
|
22
|
+
const resetCachedAgentName = dispatch => {
|
|
23
|
+
if (currentAgentName !== defaultWebChatStyles.botAvatarInitials || currentAgentInitials !== defaultWebChatStyles.botAvatarInitials) {
|
|
24
|
+
var _externalInitialsUpda;
|
|
25
|
+
currentAgentName = defaultWebChatStyles.botAvatarInitials;
|
|
26
|
+
currentAgentInitials = defaultWebChatStyles.botAvatarInitials;
|
|
27
|
+
(_externalInitialsUpda = externalInitialsUpdater) === null || _externalInitialsUpda === void 0 ? void 0 : _externalInitialsUpda(currentAgentInitials || "");
|
|
28
|
+
BroadcastService.postMessage({
|
|
29
|
+
eventName: "BotAvatarInitialsUpdated",
|
|
30
|
+
payload: {
|
|
31
|
+
initials: currentAgentInitials
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
dispatch({
|
|
35
|
+
type: "__BOT_INITIALS_UPDATED__"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
13
39
|
export const localizedStringsBotInitialsMiddleware = onInitialsChange => _ref => {
|
|
14
40
|
let {
|
|
15
41
|
dispatch
|
|
@@ -23,19 +49,31 @@ export const localizedStringsBotInitialsMiddleware = onInitialsChange => _ref =>
|
|
|
23
49
|
var _action$payload, _activity$from;
|
|
24
50
|
const activity = (_action$payload = action.payload) === null || _action$payload === void 0 ? void 0 : _action$payload.activity;
|
|
25
51
|
if (activity !== null && activity !== void 0 && (_activity$from = activity.from) !== null && _activity$from !== void 0 && _activity$from.name && activity.from.role !== Constants.userMessageTag && activity.from.name !== Constants.userMessageTag) {
|
|
26
|
-
var _activity$
|
|
52
|
+
var _activity$channelData2, _activity$channelData3, _activity$tags;
|
|
27
53
|
const agentName = activity.from.name.trim();
|
|
28
|
-
const isSystemMessage = agentName === "__agent__" || agentName.startsWith("__") || ((_activity$
|
|
29
|
-
if (
|
|
54
|
+
const isSystemMessage = agentName === "__agent__" || agentName.startsWith("__") || ((_activity$channelData2 = activity.channelData) === null || _activity$channelData2 === void 0 ? void 0 : (_activity$channelData3 = _activity$channelData2.tags) === null || _activity$channelData3 === void 0 ? void 0 : _activity$channelData3.includes(Constants.systemMessageTag)) || ((_activity$tags = activity.tags) === null || _activity$tags === void 0 ? void 0 : _activity$tags.includes(Constants.systemMessageTag));
|
|
55
|
+
if (isSystemMessage) {
|
|
56
|
+
// transfer-stale-bot-name: when a transfer system message indicates the
|
|
57
|
+
// conversation has been routed to a different agent, the
|
|
58
|
+
// previously-cached agent name must NOT linger. Otherwise the
|
|
59
|
+
// next non-system activity (e.g. typing indicator, welcome
|
|
60
|
+
// message, or the new agent's first turn before their name
|
|
61
|
+
// is observed) is announced to screen readers as the OLD
|
|
62
|
+
// agent. Reset to defaults so the next observed name takes
|
|
63
|
+
// effect cleanly.
|
|
64
|
+
if (isTransferSystemMessage(activity)) {
|
|
65
|
+
resetCachedAgentName(dispatch);
|
|
66
|
+
}
|
|
67
|
+
} else if (agentName) {
|
|
30
68
|
const newInitials = getIconText(agentName) || currentAgentInitials;
|
|
31
69
|
const hasInitialsChanged = newInitials !== currentAgentInitials;
|
|
32
70
|
const hasNameChanged = agentName !== currentAgentName;
|
|
33
71
|
currentAgentName = agentName;
|
|
34
72
|
if (hasInitialsChanged) {
|
|
35
|
-
var
|
|
73
|
+
var _externalInitialsUpda2;
|
|
36
74
|
currentAgentInitials = newInitials;
|
|
37
75
|
// Notify external React context if provided
|
|
38
|
-
(
|
|
76
|
+
(_externalInitialsUpda2 = externalInitialsUpdater) === null || _externalInitialsUpda2 === void 0 ? void 0 : _externalInitialsUpda2(currentAgentInitials || "");
|
|
39
77
|
// Broadcast (optional) for multi-tab sync without forcing consumers
|
|
40
78
|
BroadcastService.postMessage({
|
|
41
79
|
eventName: "BotAvatarInitialsUpdated",
|
|
@@ -119,7 +119,6 @@ export declare const Regex: {
|
|
|
119
119
|
};
|
|
120
120
|
export declare class HtmlIdNames {
|
|
121
121
|
static readonly MSLiveChatWidget = "MSLiveChatWidget";
|
|
122
|
-
static readonly fileSentAnnouncementRegionId = "ms_lcw_file_sent_announcement";
|
|
123
122
|
}
|
|
124
123
|
export declare class HtmlClassNames {
|
|
125
124
|
static readonly webChatBannerCloseButton = "webchat__toast__dismissButton";
|
package/lib/types/components/webchatcontainerstateful/interfaces/IWebChatContainerStatefulProps.d.ts
CHANGED
|
@@ -25,4 +25,11 @@ export interface IWebChatContainerStatefulProps {
|
|
|
25
25
|
adaptiveCardStyles?: IAdaptiveCardStyles;
|
|
26
26
|
sendBoxTextBox?: ISendBox;
|
|
27
27
|
webChatHistoryMobileAccessibilityLabel?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Accessible name applied to WebChats notification toaster region
|
|
30
|
+
* (`role="log"`). When omitted, defaults to "Chat notifications" so
|
|
31
|
+
* screen readers don't announce the empty live region as "blank"
|
|
32
|
+
* (internal tracking).
|
|
33
|
+
*/
|
|
34
|
+
webChatNotificationRegionAccessibilityLabel?: string;
|
|
28
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/omnichannel-chat-widget",
|
|
3
|
-
"version": "1.8.4-main.
|
|
3
|
+
"version": "1.8.4-main.810d050",
|
|
4
4
|
"description": "Microsoft Omnichannel Chat Widget",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"types": "lib/types/index.d.ts",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"react-test-renderer": "^18.3.1",
|
|
85
85
|
"rimraf": "^6.0.1",
|
|
86
86
|
"storybook-addon-playwright": "^4.9.2",
|
|
87
|
-
"swiper": "^
|
|
87
|
+
"swiper": "^12.1.2",
|
|
88
88
|
"terser-webpack-plugin": "^4.2.3",
|
|
89
89
|
"thread-loader": "^2.1.3",
|
|
90
90
|
"ts-loader": "^9.2.6",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"dependencies": {
|
|
96
96
|
"@azure/core-tracing": "^1.2.0",
|
|
97
97
|
"@microsoft/applicationinsights-web": "^3.3.6",
|
|
98
|
-
"@microsoft/omnichannel-chat-components": "1.1.17-main.
|
|
98
|
+
"@microsoft/omnichannel-chat-components": "1.1.17-main.f21df63",
|
|
99
99
|
"@microsoft/omnichannel-chat-sdk": "1.11.9-main.da8219b",
|
|
100
100
|
"@opentelemetry/api": "^1.9.0",
|
|
101
101
|
"abort-controller": "^3",
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
"**/lodash": "4.17.23",
|
|
173
173
|
"**/@babel/runtime-corejs3": "^7.29.0",
|
|
174
174
|
"**/brace-expansion": "2.0.3",
|
|
175
|
-
"**/swiper": "
|
|
175
|
+
"**/swiper": "12.1.2"
|
|
176
176
|
},
|
|
177
177
|
"jest": {
|
|
178
178
|
"verbose": true,
|