Skip to content

Commit

Permalink
Set default descendant when focusing on transcript and add keyboard f…
Browse files Browse the repository at this point in the history
…ocus indicators (#4035)

* Set default active descendant

* Update to TypeScript

* Add JSDoc

* Update entry

* Fix and clean up on focus activity

* Add capability detection

* Clean up

* Clean up

* Fix test

* Fix tests

* Fix tests

* Fix tests

* Clean up

* Fix tests

* Fix tests

* Fix tests

* Fix test

* Add tests

* Clean up

* Fix typing for `usePerformCardAction` hook (#3969)

* Fix typing for usePerformCardAction

* Update entry

* Fix ESLint

* Fix ESLint

* Clean up

* Clean up

* Add new focus indicator for suggested actions

* Styling send box button with accessibility

* Clean up

* Add snapshots

* Add entries

* Typo

* Fix color

* Fix tests

* Fix tests

* Fix tests

* Fix tests

* Fix tests

* Fix tests

* Fix tests

* Fix tests

* Fix tests

* Fix tests

* Improve test reliability

* Improve test reliability: wait for render

* Fix test reliability

* Improve test reliability

* Improve test reliability

* Fix typings

* Fix focusedActivityKey after merge
  • Loading branch information
compulim authored Sep 22, 2021
1 parent 02985d2 commit 1e8817e
Show file tree
Hide file tree
Showing 139 changed files with 2,861 additions and 561 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Breaking changes

- Style options are introduced to send button for improved accessibility:
- `suggestedActionBackground` and `suggestedActionXXXBackground` are being deprecated in favor of `suggestedActionBackgroundColor` and `suggestedActionBackgroundColorOnXXX` respectively, for consistencies when porting to other platforms
- `suggestedActionDisabledXXX` is being renamed to `suggestedActionXXXOnDisabled`, for consistencies with other style options
- `suggestedActionXXXOnActive`, `suggestedActionXXXOnFocus`, `suggestedActionXXXOnHover` are introduced for styling per user gestures
- `suggestedActionKeyboardFocusIndicatorXXX` are introduced for styling the "focus ring" when [focused using a keyboard](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible)

### Fixed

- Fixes [#4018](https://github.com/microsoft/BotFramework-WebChat/issues/4018). When using <kbd>TAB</kbd> or <kbd>SHIFT</kbd> + <kbd>TAB</kbd> key to focus on the transcript, it should select the last activity, by [@compulim](https://github.com/compulim), in PR [#4035](https://github.com/microsoft/BotFramework-WebChat/pull/4035)
- Fixes [#4020](https://github.com/microsoft/BotFramework-WebChat/issues/4020). With or without scan mode turned on, screen reader users should be able to press <kbd>ENTER</kbd> to focus on interactive activity, by [@compulim](https://github.com/compulim), in PR [#4041](https://github.com/microsoft/BotFramework-WebChat/pull/4041)
- Fixes [#4021](https://github.com/microsoft/BotFramework-WebChat/issues/4021). For screen reader usability, suggested actions container should not render "Is empty" alt text initially, by [@compulim](https://github.com/compulim), in PR [#4041](https://github.com/microsoft/BotFramework-WebChat/pull/4041)
- Fixes [#4029](https://github.com/microsoft/BotFramework-WebChat/issues/4029). Added new keyboard focus indicator for suggested actions, by [@compulim](https://github.com/compulim), in PR [#4035](https://github.com/microsoft/BotFramework-WebChat/pull/4035)
- New style options are introduced: `suggestedActionXXXOnActive`, `suggestedActionXXXOnFocus`, `suggestedActionXXXOnHover`, `suggestedActionKeyboardFocusIndicatorXXX`
- Style options are renamed: `suggestedActionDisabledXXX` become `suggestedActionXXXOnDisabled`
- Fixes [#4028](https://github.com/microsoft/BotFramework-WebChat/issues/4028). Added new keyboard focus indicator for send box buttons, by [@compulim](https://github.com/compulim), in PR [#4035](https://github.com/microsoft/BotFramework-WebChat/pull/4035)
- New style options are introduced: `sendBoxButtonXXXOnActive`, `sendBoxButtonXXXOnFocus`, `sendBoxButtonXXXOnHover`, `sendBoxButtonKeyboardFocusIndicatorXXX`

## [4.14.1] - 2021-09-07

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
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.
11 changes: 11 additions & 0 deletions __tests__/adaptiveCards.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ test('disable card inputs', async () => {

await pageObjects.updateProps({ disabled: false });

// Wait until render after update props
await driver.wait(
() =>
driver.executeScript(() => {
const button = document.querySelector('.ac-actionSet button:nth-of-type(2)');

return button && !button.disabled;
}),
timeouts.ui
);

// Click "Submit" button should send values to the bot
await driver.executeScript(() => {
document.querySelector('.ac-actionSet button:nth-of-type(2)').click();
Expand Down
1 change: 1 addition & 0 deletions __tests__/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ test('long URLs with keep-all', async () => {

const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS });

await driver.wait(uiConnected(), timeouts.directLine);
await pageObjects.sendMessageViaSendBox('箸より重いものを持ったことがない箸より重いものを持ったことがない', {
waitForSend: true
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
await pageConditions.minNumActivitiesShown(2);
await pageConditions.scrollToBottomCompleted();

document.querySelector('select').focus();
document.querySelector('select.ac-input').focus();

await host.sendShiftTab();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link href="/assets/index.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 () {
WebChat.renderWebChat(
{
directLine: WebChat.createDirectLine({ token: await testHelpers.token.fetchDirectLineToken() }),
store: testHelpers.createStore()
},
document.getElementById('webchat')
);

await pageConditions.uiConnected();

// GIVEN: A ready-to-submit Adaptive Card with suggested actions shown below
await pageObjects.sendMessageViaSendBox('card inputs', { waitForSend: true });
await pageConditions.minNumActivitiesShown(2);

await pageObjects.sendMessageViaSendBox('suggested-actions', { waitForSend: true });
await pageConditions.suggestedActionsShown();
await pageConditions.scrollToBottomCompleted();

// To submit the input form, the number field is mandatory.
document.querySelector('.ac-adaptiveCard input[type="number"]').value = '1';

// WHEN: The Adaptive Card is being submitted.
const submitButton = await document.querySelector('button.ac-pushButton:nth-of-type(2)');

await submitButton.click();
await pageConditions.minNumActivitiesShown(5);

// THEN: It should stick to the bottom.
await pageConditions.scrollToBottomCompleted();

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('Auto-scroll with suggested actions shown', () => {
test('should stick to bottom if submitting an Adaptive Card', () =>
runHTML('autoScroll.withSuggestedActions.submitAdaptiveCards.html'));
});
94 changes: 94 additions & 0 deletions __tests__/html/sendBox.button.styleOptions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link href="/assets/index.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 directLine = testHelpers.createDirectLineWithTranscript([]);
const store = testHelpers.createStore();
const useDefault = new URLSearchParams(location.search).get('default');

function render(overrideProps) {
WebChat.renderWebChat(
{
directLine,
store,
...overrideProps,
styleOptions: {
...(useDefault
? {}
: {
sendBoxButtonShadeBorderRadius: 5,
sendBoxButtonShadeInset: 3,

sendBoxButtonKeyboardFocusIndicatorBorderColor: 'rgba(0, 255, 255, 1)',
sendBoxButtonKeyboardFocusIndicatorBorderRadius: '100%',
sendBoxButtonKeyboardFocusIndicatorBorderStyle: 'dashed',
sendBoxButtonKeyboardFocusIndicatorBorderWidth: 2,
sendBoxButtonKeyboardFocusIndicatorInset: 6,

sendBoxButtonColor: 'rgba(255, 0, 0, 1)',
sendBoxButtonShadeColor: 'rgba(255, 0, 0, .4)',

sendBoxButtonColorOnActive: 'rgba(255, 0, 255, 1)',
sendBoxButtonShadeColorOnActive: 'rgba(255, 0, 255, .4)',

sendBoxButtonColorOnDisabled: 'rgba(255, 255, 0, 1)',
sendBoxButtonShadeColorOnDisabled: 'rgba(255, 255, 0, .4)',

sendBoxButtonColorOnFocus: 'rgba(0, 255, 0, 1)',
sendBoxButtonShadeColorOnFocus: 'rgba(0, 255, 0, .4)',

sendBoxButtonColorOnHover: 'rgba(0, 0, 255, 1)',
sendBoxButtonShadeColorOnHover: 'rgba(0, 0, 255, .4)'
}),
...overrideProps?.styleOptions
}
},
document.getElementById('webchat')
);
}

render();

// GIVEN: Web Chat is rendered with no activities and focus is on the send box.
await pageConditions.uiConnected();
await pageObjects.focusSendBoxTextBox();
await host.snapshot();

// WHEN: Web Chat is disabled
render({ disabled: true });
await pageConditions.uiConnected();

// THEN: Send box buttons should be disabled.
await host.snapshot();

// WHEN: Press TAB to focus on the send button.
render();
await pageConditions.uiConnected();
await host.sendTab();

// THEN: A focus-visible border should surround the send button.
await host.snapshot();

// WHEN: Hover mouse on the send button.
await host.hover(pageElements.sendButton());

// THEN: Both focus-visible border and shaded background should appear behind the send button.
await host.snapshot();

// WHEN: Press-and-hold the send button.
await host.pressAndHold(pageElements.sendButton());

// THEN: Both focus-visible border and shaded background should appear.
await host.snapshot();
});
</script>
</body>
</html>
6 changes: 6 additions & 0 deletions __tests__/html/sendBox.button.styleOptions.js
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('send box button', () => {
test('with different style options', () => runHTML('sendBox.button.styleOptions'));
test('with default style options', () => runHTML('sendBox.button.styleOptions?default=true'));
});
44 changes: 36 additions & 8 deletions __tests__/html/suggestedActions.layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
const initialFewerItems = !!params.get('fewer');
const initialPreset = params.get('preset');

const initialDisabled = params.get('disabled') === 'true' || /-disabled$/.test(initialPreset);

const RadioRow = ({ checked, onChange, label, value }) => (
<div className="test-harness__form-row">
<label>
Expand All @@ -69,11 +71,13 @@
flow: { suggestedActionLayout: 'flow' },
'flow-maxheight': { suggestedActionLayout: 'flow', suggestedActionsFlowMaxHeight: 120 },
stacked: { suggestedActionLayout: 'stacked' },
'stacked-disabled': { disabled: true, suggestedActionLayout: 'stacked' },
'stacked-maxheight': { suggestedActionLayout: 'stacked', suggestedActionsStackedHeight: 120 }
};

const TestHarness = () => {
const [direction, setDirection] = useState(() => initialDirection);
const [disabled, setDisabled] = useState(() => initialDisabled || false);
const [fewerItems, setFewerItems] = useState(() => initialFewerItems || false);
const [preset, setPreset] = useState(() => initialPreset || 'carousel');

Expand Down Expand Up @@ -154,14 +158,17 @@
[fewerItems]
);

const handleDisabledChange = useCallback(({ target: { checked } }) => setDisabled(checked), [setDisabled]);

const handleDirectionChange = useCallback(
({ target: { checked } }) => setDirection(checked ? 'rtl' : undefined),
[setDirection]
);

const handleFewerItemsChange = useCallback(({ target: { checked } }) => setFewerItems(checked), [
setFewerItems
]);
const handleFewerItemsChange = useCallback(
({ target: { checked } }) => setFewerItems(checked),
[setFewerItems]
);

const handlePresetChange = useCallback(
({ target: { value } }) => {
Expand All @@ -174,10 +181,11 @@
const hashParams = new URLSearchParams({ preset });

direction === 'rtl' && hashParams.set('dir', 'rtl');
disabled && hashParams.set('disabled', 'true');
fewerItems && hashParams.set('fewer', '1');

window.history.replaceState(undefined, undefined, `#${hashParams}`);
}, [direction, fewerItems, preset]);
}, [direction, disabled, fewerItems, preset]);

return (
<div className="test-harness">
Expand All @@ -196,6 +204,12 @@
value="flow-maxheight"
/>
<RadioRow checked={preset === 'stacked'} onChange={handlePresetChange} label="Stacked" value="stacked" />
<RadioRow
checked={preset === 'stacked-disabled'}
onChange={handlePresetChange}
label="Stacked and disabled"
value="stacked-disabled"
/>
<RadioRow
checked={preset === 'stacked-maxheight'}
onChange={handlePresetChange}
Expand Down Expand Up @@ -225,11 +239,23 @@
Right-to-left
</label>
</div>
<div className="test-harness__form-row">
<label>
<input
checked={disabled}
className="test_harness__input"
onChange={handleDisabledChange}
type="checkbox"
/>
Disabled
</label>
</div>
</form>
<ReactWebChat
className="test-harness__webchat"
directLine={directLine}
dir={direction === 'rtl' ? 'rtl' : undefined}
disabled={disabled}
store={testHelpers.createStore()}
styleOptions={STYLE_OPTIONS_PRESETS[preset]}
/>
Expand Down Expand Up @@ -276,10 +302,12 @@
await host.snapshot();
}

await host.click(document.querySelector('.webchat__suggested-action__button'));

await pageConditions.numActivitiesShown(2);
await host.snapshot();
// Test clicking the button only if they are not disabled.
if (!/-disabled$/iu.test(initialPreset)) {
await pageObjects.clickNthSuggestedAction(1);
await pageConditions.numActivitiesShown(2);
await host.snapshot();
}
});
</script>
</body>
Expand Down
1 change: 1 addition & 0 deletions __tests__/html/suggestedActions.layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('suggested actions', () => {
['flow layout', 'flow'],
['flow layout with maxHeight', 'flow-maxheight'],
['stacked layout', 'stacked'],
['stacked layout and disabled', 'stacked-disabled'],
['stacked layout with height', 'stacked-maxheight']
])('using %s', (_, preset, extraSearchParams) => {
test('should be correct', async () => {
Expand Down
Loading

0 comments on commit 1e8817e

Please sign in to comment.