@microsoft/omnichannel-chat-components 1.1.19 → 1.2.0-main.5ebd4eb
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/README.md +140 -1
- package/lib/cjs/common/Constants.js +8 -11
- package/lib/cjs/components/callingcontainer/subcomponents/CurrentCall/CurrentCall.js +10 -3
- package/lib/cjs/components/callingcontainer/subcomponents/Timer/Timer.js +10 -1
- package/lib/cjs/components/chatbutton/ChatButton.blankAnnouncements.a11y.spec.js +158 -0
- package/lib/cjs/components/chatbutton/ChatButton.browseMode.a11y.spec.js +227 -0
- package/lib/cjs/components/chatbutton/ChatButton.browseMode.unfixed.a11y.spec.js +112 -0
- package/lib/cjs/components/chatbutton/ChatButton.js +52 -16
- package/lib/cjs/components/common/subcomponents/CloseButton.js +1 -3
- package/lib/cjs/components/confirmationpane/ConfirmationPane.js +10 -8
- package/lib/cjs/components/confirmationpane/common/defaultProps/defaultConfirmationPaneControlProps.js +1 -0
- package/lib/cjs/components/footer/subcomponents/AudioNotificationButton.js +11 -4
- package/lib/cjs/components/footer/subcomponents/DownloadTranscriptButton.js +1 -3
- package/lib/cjs/components/footer/subcomponents/EmailTranscriptButton.js +1 -3
- package/lib/cjs/components/header/Header.js +16 -4
- package/lib/cjs/components/header/common/defaultStyles/defaultHeaderStyleProps.js +23 -0
- package/lib/cjs/components/header/subcomponents/MinimizeButton.js +1 -3
- package/lib/cjs/components/inputvalidationpane/InputValidationPane.js +34 -14
- package/lib/cjs/components/inputvalidationpane/common/default/defaultProps/defaultInputValidationPaneControlProps.js +1 -0
- package/lib/cjs/components/notificationpane/subcomponents/CloseChatButton.js +1 -3
- package/lib/cjs/components/notificationpane/subcomponents/DismissButton.js +1 -3
- package/lib/cjs/components/prechatsurveypane/PreChatSurveyPane.js +94 -17
- package/lib/cjs/components/prechatsurveypane/common/defaultProps/defaultStyles/defaultPreChatSurveyPaneMultichoiceInputStyles.js +1 -0
- package/lib/cjs/components/prechatsurveypane/common/defaultProps/defaultStyles/defaultPreChatSurveyPaneMultilineTextInputStyles.js +1 -0
- package/lib/cjs/components/prechatsurveypane/common/defaultProps/defaultStyles/defaultPreChatSurveyPaneTextInputStyles.js +1 -0
- package/lib/cjs/package.json +1 -0
- package/lib/cjs/services/EventQueue.js +4 -7
- package/lib/esm/common/Constants.js +1 -1
- package/lib/esm/components/callingcontainer/subcomponents/CurrentCall/CurrentCall.js +10 -3
- package/lib/esm/components/callingcontainer/subcomponents/Timer/Timer.js +10 -1
- package/lib/esm/components/chatbutton/ChatButton.blankAnnouncements.a11y.spec.js +155 -0
- package/lib/esm/components/chatbutton/ChatButton.browseMode.a11y.spec.js +224 -0
- package/lib/esm/components/chatbutton/ChatButton.browseMode.unfixed.a11y.spec.js +108 -0
- package/lib/esm/components/chatbutton/ChatButton.js +53 -16
- package/lib/esm/components/common/subcomponents/CloseButton.js +1 -3
- package/lib/esm/components/confirmationpane/ConfirmationPane.js +10 -8
- package/lib/esm/components/confirmationpane/common/defaultProps/defaultConfirmationPaneControlProps.js +1 -0
- package/lib/esm/components/footer/subcomponents/AudioNotificationButton.js +11 -4
- package/lib/esm/components/footer/subcomponents/DownloadTranscriptButton.js +1 -3
- package/lib/esm/components/footer/subcomponents/EmailTranscriptButton.js +1 -3
- package/lib/esm/components/header/Header.js +16 -4
- package/lib/esm/components/header/common/defaultStyles/defaultHeaderStyleProps.js +23 -0
- package/lib/esm/components/header/subcomponents/MinimizeButton.js +1 -3
- package/lib/esm/components/inputvalidationpane/InputValidationPane.js +34 -14
- package/lib/esm/components/inputvalidationpane/common/default/defaultProps/defaultInputValidationPaneControlProps.js +1 -0
- package/lib/esm/components/notificationpane/subcomponents/CloseChatButton.js +1 -3
- package/lib/esm/components/notificationpane/subcomponents/DismissButton.js +1 -3
- package/lib/esm/components/prechatsurveypane/PreChatSurveyPane.js +94 -16
- package/lib/esm/components/prechatsurveypane/common/defaultProps/defaultStyles/defaultPreChatSurveyPaneMultichoiceInputStyles.js +1 -0
- package/lib/esm/components/prechatsurveypane/common/defaultProps/defaultStyles/defaultPreChatSurveyPaneMultilineTextInputStyles.js +1 -0
- package/lib/esm/components/prechatsurveypane/common/defaultProps/defaultStyles/defaultPreChatSurveyPaneTextInputStyles.js +1 -0
- package/lib/types/common/Constants.d.ts +2 -0
- package/lib/types/components/chatbutton/ChatButton.blankAnnouncements.a11y.spec.d.ts +1 -0
- package/lib/types/components/chatbutton/ChatButton.browseMode.a11y.spec.d.ts +1 -0
- package/lib/types/components/chatbutton/ChatButton.browseMode.unfixed.a11y.spec.d.ts +1 -0
- package/lib/types/components/confirmationpane/interfaces/IConfirmationPaneControlProps.d.ts +1 -0
- package/lib/types/components/header/interfaces/IHeaderStyleProps.d.ts +12 -0
- package/lib/types/components/inputvalidationpane/interfaces/IInputValidationPaneControlProps.d.ts +1 -0
- package/package.json +41 -32
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
require("@testing-library/jest-dom/extend-expect");
|
|
4
|
+
var _react = require("@testing-library/react");
|
|
5
|
+
var _BroadcastService = require("../../services/BroadcastService");
|
|
6
|
+
var _ChatButton = _interopRequireDefault(require("./ChatButton"));
|
|
7
|
+
var _react2 = _interopRequireDefault(require("react"));
|
|
8
|
+
var _defaultChatButtonProps = require("./common/defaultProps/defaultChatButtonProps");
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Repro / catcher for internal tracking — NVDA / JAWS in browse mode (virtual cursor)
|
|
14
|
+
* land on "Let's Chat, We're Online" multiple times when navigating with the
|
|
15
|
+
* down-arrow key.
|
|
16
|
+
*
|
|
17
|
+
* Root cause in code: `ChatButton` renders a Fluent UI `<Stack role="button">`
|
|
18
|
+
* with `tabIndex={0}` whose accessible name is computed from its visible
|
|
19
|
+
* children — a `<Label>` for the title (e.g. "Let's Chat!") and a `<Label>`
|
|
20
|
+
* for the subtitle (e.g. "We're online."). In browse mode, NVDA / JAWS treat
|
|
21
|
+
* the button itself AND each inner text node as separate virtual-cursor stops,
|
|
22
|
+
* each carrying the same announceable name fragments. There is no
|
|
23
|
+
* `aria-label` set by default, and the inner labels are not marked
|
|
24
|
+
* `aria-hidden="true"` (which is what would collapse them into a single
|
|
25
|
+
* announcement under the button container).
|
|
26
|
+
*
|
|
27
|
+
* Catcher contract: in the rendered chat-button subtree, at most ONE element
|
|
28
|
+
* may expose each of the title / subtitle strings as an announceable name
|
|
29
|
+
* source. An "announceable name source" here is:
|
|
30
|
+
* - an `aria-label` attribute on a focusable / role-bearing element, OR
|
|
31
|
+
* - a visible `<Label>` (or other text-bearing element) that is NOT
|
|
32
|
+
* `aria-hidden="true"` and is not nested inside an element that is
|
|
33
|
+
* `aria-hidden="true"`.
|
|
34
|
+
*
|
|
35
|
+
* Regression guard: in the rendered DOM, the parent role=button Stack owns a
|
|
36
|
+
* single consolidated aria-label (synthesized from title + subtitle, plus
|
|
37
|
+
* unread-count fragment when applicable) and the inner Labels live inside an
|
|
38
|
+
* aria-hidden text container so browse-mode lands on the button exactly once.
|
|
39
|
+
* Override paths (componentOverrides.title/subtitle/textContainer or a
|
|
40
|
+
* consumer-supplied controlProps.ariaLabel) are preserved unchanged so
|
|
41
|
+
* customers who manage their own accessible names are not affected.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
beforeAll(() => {
|
|
45
|
+
(0, _BroadcastService.BroadcastServiceInitialize)("testChannel");
|
|
46
|
+
});
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
(0, _react.cleanup)();
|
|
49
|
+
});
|
|
50
|
+
const isInsideAriaHidden = el => {
|
|
51
|
+
let cursor = el;
|
|
52
|
+
while (cursor) {
|
|
53
|
+
if (cursor.getAttribute("aria-hidden") === "true") return true;
|
|
54
|
+
cursor = cursor.parentElement;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
};
|
|
58
|
+
const visibleTextElementsMatching = (root, text) => {
|
|
59
|
+
return Array.from(root.querySelectorAll("*")).filter(el => {
|
|
60
|
+
if (isInsideAriaHidden(el)) return false;
|
|
61
|
+
// Only count leaf-ish text-bearing elements (don't double-count
|
|
62
|
+
// ancestors whose textContent obviously aggregates children).
|
|
63
|
+
const ownText = Array.from(el.childNodes).filter(n => n.nodeType === Node.TEXT_NODE).map(n => (n.textContent || "").trim()).join(" ").trim();
|
|
64
|
+
return ownText === text;
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Regression guard for internal tracking — ChatButton must not produce duplicate
|
|
70
|
+
* NVDA / JAWS browse-mode stops. Visible title / subtitle text is excluded
|
|
71
|
+
* from the accessibility tree (aria-hidden) and the button container owns a
|
|
72
|
+
* single consolidated aria-label.
|
|
73
|
+
*/
|
|
74
|
+
describe("ChatButton — browse-mode duplicate stops (internal tracking)", () => {
|
|
75
|
+
it("title text 'Let's Chat!' must NOT appear as a visible (non-aria-hidden) name source in the chat-button subtree", () => {
|
|
76
|
+
const _render = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, _defaultChatButtonProps.defaultChatButtonProps)),
|
|
77
|
+
container = _render.container;
|
|
78
|
+
const button = container.firstElementChild;
|
|
79
|
+
expect(button).not.toBeNull();
|
|
80
|
+
const titleStops = visibleTextElementsMatching(button, "Let's Chat!");
|
|
81
|
+
// The visible title should be excluded from the accessibility tree
|
|
82
|
+
// (e.g. via aria-hidden on the text container) so the announced name
|
|
83
|
+
// comes solely from the consolidated aria-label on the button. Any
|
|
84
|
+
// exposed text-bearing element with this exact text creates an
|
|
85
|
+
// additional browse-mode stop and reproduces internal tracking.
|
|
86
|
+
expect(titleStops.length).toBe(0);
|
|
87
|
+
});
|
|
88
|
+
it("subtitle text 'We're online.' must NOT appear as a visible (non-aria-hidden) name source in the chat-button subtree", () => {
|
|
89
|
+
const _render2 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, _defaultChatButtonProps.defaultChatButtonProps)),
|
|
90
|
+
container = _render2.container;
|
|
91
|
+
const button = container.firstElementChild;
|
|
92
|
+
expect(button).not.toBeNull();
|
|
93
|
+
const subtitleStops = visibleTextElementsMatching(button, "We're online.");
|
|
94
|
+
expect(subtitleStops.length).toBe(0);
|
|
95
|
+
});
|
|
96
|
+
it("the chat-button container must own a single consolidated aria-label so browse mode lands on it once", () => {
|
|
97
|
+
const _render3 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, _defaultChatButtonProps.defaultChatButtonProps)),
|
|
98
|
+
container = _render3.container;
|
|
99
|
+
const button = container.firstElementChild;
|
|
100
|
+
expect(button).not.toBeNull();
|
|
101
|
+
// Either the container has a non-empty aria-label, OR every inner
|
|
102
|
+
// text-bearing descendant is aria-hidden so the computed name comes
|
|
103
|
+
// from the inner text exactly once with no extra browse-mode stops.
|
|
104
|
+
const hasAriaLabel = !!(button.getAttribute("aria-label") || "").trim();
|
|
105
|
+
const innerVisibleText = visibleTextElementsMatching(button, "Let's Chat!").length + visibleTextElementsMatching(button, "We're online.").length;
|
|
106
|
+
// Today: hasAriaLabel === false (default ariaLabel is undefined) AND
|
|
107
|
+
// innerVisibleText > 0. The catcher requires at least one of these
|
|
108
|
+
// to flip.
|
|
109
|
+
expect(hasAriaLabel || innerVisibleText === 0).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
it("the synthesized aria-label includes the unread-count fragment when hideNotificationBubble=false and unreadMessageCount > 0", () => {
|
|
112
|
+
const props = {
|
|
113
|
+
..._defaultChatButtonProps.defaultChatButtonProps,
|
|
114
|
+
controlProps: {
|
|
115
|
+
..._defaultChatButtonProps.defaultChatButtonProps.controlProps,
|
|
116
|
+
hideNotificationBubble: false,
|
|
117
|
+
unreadMessageCount: "3",
|
|
118
|
+
ariaLabelUnreadMessageString: "you have new messages",
|
|
119
|
+
titleText: "Let's Chat!",
|
|
120
|
+
subtitleText: "We're online."
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const _render4 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, props)),
|
|
124
|
+
container = _render4.container;
|
|
125
|
+
const button = container.firstElementChild;
|
|
126
|
+
const ariaLabel = button.getAttribute("aria-label") || "";
|
|
127
|
+
expect(ariaLabel).toContain("3");
|
|
128
|
+
expect(ariaLabel).toContain("you have new messages");
|
|
129
|
+
expect(ariaLabel).toContain("Let's Chat!");
|
|
130
|
+
expect(ariaLabel).toContain("We're online.");
|
|
131
|
+
});
|
|
132
|
+
it("a consumer-supplied controlProps.ariaLabel wins over the synthesized label", () => {
|
|
133
|
+
const props = {
|
|
134
|
+
..._defaultChatButtonProps.defaultChatButtonProps,
|
|
135
|
+
controlProps: {
|
|
136
|
+
..._defaultChatButtonProps.defaultChatButtonProps.controlProps,
|
|
137
|
+
ariaLabel: "Talk to a live agent"
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const _render5 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, props)),
|
|
141
|
+
container = _render5.container;
|
|
142
|
+
const button = container.firstElementChild;
|
|
143
|
+
expect(button.getAttribute("aria-label")).toBe("Talk to a live agent");
|
|
144
|
+
});
|
|
145
|
+
it("componentOverrides.textContainer preserves consumer-rendered visible text (synthesis is skipped)", () => {
|
|
146
|
+
const customText = "My custom chat text";
|
|
147
|
+
const props = {
|
|
148
|
+
..._defaultChatButtonProps.defaultChatButtonProps,
|
|
149
|
+
componentOverrides: {
|
|
150
|
+
textContainer: /*#__PURE__*/_react2.default.createElement("div", {
|
|
151
|
+
id: "my-custom-text"
|
|
152
|
+
}, customText)
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const _render6 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, props)),
|
|
156
|
+
container = _render6.container;
|
|
157
|
+
const button = container.firstElementChild;
|
|
158
|
+
// The custom text MUST remain visible in the a11y tree so consumers
|
|
159
|
+
// who replace the text container keep their announced text.
|
|
160
|
+
const customStops = visibleTextElementsMatching(button, customText);
|
|
161
|
+
expect(customStops.length).toBeGreaterThan(0);
|
|
162
|
+
// And the button must NOT carry a synthesized aria-label that would
|
|
163
|
+
// override the consumer's content.
|
|
164
|
+
const ariaLabel = (button.getAttribute("aria-label") || "").trim();
|
|
165
|
+
expect(ariaLabel).toBe("");
|
|
166
|
+
});
|
|
167
|
+
it("componentOverrides.title preserves consumer-rendered visible title (synthesis is skipped)", () => {
|
|
168
|
+
const customTitle = "Custom override title";
|
|
169
|
+
const props = {
|
|
170
|
+
..._defaultChatButtonProps.defaultChatButtonProps,
|
|
171
|
+
componentOverrides: {
|
|
172
|
+
title: /*#__PURE__*/_react2.default.createElement("span", {
|
|
173
|
+
id: "my-custom-title"
|
|
174
|
+
}, customTitle)
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
const _render7 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, props)),
|
|
178
|
+
container = _render7.container;
|
|
179
|
+
const button = container.firstElementChild;
|
|
180
|
+
const customStops = visibleTextElementsMatching(button, customTitle);
|
|
181
|
+
expect(customStops.length).toBeGreaterThan(0);
|
|
182
|
+
const ariaLabel = (button.getAttribute("aria-label") || "").trim();
|
|
183
|
+
expect(ariaLabel).toBe("");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Regression guard for the strict string-equality slip-throughs that
|
|
187
|
+
// brittle `unreadMessageCount !== "0"` allowed: values that coerce to
|
|
188
|
+
// numeric 0 (or non-numeric noise) must NOT render the bubble nor pollute
|
|
189
|
+
// the synthesized aria-label with a "0 you have new messages" fragment.
|
|
190
|
+
describe.each([["padded zero (' 0 ')", " 0 "], ["decimal zero ('0.0')", "0.0"], ["empty string ('')", ""], ["non-numeric ('abc')", "abc"]])("zero-equivalent unreadMessageCount: %s", (_label, value) => {
|
|
191
|
+
it("does NOT render the notification bubble", () => {
|
|
192
|
+
const props = {
|
|
193
|
+
..._defaultChatButtonProps.defaultChatButtonProps,
|
|
194
|
+
controlProps: {
|
|
195
|
+
..._defaultChatButtonProps.defaultChatButtonProps.controlProps,
|
|
196
|
+
hideNotificationBubble: false,
|
|
197
|
+
unreadMessageCount: value,
|
|
198
|
+
ariaLabelUnreadMessageString: "you have new messages"
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const _render8 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, props)),
|
|
202
|
+
container = _render8.container;
|
|
203
|
+
const bubble = container.querySelector("[id$='-notification-bubble']");
|
|
204
|
+
expect(bubble).toBeNull();
|
|
205
|
+
});
|
|
206
|
+
it("does NOT inject the unread-count fragment into the synthesized aria-label", () => {
|
|
207
|
+
const props = {
|
|
208
|
+
..._defaultChatButtonProps.defaultChatButtonProps,
|
|
209
|
+
controlProps: {
|
|
210
|
+
..._defaultChatButtonProps.defaultChatButtonProps.controlProps,
|
|
211
|
+
hideNotificationBubble: false,
|
|
212
|
+
unreadMessageCount: value,
|
|
213
|
+
ariaLabelUnreadMessageString: "you have new messages"
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const _render9 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, props)),
|
|
217
|
+
container = _render9.container;
|
|
218
|
+
const button = container.firstElementChild;
|
|
219
|
+
const ariaLabel = button.getAttribute("aria-label") || "";
|
|
220
|
+
expect(ariaLabel).not.toContain("you have new messages");
|
|
221
|
+
// and the raw zero-equivalent must not leak into the label
|
|
222
|
+
if (value.trim().length > 0) {
|
|
223
|
+
expect(ariaLabel).not.toContain(value.trim());
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
require("@testing-library/jest-dom/extend-expect");
|
|
4
|
+
var _react = require("@testing-library/react");
|
|
5
|
+
var _BroadcastService = require("../../services/BroadcastService");
|
|
6
|
+
var _ChatButton = _interopRequireDefault(require("./ChatButton"));
|
|
7
|
+
var _react2 = _interopRequireDefault(require("react"));
|
|
8
|
+
var _defaultChatButtonControlProps = require("./common/defaultProps/defaultChatButtonControlProps");
|
|
9
|
+
var _defaultChatButtonProps = require("./common/defaultProps/defaultChatButtonProps");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
12
|
+
|
|
13
|
+
const expectedTitle = _defaultChatButtonControlProps.defaultChatButtonControlProps.titleText;
|
|
14
|
+
const expectedSubtitle = _defaultChatButtonControlProps.defaultChatButtonControlProps.subtitleText;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Repro / catcher for internal tracking — NVDA / JAWS in browse mode (virtual cursor)
|
|
18
|
+
* land on "Let's Chat, We're Online" multiple times when navigating with the
|
|
19
|
+
* down-arrow key.
|
|
20
|
+
*
|
|
21
|
+
* Root cause in code: `ChatButton` renders a Fluent UI `<Stack role="button">`
|
|
22
|
+
* with `tabIndex={0}` whose accessible name is computed from its visible
|
|
23
|
+
* children — a `<Label>` for the title (e.g. "Let's Chat!") and a `<Label>`
|
|
24
|
+
* for the subtitle (e.g. "We're online."). In browse mode, NVDA / JAWS treat
|
|
25
|
+
* the button itself AND each inner text node as separate virtual-cursor stops,
|
|
26
|
+
* each carrying the same announceable name fragments. There is no
|
|
27
|
+
* `aria-label` set by default, and the inner labels are not marked
|
|
28
|
+
* `aria-hidden="true"` (which is what would collapse them into a single
|
|
29
|
+
* announcement under the button container).
|
|
30
|
+
*
|
|
31
|
+
* Catcher contract: the title / subtitle strings must NOT appear as
|
|
32
|
+
* additional announceable name sources in the chat-button subtree (only the
|
|
33
|
+
* single consolidated aria-label on the role=button container should name the
|
|
34
|
+
* button). An "announceable name source" here is:
|
|
35
|
+
* - an `aria-label` attribute on a focusable / role-bearing element, OR
|
|
36
|
+
* - a visible `<Label>` (or other text-bearing element) that is NOT
|
|
37
|
+
* `aria-hidden="true"` and is not nested inside an element that is
|
|
38
|
+
* `aria-hidden="true"`.
|
|
39
|
+
*
|
|
40
|
+
* Expected to FAIL today: the rendered DOM contains BOTH the title text node
|
|
41
|
+
* AND the subtitle text node as bare visible text, and the parent Stack has
|
|
42
|
+
* no `aria-label` to consolidate them. Browse-mode therefore sees three
|
|
43
|
+
* stops (button, title, subtitle) all carrying the same combined name.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
beforeAll(() => {
|
|
47
|
+
(0, _BroadcastService.BroadcastServiceInitialize)("testChannel");
|
|
48
|
+
});
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
(0, _react.cleanup)();
|
|
51
|
+
});
|
|
52
|
+
const isInsideAriaHidden = el => {
|
|
53
|
+
let cursor = el;
|
|
54
|
+
while (cursor) {
|
|
55
|
+
if (cursor.getAttribute("aria-hidden") === "true") return true;
|
|
56
|
+
cursor = cursor.parentElement;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
const visibleTextElementsMatching = (root, text) => {
|
|
61
|
+
return Array.from(root.querySelectorAll("*")).filter(el => {
|
|
62
|
+
if (isInsideAriaHidden(el)) return false;
|
|
63
|
+
// Only count leaf-ish text-bearing elements (don't double-count
|
|
64
|
+
// ancestors whose textContent obviously aggregates children).
|
|
65
|
+
const ownText = Array.from(el.childNodes).filter(n => n.nodeType === Node.TEXT_NODE).map(n => (n.textContent || "").trim()).join(" ").trim();
|
|
66
|
+
return ownText === text;
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* SKIPPED until the source fix lands. Un-skip the describe below to validate
|
|
72
|
+
* the fix to internal tracking; the suite is expected to FAIL today against unfixed
|
|
73
|
+
* source. Mirrors the chat-widget `*.unfixed.a11y.spec.tsx` convention.
|
|
74
|
+
*/
|
|
75
|
+
describe.skip("ChatButton — browse-mode duplicate stops (internal tracking)", () => {
|
|
76
|
+
it(`title text '${expectedTitle}' must NOT appear as a visible (non-aria-hidden) name source in the chat-button subtree`, () => {
|
|
77
|
+
const _render = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, _defaultChatButtonProps.defaultChatButtonProps)),
|
|
78
|
+
container = _render.container;
|
|
79
|
+
const button = container.firstElementChild;
|
|
80
|
+
expect(button).not.toBeNull();
|
|
81
|
+
const titleStops = visibleTextElementsMatching(button, expectedTitle);
|
|
82
|
+
// The visible title should be excluded from the accessibility tree
|
|
83
|
+
// (e.g. via aria-hidden on the text container) so the announced name
|
|
84
|
+
// comes solely from the consolidated aria-label on the button. Any
|
|
85
|
+
// exposed text-bearing element with this exact text creates an
|
|
86
|
+
// additional browse-mode stop and reproduces internal tracking.
|
|
87
|
+
expect(titleStops.length).toBe(0);
|
|
88
|
+
});
|
|
89
|
+
it(`subtitle text '${expectedSubtitle}' must NOT appear as a visible (non-aria-hidden) name source in the chat-button subtree`, () => {
|
|
90
|
+
const _render2 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, _defaultChatButtonProps.defaultChatButtonProps)),
|
|
91
|
+
container = _render2.container;
|
|
92
|
+
const button = container.firstElementChild;
|
|
93
|
+
expect(button).not.toBeNull();
|
|
94
|
+
const subtitleStops = visibleTextElementsMatching(button, expectedSubtitle);
|
|
95
|
+
expect(subtitleStops.length).toBe(0);
|
|
96
|
+
});
|
|
97
|
+
it("the chat-button container must own a single consolidated aria-label so browse mode lands on it once", () => {
|
|
98
|
+
const _render3 = (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_ChatButton.default, _defaultChatButtonProps.defaultChatButtonProps)),
|
|
99
|
+
container = _render3.container;
|
|
100
|
+
const button = container.firstElementChild;
|
|
101
|
+
expect(button).not.toBeNull();
|
|
102
|
+
// Either the container has a non-empty aria-label, OR every inner
|
|
103
|
+
// text-bearing descendant is aria-hidden so the computed name comes
|
|
104
|
+
// from the inner text exactly once with no extra browse-mode stops.
|
|
105
|
+
const hasAriaLabel = !!(button.getAttribute("aria-label") || "").trim();
|
|
106
|
+
const innerVisibleText = visibleTextElementsMatching(button, expectedTitle).length + visibleTextElementsMatching(button, expectedSubtitle).length;
|
|
107
|
+
// Today: hasAriaLabel === false (default ariaLabel is undefined) AND
|
|
108
|
+
// innerVisibleText > 0. The catcher requires at least one of these
|
|
109
|
+
// to flip.
|
|
110
|
+
expect(hasAriaLabel || innerVisibleText === 0).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -17,13 +17,24 @@ var _defaultChatButtonSubTitleStyles = require("./common/defaultStyles/defaultCh
|
|
|
17
17
|
var _defaultChatButtonTextContainerStyles = require("./common/defaultStyles/defaultChatButtonTextContainerStyles");
|
|
18
18
|
var _defaultChatButtonTitleStyles = require("./common/defaultStyles/defaultChatButtonTitleStyles");
|
|
19
19
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
20
|
+
// Returns true when the unread-message count represents a positive number.
|
|
21
|
+
// Defensive against non-strict callers that may pass " 0 ", "0.0", "" or a
|
|
22
|
+
// stringified numeric 0; only a finite count strictly greater than zero counts
|
|
23
|
+
// as "unread" for both the notification bubble and the synthesized aria-label.
|
|
24
|
+
function hasUnreadMessages(unreadMessageCount) {
|
|
25
|
+
if (unreadMessageCount === undefined || unreadMessageCount === null) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const parsed = Number(unreadMessageCount);
|
|
29
|
+
return Number.isFinite(parsed) && parsed > 0;
|
|
30
|
+
}
|
|
20
31
|
function NotificationBubble(props, parentId) {
|
|
21
32
|
var _props$styleProps, _props$controlProps;
|
|
22
33
|
const notificationBubbleStyles = {
|
|
23
34
|
root: Object.assign({}, _defaultChatButtonNotificationBubbleStyles.defaultChatButtonNotificationBubbleStyles, (_props$styleProps = props.styleProps) === null || _props$styleProps === void 0 ? void 0 : _props$styleProps.notificationBubbleStyleProps)
|
|
24
35
|
};
|
|
25
36
|
const unreadMessageCount = ((_props$controlProps = props.controlProps) === null || _props$controlProps === void 0 ? void 0 : _props$controlProps.unreadMessageCount) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.unreadMessageCount);
|
|
26
|
-
if (unreadMessageCount
|
|
37
|
+
if (hasUnreadMessages(unreadMessageCount)) {
|
|
27
38
|
var _props$componentOverr, _props$controlProps2, _props$controlProps3, _props$styleProps2, _props$controlProps4, _props$controlProps5;
|
|
28
39
|
return (0, _decodeComponentString.decodeComponentString)((_props$componentOverr = props.componentOverrides) === null || _props$componentOverr === void 0 ? void 0 : _props$componentOverr.notificationBubble) || /*#__PURE__*/_react2.default.createElement(_react.Stack, {
|
|
29
40
|
"aria-live": "polite",
|
|
@@ -49,7 +60,7 @@ function IconContainer(props, parentId) {
|
|
|
49
60
|
});
|
|
50
61
|
}
|
|
51
62
|
function TextContainer(props, parentId) {
|
|
52
|
-
var _props$styleProps5, _props$styleProps6, _props$styleProps7, _props$controlProps6, _props$controlProps7, _props$controlProps8, _props$controlProps9, _props$controlProps0, _props$controlProps1, _props$componentOverr3, _props$styleProps8, _props$
|
|
63
|
+
var _props$styleProps5, _props$styleProps6, _props$styleProps7, _props$controlProps6, _props$controlProps7, _props$controlProps8, _props$controlProps9, _props$controlProps0, _props$controlProps1, _props$componentOverr3, _props$componentOverr4, _props$componentOverr5, _props$styleProps8, _props$componentOverr6, _props$styleProps9, _props$componentOverr7, _props$styleProps0;
|
|
53
64
|
const textContainerStyles = {
|
|
54
65
|
root: Object.assign({}, _defaultChatButtonTextContainerStyles.defaultChatButtonTextContainerStyles, (_props$styleProps5 = props.styleProps) === null || _props$styleProps5 === void 0 ? void 0 : _props$styleProps5.textContainerStyleProps)
|
|
55
66
|
};
|
|
@@ -65,16 +76,26 @@ function TextContainer(props, parentId) {
|
|
|
65
76
|
const titleText = ((_props$controlProps9 = props.controlProps) === null || _props$controlProps9 === void 0 ? void 0 : _props$controlProps9.titleText) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.titleText);
|
|
66
77
|
const subtitleDir = ((_props$controlProps0 = props.controlProps) === null || _props$controlProps0 === void 0 ? void 0 : _props$controlProps0.dir) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.dir);
|
|
67
78
|
const subtitleText = ((_props$controlProps1 = props.controlProps) === null || _props$controlProps1 === void 0 ? void 0 : _props$controlProps1.subtitleText) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.subtitleText);
|
|
68
|
-
|
|
79
|
+
|
|
80
|
+
// internal tracking: when the default title / subtitle Labels are used, hide the
|
|
81
|
+
// text container subtree from the accessibility tree. The button container
|
|
82
|
+
// owns a consolidated aria-label that already announces the same text, so
|
|
83
|
+
// exposing the inner Labels causes NVDA / JAWS browse-mode to land on the
|
|
84
|
+
// same announcement multiple times. Customer overrides for title /
|
|
85
|
+
// subtitle keep their default a11y behavior so they can manage their own
|
|
86
|
+
// accessible names.
|
|
87
|
+
const hideTextFromA11yTree = !((_props$componentOverr3 = props.componentOverrides) !== null && _props$componentOverr3 !== void 0 && _props$componentOverr3.title) && !((_props$componentOverr4 = props.componentOverrides) !== null && _props$componentOverr4 !== void 0 && _props$componentOverr4.subtitle);
|
|
88
|
+
return (0, _decodeComponentString.decodeComponentString)((_props$componentOverr5 = props.componentOverrides) === null || _props$componentOverr5 === void 0 ? void 0 : _props$componentOverr5.textContainer) || /*#__PURE__*/_react2.default.createElement(_react.Stack, {
|
|
69
89
|
styles: textContainerStyles,
|
|
70
90
|
className: (_props$styleProps8 = props.styleProps) === null || _props$styleProps8 === void 0 || (_props$styleProps8 = _props$styleProps8.classNames) === null || _props$styleProps8 === void 0 ? void 0 : _props$styleProps8.textContainerClassName,
|
|
71
|
-
id: parentId + "-text-container"
|
|
72
|
-
|
|
91
|
+
id: parentId + "-text-container",
|
|
92
|
+
"aria-hidden": hideTextFromA11yTree || undefined
|
|
93
|
+
}, !hideChatTitle && ((0, _decodeComponentString.decodeComponentString)((_props$componentOverr6 = props.componentOverrides) === null || _props$componentOverr6 === void 0 ? void 0 : _props$componentOverr6.title) || /*#__PURE__*/_react2.default.createElement(_react.Label, {
|
|
73
94
|
styles: titleStyles,
|
|
74
95
|
dir: titleDir,
|
|
75
96
|
className: (_props$styleProps9 = props.styleProps) === null || _props$styleProps9 === void 0 || (_props$styleProps9 = _props$styleProps9.classNames) === null || _props$styleProps9 === void 0 ? void 0 : _props$styleProps9.titleClassName,
|
|
76
97
|
id: parentId + "-title"
|
|
77
|
-
}, titleText)), !hideChatSubtitle && ((0, _decodeComponentString.decodeComponentString)((_props$
|
|
98
|
+
}, titleText)), !hideChatSubtitle && ((0, _decodeComponentString.decodeComponentString)((_props$componentOverr7 = props.componentOverrides) === null || _props$componentOverr7 === void 0 ? void 0 : _props$componentOverr7.subtitle) || /*#__PURE__*/_react2.default.createElement(_react.Label, {
|
|
78
99
|
styles: subtitleStyles,
|
|
79
100
|
dir: subtitleDir,
|
|
80
101
|
className: (_props$styleProps0 = props.styleProps) === null || _props$styleProps0 === void 0 || (_props$styleProps0 = _props$styleProps0.classNames) === null || _props$styleProps0 === void 0 ? void 0 : _props$styleProps0.subtitleClassName,
|
|
@@ -82,21 +103,36 @@ function TextContainer(props, parentId) {
|
|
|
82
103
|
}, subtitleText)));
|
|
83
104
|
}
|
|
84
105
|
function ChatButton(props) {
|
|
85
|
-
var _props$controlProps10, _props$controlProps11, _props$controlProps12, _props$controlProps13, _props$controlProps14, _props$controlProps15, _props$controlProps16, _props$controlProps17, _props$styleProps1;
|
|
106
|
+
var _props$controlProps10, _props$controlProps11, _props$controlProps12, _props$controlProps13, _props$controlProps14, _props$controlProps15, _props$controlProps16, _props$controlProps17, _props$controlProps18, _props$controlProps19, _props$controlProps20, _props$controlProps21, _props$controlProps22, _props$componentOverr8, _props$componentOverr9, _props$componentOverr0, _props$controlProps23, _props$styleProps1;
|
|
86
107
|
const elementId = ((_props$controlProps10 = props.controlProps) === null || _props$controlProps10 === void 0 ? void 0 : _props$controlProps10.id) ?? _Constants.Ids.DefaultChatButtonId;
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
|
|
108
|
+
const defaultRole = ((_props$controlProps11 = props.controlProps) === null || _props$controlProps11 === void 0 ? void 0 : _props$controlProps11.role) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.role);
|
|
109
|
+
const containersDir = ((_props$controlProps12 = props.controlProps) === null || _props$controlProps12 === void 0 ? void 0 : _props$controlProps12.dir) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.dir);
|
|
110
|
+
const hideChatButton = ((_props$controlProps13 = props.controlProps) === null || _props$controlProps13 === void 0 ? void 0 : _props$controlProps13.hideChatButton) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.hideChatButton);
|
|
111
|
+
const hideChatIcon = ((_props$controlProps14 = props.controlProps) === null || _props$controlProps14 === void 0 ? void 0 : _props$controlProps14.hideChatIcon) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.hideChatIcon);
|
|
112
|
+
const hideChatTextContainer = ((_props$controlProps15 = props.controlProps) === null || _props$controlProps15 === void 0 ? void 0 : _props$controlProps15.hideChatTextContainer) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.hideChatTextContainer);
|
|
113
|
+
const hideNotificationBubble = ((_props$controlProps16 = props.controlProps) === null || _props$controlProps16 === void 0 ? void 0 : _props$controlProps16.hideNotificationBubble) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.hideNotificationBubble);
|
|
114
|
+
|
|
115
|
+
// internal tracking: when the consumer has not supplied a custom aria-label and
|
|
116
|
+
// the default title / subtitle Labels are in play, synthesize a single
|
|
117
|
+
// consolidated aria-label from the visible text so NVDA / JAWS browse
|
|
118
|
+
// mode lands on the role=button container exactly once. The text
|
|
119
|
+
// container is also marked aria-hidden in TextContainer so the inner
|
|
120
|
+
// labels do not produce additional virtual-cursor stops.
|
|
121
|
+
const titleText = ((_props$controlProps17 = props.controlProps) === null || _props$controlProps17 === void 0 ? void 0 : _props$controlProps17.titleText) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.titleText);
|
|
122
|
+
const subtitleText = ((_props$controlProps18 = props.controlProps) === null || _props$controlProps18 === void 0 ? void 0 : _props$controlProps18.subtitleText) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.subtitleText);
|
|
123
|
+
const hideChatTitle = ((_props$controlProps19 = props.controlProps) === null || _props$controlProps19 === void 0 ? void 0 : _props$controlProps19.hideChatTitle) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.hideChatTitle);
|
|
124
|
+
const hideChatSubtitle = ((_props$controlProps20 = props.controlProps) === null || _props$controlProps20 === void 0 ? void 0 : _props$controlProps20.hideChatSubtitle) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.hideChatSubtitle);
|
|
125
|
+
const unreadMessageCount = ((_props$controlProps21 = props.controlProps) === null || _props$controlProps21 === void 0 ? void 0 : _props$controlProps21.unreadMessageCount) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.unreadMessageCount);
|
|
126
|
+
const ariaLabelUnreadMessageString = ((_props$controlProps22 = props.controlProps) === null || _props$controlProps22 === void 0 ? void 0 : _props$controlProps22.ariaLabelUnreadMessageString) ?? (_defaultChatButtonControlProps.defaultChatButtonControlProps === null || _defaultChatButtonControlProps.defaultChatButtonControlProps === void 0 ? void 0 : _defaultChatButtonControlProps.defaultChatButtonControlProps.ariaLabelUnreadMessageString);
|
|
127
|
+
const canSynthesizeAriaLabel = !hideChatTextContainer && !((_props$componentOverr8 = props.componentOverrides) !== null && _props$componentOverr8 !== void 0 && _props$componentOverr8.textContainer) && !((_props$componentOverr9 = props.componentOverrides) !== null && _props$componentOverr9 !== void 0 && _props$componentOverr9.title) && !((_props$componentOverr0 = props.componentOverrides) !== null && _props$componentOverr0 !== void 0 && _props$componentOverr0.subtitle);
|
|
128
|
+
const synthesizedAriaLabel = canSynthesizeAriaLabel ? [!hideNotificationBubble && hasUnreadMessages(unreadMessageCount) ? `${unreadMessageCount} ${ariaLabelUnreadMessageString ?? ""}`.trim() : "", !hideChatTitle ? titleText : "", !hideChatSubtitle ? subtitleText : ""].filter(Boolean).join(" ").trim() : "";
|
|
129
|
+
const defaultAriaLabel = ((_props$controlProps23 = props.controlProps) === null || _props$controlProps23 === void 0 ? void 0 : _props$controlProps23.ariaLabel) ?? _defaultChatButtonControlProps.defaultChatButtonControlProps.ariaLabel ?? (synthesizedAriaLabel || undefined);
|
|
94
130
|
const chatButtonGroupStyles = {
|
|
95
131
|
root: Object.assign({}, _defaultChatButtonGeneralStyles.defaultChatButtonGeneralStyles, (_props$styleProps1 = props.styleProps) === null || _props$styleProps1 === void 0 ? void 0 : _props$styleProps1.generalStyleProps)
|
|
96
132
|
};
|
|
97
133
|
const handleInitiateChatClick = (0, _react2.useCallback)(() => {
|
|
98
|
-
var _props$
|
|
99
|
-
if ((_props$
|
|
134
|
+
var _props$controlProps24;
|
|
135
|
+
if ((_props$controlProps24 = props.controlProps) !== null && _props$controlProps24 !== void 0 && _props$controlProps24.onClick) {
|
|
100
136
|
const customEvent = {
|
|
101
137
|
elementType: _Constants.ElementType.ChatButton,
|
|
102
138
|
elementId: elementId,
|
|
@@ -9,9 +9,7 @@ var _Constants = require("../../../common/Constants");
|
|
|
9
9
|
var _CommandButton = _interopRequireDefault(require("../commandbutton/CommandButton"));
|
|
10
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
function CloseButton(props) {
|
|
12
|
-
const
|
|
13
|
-
type
|
|
14
|
-
} = props;
|
|
12
|
+
const type = props.type;
|
|
15
13
|
const customEvent = {
|
|
16
14
|
elementType: _Constants.ElementType.CloseButton,
|
|
17
15
|
elementId: props === null || props === void 0 ? void 0 : props.id,
|
|
@@ -23,7 +23,7 @@ var _defaultConfirmationPaneConfirmButtonFocusedStyles = require("./common/defau
|
|
|
23
23
|
var _defaultConfirmationPaneCancelButtonFocusedStyles = require("./common/defaultStyles/defaultConfirmationPaneCancelButtonFocusedStyles");
|
|
24
24
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
25
25
|
function ConfirmationPane(props) {
|
|
26
|
-
var _props$controlProps, _props$styleProps, _props$styleProps2, _props$styleProps3, _props$styleProps4, _props$styleProps5, _props$styleProps6, _props$styleProps7, _props$styleProps8, _props$styleProps9, _props$styleProps0, _props$styleProps1, _props$styleProps10, _props$controlProps6, _props$controlProps7, _props$controlProps8, _props$componentOverr, _props$styleProps11, _props$controlProps9, _props$controlProps0, _props$componentOverr2, _props$styleProps12, _props$controlProps1, _props$styleProps13, _props$controlProps10, _props$
|
|
26
|
+
var _props$controlProps, _props$styleProps, _props$styleProps2, _props$styleProps3, _props$styleProps4, _props$styleProps5, _props$styleProps6, _props$styleProps7, _props$styleProps8, _props$styleProps9, _props$styleProps0, _props$styleProps1, _props$styleProps10, _props$controlProps6, _props$controlProps7, _props$controlProps8, _props$componentOverr, _props$styleProps11, _props$controlProps9, _props$controlProps0, _props$componentOverr2, _props$styleProps12, _props$controlProps1, _props$styleProps13, _props$controlProps10, _props$controlProps11, _props$componentOverr3, _props$styleProps14, _props$controlProps12, _props$controlProps13, _props$controlProps14, _props$componentOverr4, _props$styleProps15, _props$controlProps15, _props$controlProps16;
|
|
27
27
|
const elementId = ((_props$controlProps = props.controlProps) === null || _props$controlProps === void 0 ? void 0 : _props$controlProps.id) ?? _defaultConfirmationPaneControlProps.defaultConfirmationPaneControlProps.id;
|
|
28
28
|
const handleConfirmClick = (0, _react2.useCallback)(() => {
|
|
29
29
|
var _props$controlProps2;
|
|
@@ -105,21 +105,23 @@ function ConfirmationPane(props) {
|
|
|
105
105
|
horizontal: true,
|
|
106
106
|
className: (_props$styleProps13 = props.styleProps) === null || _props$styleProps13 === void 0 || (_props$styleProps13 = _props$styleProps13.classNames) === null || _props$styleProps13 === void 0 ? void 0 : _props$styleProps13.buttonGroupClassName,
|
|
107
107
|
styles: buttonGroupStyles,
|
|
108
|
-
id: elementId + "-buttongroup"
|
|
109
|
-
|
|
108
|
+
id: elementId + "-buttongroup",
|
|
109
|
+
role: "group",
|
|
110
|
+
"aria-label": ((_props$controlProps10 = props.controlProps) === null || _props$controlProps10 === void 0 ? void 0 : _props$controlProps10.buttonGroupAriaLabel) || _defaultConfirmationPaneControlProps.defaultConfirmationPaneControlProps.buttonGroupAriaLabel
|
|
111
|
+
}, !((_props$controlProps11 = props.controlProps) !== null && _props$controlProps11 !== void 0 && _props$controlProps11.hideConfirmButton) && ((0, _decodeComponentString.decodeComponentString)((_props$componentOverr3 = props.componentOverrides) === null || _props$componentOverr3 === void 0 ? void 0 : _props$componentOverr3.confirmButton) || /*#__PURE__*/_react2.default.createElement(_Button.PrimaryButton, {
|
|
110
112
|
className: (_props$styleProps14 = props.styleProps) === null || _props$styleProps14 === void 0 || (_props$styleProps14 = _props$styleProps14.classNames) === null || _props$styleProps14 === void 0 ? void 0 : _props$styleProps14.confirmButtonClassName,
|
|
111
113
|
styles: confirmButtonStyles,
|
|
112
|
-
text: ((_props$
|
|
114
|
+
text: ((_props$controlProps12 = props.controlProps) === null || _props$controlProps12 === void 0 ? void 0 : _props$controlProps12.confirmButtonText) || _defaultConfirmationPaneControlProps.defaultConfirmationPaneControlProps.confirmButtonText,
|
|
113
115
|
onClick: handleConfirmClick,
|
|
114
116
|
id: elementId + "-confirmbutton",
|
|
115
|
-
ariaLabel: ((_props$
|
|
116
|
-
})), !((_props$
|
|
117
|
+
ariaLabel: ((_props$controlProps13 = props.controlProps) === null || _props$controlProps13 === void 0 ? void 0 : _props$controlProps13.confirmButtonAriaLabel) || _defaultConfirmationPaneControlProps.defaultConfirmationPaneControlProps.confirmButtonAriaLabel
|
|
118
|
+
})), !((_props$controlProps14 = props.controlProps) !== null && _props$controlProps14 !== void 0 && _props$controlProps14.hideCancelButton) && ((0, _decodeComponentString.decodeComponentString)((_props$componentOverr4 = props.componentOverrides) === null || _props$componentOverr4 === void 0 ? void 0 : _props$componentOverr4.cancelButton) || /*#__PURE__*/_react2.default.createElement(_Button.DefaultButton, {
|
|
117
119
|
className: (_props$styleProps15 = props.styleProps) === null || _props$styleProps15 === void 0 || (_props$styleProps15 = _props$styleProps15.classNames) === null || _props$styleProps15 === void 0 ? void 0 : _props$styleProps15.cancelButtonClassName,
|
|
118
120
|
styles: cancelButtonStyles,
|
|
119
|
-
text: ((_props$
|
|
121
|
+
text: ((_props$controlProps15 = props.controlProps) === null || _props$controlProps15 === void 0 ? void 0 : _props$controlProps15.cancelButtonText) || _defaultConfirmationPaneControlProps.defaultConfirmationPaneControlProps.cancelButtonText,
|
|
120
122
|
onClick: handleCancelClick,
|
|
121
123
|
id: elementId + "-cancelbutton",
|
|
122
|
-
ariaLabel: ((_props$
|
|
124
|
+
ariaLabel: ((_props$controlProps16 = props.controlProps) === null || _props$controlProps16 === void 0 ? void 0 : _props$controlProps16.cancelButtonAriaLabel) || _defaultConfirmationPaneControlProps.defaultConfirmationPaneControlProps.cancelButtonAriaLabel
|
|
123
125
|
})))));
|
|
124
126
|
}
|
|
125
127
|
var _default = exports.default = ConfirmationPane;
|
|
@@ -13,6 +13,7 @@ const defaultConfirmationPaneControlProps = exports.defaultConfirmationPaneContr
|
|
|
13
13
|
titleText: _Constants.Texts.ConfirmationPaneTitle,
|
|
14
14
|
hideSubtitle: false,
|
|
15
15
|
subtitleText: _Constants.Texts.ConfirmationPaneSubtitle,
|
|
16
|
+
buttonGroupAriaLabel: _Constants.AriaLabels.ConfirmationPaneButtonGroup,
|
|
16
17
|
hideConfirmButton: false,
|
|
17
18
|
confirmButtonText: _Constants.Texts.ConfirmButtonText,
|
|
18
19
|
confirmButtonAriaLabel: _Constants.AriaLabels.ConfirmationPaneConfirm,
|
|
@@ -9,11 +9,18 @@ var _react2 = _interopRequireWildcard(require("react"));
|
|
|
9
9
|
var _BroadcastService = require("../../../services/BroadcastService");
|
|
10
10
|
var _Constants = require("../../../common/Constants");
|
|
11
11
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
12
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
13
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
14
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
15
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
16
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
17
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
12
18
|
function AudioNotificationButton(props) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
const disabled = props.disabled;
|
|
20
|
+
const _useState = (0, _react2.useState)(props.isAudioMuted),
|
|
21
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
22
|
+
muted = _useState2[0],
|
|
23
|
+
setMuted = _useState2[1];
|
|
17
24
|
let iconStyles = {};
|
|
18
25
|
if (props.type === _Constants.ButtonTypes.Icon) {
|
|
19
26
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -9,9 +9,7 @@ var _Constants = require("../../../common/Constants");
|
|
|
9
9
|
var _CommandButton = _interopRequireDefault(require("../../common/commandbutton/CommandButton"));
|
|
10
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
function DownloadTranscriptButton(props) {
|
|
12
|
-
const
|
|
13
|
-
type
|
|
14
|
-
} = props;
|
|
12
|
+
const type = props.type;
|
|
15
13
|
const customEvent = {
|
|
16
14
|
elementType: _Constants.ElementType.FooterDownloadTranscriptButton,
|
|
17
15
|
elementId: props === null || props === void 0 ? void 0 : props.id,
|
|
@@ -9,9 +9,7 @@ var _Constants = require("../../../common/Constants");
|
|
|
9
9
|
var _CommandButton = _interopRequireDefault(require("../../common/commandbutton/CommandButton"));
|
|
10
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
function EmailTranscriptButton(props) {
|
|
12
|
-
const
|
|
13
|
-
type
|
|
14
|
-
} = props;
|
|
12
|
+
const type = props.type;
|
|
15
13
|
const customEvent = {
|
|
16
14
|
elementType: _Constants.ElementType.FooterEmailTranscriptButton,
|
|
17
15
|
elementId: props === null || props === void 0 ? void 0 : props.id,
|