Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converge suggested actions into live region twin and add roving tab index #4314

Merged
merged 17 commits into from
Jun 16, 2022
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,26 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Breaking changes

- Suggested actions is now a [`role="toolbar"`](https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/) and adopted roving tab index
- <kbd>TAB</kbd> key will now land on the container, instead of individual button
- While the focus is on the container, <kbd>LEFT</kbd>/<kbd>RIGHT</kbd> arrow keys are used to select different buttons (<kbd>UP</kbd>/<kbd>DOWN</kbd> for stacked layout)
- Visual focus indicator is now two tiered. The default styling is same as the one we use in chat history
- New style options added `suggestedActionsVisualKeyboardIndicatorColor`, `suggestedActionsVisualKeyboardIndicatorStyle`, `suggestedActionsVisualKeyboardIndicatorWidth`
- Suggested actions container will be unmounted when there are no suggested action button to display
- Suggested actions container is not longer a live region. The suggested action buttons will now be narrated by the chat history live region

### Changed

- Resolves [#4301](https://github.com/microsoft/BotFramework-WebChat/issues/4301). Updated `Dockerfile` to support secure container supply chain, by [@compulim](https://github.com/compulim) in PR [#4303](https://github.com/microsoft/BotFramework-WebChat/pull/4303)

### Fixed

- Fixes [#4293](https://github.com/microsoft/BotFramework-WebChat/issues/4293) and [#4296](https://github.com/microsoft/BotFramework-WebChat/issues/4296). Fixed accessibility issues for suggested actions, by [@compulim](https://github.com/compulim), in PR [#4314](https://github.com/microsoft/BotFramework-WebChat/pull/4314)
- Centralized live region of suggested actions into chat history live region for better live region control
- Suggested actions container is now a `role="toolbar"` and uses roving tab index for multiple suggested action

## [4.15.2] - 2022-05-09

### Breaking changes
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions __tests__/adaptiveCards.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,12 @@ test('unknown card', async () => {

const browserConsoleErrors = await driver.manage().logs().get(logging.Type.BROWSER);

expect(browserConsoleErrors[0].level.name_).toEqual('WARNING');
expect(browserConsoleErrors[0].message).toContain('No renderer for attachment for screen reader of type');
expect(
compulim marked this conversation as resolved.
Show resolved Hide resolved
browserConsoleErrors.find(
({ level: { name_ }, message }) =>
name_ === 'WARNING' && ~message.indexOf('No renderer for attachment for screen reader of type')
)
).toBeTruthy();
});

test('Inputs card with custom style options and submit action', async () => {
Expand Down
3 changes: 3 additions & 0 deletions __tests__/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ test('thumbnail card with a long title and richCardWrapTitle set to default valu
test('absolute timestamp', async () => {
const activities = [
{
channelData: {},
compulim marked this conversation as resolved.
Show resolved Hide resolved
type: 'message',
id: '6266x5ZXhXkBfuIH0fNx0h-o|0000000',
timestamp: '2019-08-08T16:41:12.9397263Z',
Expand All @@ -148,6 +149,7 @@ test('absolute timestamp', async () => {
text: 'echo "Hello, World!"'
},
{
channelData: {},
type: 'message',
id: '6266x5ZXhXkBfuIH0fNx0h-o|0000001',
timestamp: '2019-08-08T16:41:13.1835518Z',
Expand All @@ -159,6 +161,7 @@ test('absolute timestamp', async () => {
text: 'Echoing back in a separate activity.'
},
{
channelData: {},
type: 'message',
id: '6266x5ZXhXkBfuIH0fNx0h-o|0000002',
timestamp: '2019-08-08T16:41:13.3963019Z',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@
text: index + 1 + ''
}));

// We want to lockdown on the number of renderMarkdown() calls for <ScreenReaderActivity>.
// We want to lockdown on the number of renderMarkdown() calls for <LiveRegionActivity>.
// It should not increase significantly over time.

let numRenderMarkdownWithScreenReaderActivity = 0;
let numRenderMarkdownWithoutScreenReaderActivity = 0;
let numRenderMarkdownWithLiveRegionActivity = 0;
let numRenderMarkdownWithoutLiveRegionActivity = 0;

WebChat.renderWebChat(
{
directLine: testHelpers.createDirectLineWithTranscript(transcript),
renderMarkdown: markdown => {
numRenderMarkdownWithScreenReaderActivity++;
numRenderMarkdownWithLiveRegionActivity++;

return markdown;
},
Expand All @@ -60,11 +60,11 @@
WebChat.renderWebChat(
{
directLine: testHelpers.createDirectLineWithTranscript(
// If "channelData['webchat:fallback-text']" field is set to empty string, it will disable <ScreenReaderActivity>.
// If "channelData['webchat:fallback-text']" field is set to empty string, it will disable <LiveRegionActivity>.
transcript.map(activity => ({ ...activity, channelData: { 'webchat:fallback-text': '' } }))
),
renderMarkdown: markdown => {
numRenderMarkdownWithoutScreenReaderActivity++;
numRenderMarkdownWithoutLiveRegionActivity++;

return markdown;
},
Expand All @@ -78,10 +78,10 @@

// Number of renderMarkdown() call with or without screen reader activity should be 20.

// Number of <ScreenReaderActivity> rendered x number of activities = number of renderMarkdown
// Number of <LiveRegionActivity> rendered x number of activities = number of renderMarkdown
// 2 x 10 activities = 20 render loop

const numDiffRender = numRenderMarkdownWithScreenReaderActivity - numRenderMarkdownWithoutScreenReaderActivity;
const numDiffRender = numRenderMarkdownWithLiveRegionActivity - numRenderMarkdownWithoutLiveRegionActivity;

expect(numDiffRender).toBe(20);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<link href="/assets/accessibility.liveRegionAttachment.css" rel="stylesheet" type="text/css" />
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
</head>
<body>
<div id="webchat"></div>
<script>
run(async function () {
const baseActivity = {
from: {
id: 'bot',
role: 'bot'
},
textFormat: 'markdown',
timestamp: new Date(2000, 0, 1, 12, 34, 56, 789).toISOString(),
type: 'message'
};

WebChat.renderWebChat(
{
directLine: testHelpers.createDirectLineWithTranscript([
{
...baseActivity,
suggestedActions: {
actions: [
{
title: 'USA',
type: 'imBack'
},
{
title: 'Hong Kong',
type: 'imBack'
}
]
},
text: 'Where are you from?'
}
]),
store: testHelpers.createStore(),
styleOptions: {
internalLiveRegionFadeAfter: 60000
}
},
document.getElementById('webchat')
);

await pageConditions.uiConnected();
await pageConditions.numActivitiesShown(1);
await pageConditions.liveRegionStabilized();

const screenReaderTexts = [].map.call(pageElements.transcriptLiveRegion().children, child =>
testHelpers.getAllTextContents(child).join('\n')
);

expect(screenReaderTexts).toHaveLength(2);

expect(screenReaderTexts[0]).toBe(
'Bot said:\nWhere are you from?\nUSA\nHong Kong\nSent at January 1 at 12:34 PM'
);
expect(screenReaderTexts[1]).toBe('Suggested Actions Container: Has content. Press Alt + Shift + A to select.');

// The screenshot should show the suggested actions as HTML <button> and verify we sent a <button> to screen reader.
await host.snapshot();
});
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @jest-environment ./packages/test/harness/src/host/jest/WebDriverEnvironment.js */

describe('accessibility requirement', () => {
describe('suggested actions in live region', () =>
test('with message', () => runHTML('accessibility.liveRegionSuggestedActions.withMessage.html')));
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<link href="/assets/accessibility.liveRegionAttachment.css" rel="stylesheet" type="text/css" />
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
</head>
<body>
<div id="webchat"></div>
<script>
run(async function () {
const baseActivity = {
from: {
id: 'bot',
role: 'bot'
},
textFormat: 'markdown',
timestamp: new Date(2000, 0, 1, 12, 34, 56, 789).toISOString(),
type: 'message'
};

WebChat.renderWebChat(
{
directLine: testHelpers.createDirectLineWithTranscript([
{
...baseActivity,
suggestedActions: {
actions: [
{
title: 'What can I say?',
type: 'imBack'
},
{
title: 'What is the weather?',
type: 'imBack'
}
]
}
}
]),
store: testHelpers.createStore(),
styleOptions: {
internalLiveRegionFadeAfter: 60000
}
},
document.getElementById('webchat')
);

await pageConditions.uiConnected();
await pageConditions.liveRegionStabilized();

const screenReaderTexts = [].map.call(pageElements.transcriptLiveRegion().children, child =>
testHelpers.getAllTextContents(child).join('\n')
);

expect(screenReaderTexts).toHaveLength(2);

expect(screenReaderTexts[0]).toBe(
'Bot said:\nWhat can I say?\nWhat is the weather?\nSent at January 1 at 12:34 PM'
);
expect(screenReaderTexts[1]).toBe('Suggested Actions Container: Has content. Press Alt + Shift + A to select.');

// The screenshot should show the suggested actions as HTML <button> and verify we sent a <button> to screen reader.
await host.snapshot();
});
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @jest-environment ./packages/test/harness/src/host/jest/WebDriverEnvironment.js */

describe('accessibility requirement', () => {
describe('suggested actions in live region', () =>
test('without message', () => runHTML('accessibility.liveRegionSuggestedActions.withoutMessage.html')));
});

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
.webchat__screen-reader-activity, .webchat__live-region-transcript__interactive-note, .webchat__live-region-transcript__text-element {
.webchat__live-region-activity,
.webchat__live-region-transcript__interactive-note,
.webchat__live-region-transcript__suggested-actions-note,
.webchat__live-region-transcript__text-element {
color: initial !important;
height: initial !important;
opacity: initial !important;
Expand All @@ -9,6 +12,6 @@
width: initial !important;
}

.webchat__screen-reader-activity .webchat__screen-reader-activity__timestamp {
.webchat__live-region-activity .webchat__live-region-activity__timestamp {
display: none;
}
Loading