@microsoft/omnichannel-chat-widget 1.8.4-main.2e8be66 → 1.8.4-main.319d589
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/webchatcontainerstateful/WebChatContainerStateful.js +47 -17
- package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatAdapter.js +10 -0
- package/lib/cjs/components/webchatcontainerstateful/common/defaultProps/defaultWebChatContainerStatefulProps.js +2 -1
- package/lib/cjs/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +3 -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/esm/common/Constants.js +0 -1
- package/lib/esm/components/webchatcontainerstateful/WebChatContainerStateful.js +48 -18
- package/lib/esm/components/webchatcontainerstateful/common/DesignerChatAdapter.js +10 -0
- package/lib/esm/components/webchatcontainerstateful/common/defaultProps/defaultWebChatContainerStatefulProps.js +2 -1
- package/lib/esm/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +3 -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/types/common/Constants.d.ts +0 -1
- package/lib/types/components/webchatcontainerstateful/common/utils/chatAdapterUtils.d.ts +1 -1
- package/lib/types/components/webchatcontainerstateful/interfaces/IWebChatContainerStatefulProps.d.ts +7 -0
- package/package.json +1 -1
|
@@ -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
|
});
|
|
@@ -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,
|
|
@@ -59,6 +59,16 @@ let DesignerChatAdapter = /*#__PURE__*/function (_MockAdapter) {
|
|
|
59
59
|
if (msg.text) {
|
|
60
60
|
if (msg.suggestedActions) {
|
|
61
61
|
(0, _chatAdapterUtils.postAgentSuggestedActionsActivity)(this.activityObserver, msg.text, msg.suggestedActions, index * 100);
|
|
62
|
+
} else if (msg.from && msg.from.role) {
|
|
63
|
+
// Route caller-supplied `from` through the shared
|
|
64
|
+
// postBotMessageActivity helper so the activity shape
|
|
65
|
+
// (id, channelData.tags, timestamp, type) matches every
|
|
66
|
+
// other designer-mode path and downstream middleware
|
|
67
|
+
// (localizedStringsBotInitialsMiddleware, telemetry,
|
|
68
|
+
// attachment plumbing) behaves identically. The override
|
|
69
|
+
// narrows only the fields the caller cares about (e.g.
|
|
70
|
+
// from.name / from.role) — base botUser fields remain.
|
|
71
|
+
(0, _chatAdapterUtils.postBotMessageActivity)(this.activityObserver, msg.text, undefined, index * 100, msg.from);
|
|
62
72
|
} else {
|
|
63
73
|
(0, _chatAdapterUtils.postBotMessageActivity)(this.activityObserver, msg.text, undefined, index * 100);
|
|
64
74
|
}
|
|
@@ -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;
|
|
@@ -44,11 +44,13 @@ exports.postEchoActivity = postEchoActivity;
|
|
|
44
44
|
const postBotMessageActivity = function (activityObserver, text) {
|
|
45
45
|
let tags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "";
|
|
46
46
|
let delay = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1000;
|
|
47
|
+
let fromOverride = arguments.length > 4 ? arguments[4] : undefined;
|
|
47
48
|
setTimeout(() => {
|
|
48
49
|
activityObserver === null || activityObserver === void 0 ? void 0 : activityObserver.next({
|
|
49
50
|
id: (0, _omnichannelChatSdk.uuidv4)(),
|
|
50
51
|
from: {
|
|
51
|
-
...botUser
|
|
52
|
+
...botUser,
|
|
53
|
+
...(fromOverride ?? {})
|
|
52
54
|
},
|
|
53
55
|
text,
|
|
54
56
|
type: "message",
|
|
@@ -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");
|
|
@@ -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
|
});
|
|
@@ -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,
|
|
@@ -52,6 +52,16 @@ export let DesignerChatAdapter = /*#__PURE__*/function (_MockAdapter) {
|
|
|
52
52
|
if (msg.text) {
|
|
53
53
|
if (msg.suggestedActions) {
|
|
54
54
|
postAgentSuggestedActionsActivity(this.activityObserver, msg.text, msg.suggestedActions, index * 100);
|
|
55
|
+
} else if (msg.from && msg.from.role) {
|
|
56
|
+
// Route caller-supplied `from` through the shared
|
|
57
|
+
// postBotMessageActivity helper so the activity shape
|
|
58
|
+
// (id, channelData.tags, timestamp, type) matches every
|
|
59
|
+
// other designer-mode path and downstream middleware
|
|
60
|
+
// (localizedStringsBotInitialsMiddleware, telemetry,
|
|
61
|
+
// attachment plumbing) behaves identically. The override
|
|
62
|
+
// narrows only the fields the caller cares about (e.g.
|
|
63
|
+
// from.name / from.role) — base botUser fields remain.
|
|
64
|
+
postBotMessageActivity(this.activityObserver, msg.text, undefined, index * 100, msg.from);
|
|
55
65
|
} else {
|
|
56
66
|
postBotMessageActivity(this.activityObserver, msg.text, undefined, index * 100);
|
|
57
67
|
}
|
|
@@ -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
|
};
|
|
@@ -34,11 +34,13 @@ export const postEchoActivity = function (activityObserver, activity, user) {
|
|
|
34
34
|
export const postBotMessageActivity = function (activityObserver, text) {
|
|
35
35
|
let tags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "";
|
|
36
36
|
let delay = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1000;
|
|
37
|
+
let fromOverride = arguments.length > 4 ? arguments[4] : undefined;
|
|
37
38
|
setTimeout(() => {
|
|
38
39
|
activityObserver === null || activityObserver === void 0 ? void 0 : activityObserver.next({
|
|
39
40
|
id: uuidv4(),
|
|
40
41
|
from: {
|
|
41
|
-
...botUser
|
|
42
|
+
...botUser,
|
|
43
|
+
...(fromOverride ?? {})
|
|
42
44
|
},
|
|
43
45
|
text,
|
|
44
46
|
type: "message",
|
|
@@ -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");
|
|
@@ -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";
|
|
@@ -4,7 +4,7 @@ export declare const customerUser: User;
|
|
|
4
4
|
export declare const botUser: User;
|
|
5
5
|
export declare const agentUser: User;
|
|
6
6
|
export declare const postEchoActivity: (activityObserver: Subscriber<Activity> | undefined, activity: Message, user: User, delay?: number) => void;
|
|
7
|
-
export declare const postBotMessageActivity: (activityObserver: Subscriber<Activity> | undefined, text: string, tags?: string, delay?: number) => void;
|
|
7
|
+
export declare const postBotMessageActivity: (activityObserver: Subscriber<Activity> | undefined, text: string, tags?: string, delay?: number, fromOverride?: Partial<User>) => void;
|
|
8
8
|
export declare const postAgentMessageActivity: (activityObserver: Subscriber<Activity> | undefined, text: string, tags?: string, delay?: number) => void;
|
|
9
9
|
export declare const postSystemMessageActivity: (activityObserver: Subscriber<Activity> | undefined, text: string, delay?: number) => void;
|
|
10
10
|
export declare const postBotTypingActivity: (activityObserver: Subscriber<Activity> | undefined, delay?: number) => void;
|
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
|
}
|