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

feat(legend): add keyboard navigation #880

Merged
merged 56 commits into from
Dec 9, 2020

Conversation

rshen91
Copy link
Contributor

@rshen91 rshen91 commented Oct 27, 2020

Summary

Closes #613
This PR adds keyboard navigation to the legend. Screen reader tested using VoiceOver on local mac to read the label and extra if relevant.
Nov-06-2020 12-23-47

Checklist

Delete any items that are not applicable to this PR.

  • Unit tests were updated or added to match the most common scenarios

@rshen91 rshen91 added :legend Legend related issue :accessibility Accessibility related issue labels Oct 27, 2020
@rshen91 rshen91 self-assigned this Oct 27, 2020
@codecov-io
Copy link

codecov-io commented Nov 3, 2020

Codecov Report

Merging #880 (547f69d) into master (bda63f6) will increase coverage by 0.52%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #880      +/-   ##
==========================================
+ Coverage   70.14%   70.66%   +0.52%     
==========================================
  Files         343      359      +16     
  Lines       11035    11341     +306     
  Branches     2392     2436      +44     
==========================================
+ Hits         7740     8014     +274     
- Misses       3281     3307      +26     
- Partials       14       20       +6     
Flag Coverage Δ
unittests 70.13% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/components/legend/color.tsx 100.00% <100.00%> (ø)
src/components/legend/label.tsx 100.00% <100.00%> (ø)
src/components/legend/legend_item.tsx 92.40% <100.00%> (ø)
src/mocks/series/series.ts 90.00% <0.00%> (ø)
src/mocks/store/store.ts 92.59% <0.00%> (ø)
src/mocks/series/utils.ts 100.00% <0.00%> (ø)
src/mocks/series/series_identifiers.ts 100.00% <0.00%> (ø)
src/mocks/specs/specs.ts 82.95% <0.00%> (ø)
src/mocks/specs/index.ts 100.00% <0.00%> (ø)
src/mocks/annotations/annotations.ts 73.33% <0.00%> (ø)
... and 9 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bda63f6...547f69d. Read the comment docs.

@rshen91 rshen91 marked this pull request as ready for review November 6, 2020 22:26
@rshen91
Copy link
Contributor Author

rshen91 commented Nov 6, 2020

There are vrts failing for small pixel amounts is it ok to update the stories @markov00 @nickofthyme ?

@rshen91 rshen91 requested a review from myasonik November 9, 2020 18:15
@nickofthyme
Copy link
Collaborator

@rshen91 Sorry, yes. I would say it's always appropriate to update the vrt screenshots, then on the PR we can just review what changed in screenshot. Sometimes minor changes somehow create small pixel differences.

Copy link
Member

@markov00 markov00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Rachel, with just few changes to the code it looks great!
I'd like to note a few issues:

  1. the focus style doesn't looks like the focus style used in EUI. Here I'd like to ask @miukimiu her opinion about that and if we need background + border in the same style as EUI
  2. I've noticed an issue with the keyboard: if you enable the color picker with the keyboard we are not passing the focus to the color picker element. Moreover, as shown on the gif, tabbing to the legend item label with the color picker open and clicking on that label cause a crash on the chart
    Nov-11-2020 14-46-13
  3. Can you prepare a story that "pass" the focus to the color picker? I'm not sure if this is something that happens automatically or we should implement that through our code
  4. if possible instead of updating all these screenshot, it could be better to fix the difference in the padding of the updated DOM structure
  5. @myasonik I'd like your opinion on the area-labels and the role applied to the legend.

src/chart_types/xy_chart/renderer/canvas/xy_chart.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/extra.tsx Outdated Show resolved Hide resolved
src/components/legend/label.tsx Outdated Show resolved Hide resolved
src/components/legend/legend.tsx Outdated Show resolved Hide resolved
stories/legend/11_legend_actions.tsx Show resolved Hide resolved
Copy link
Collaborator

@nickofthyme nickofthyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, just a few comments on top of @myasonik's

src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
src/components/legend/color.tsx Outdated Show resolved Hide resolved
stories/legend/11_legend_actions.tsx Show resolved Hide resolved
Comment on lines 350 to 369
await page.evaluateOnNewDocument(() => {
const style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
*,
*::after,
*::before,
.echLegendItem {
transition-delay: 0s !important;
transition-duration: 0s !important;
animation-delay: -0.0001s !important;
animation-duration: 0s !important;
animation-play-state: paused !important;
caret-color: transparent !important;
};`;
const storyRoot = document.getElementById('#story-root');
if (storyRoot) {
storyRoot.appendChild(style);
}
});
Copy link
Collaborator

@nickofthyme nickofthyme Dec 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than adding all the css here you could just add a class to the #story-root element. No need to fuss with creating a style tag and appending it to the dom.

const storyRoot = document.getElementById('story-root');
if (storyRoot) {
  storyRoot.classList.add('disable-animations')
}

Sidenote: getElementById implies the type of selector so using # won't work

Comment on lines 29 to 39
// *,
// *::after,
// *::before,
// .echLegendItem {
// transition-delay: 0s !important;
// transition-duration: 0s !important;
// animation-delay: -0.0001s !important;
// animation-duration: 0s !important;
// animation-play-state: paused !important;
// caret-color: transparent !important;
// }
Copy link
Collaborator

@nickofthyme nickofthyme Dec 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By adding the class you can then do...

#story-root {
  &.disable-animations {
    *,
    *::after,
    *::before{
      transition-delay: 0s !important;
      transition-duration: 0s !important;
      animation-delay: -0.0001s !important;
      animation-duration: 0s !important;
      animation-play-state: paused !important;
      caret-color: transparent !important;
    }
  }
}

@rshen91
Copy link
Contributor Author

rshen91 commented Dec 4, 2020

jenkins test this please

@rshen91
Copy link
Contributor Author

rshen91 commented Dec 4, 2020

@nickofthyme and @markov00 in 3631426 I added a workaround for the vrts that were failing in legend_stories and area_stories with disableAnimations(). Can you let me know your thoughts?

@@ -460,6 +440,13 @@ class CommonPage {
});
}

async disableAnimations(url: string) {
await this.loadElementFromURL(url, '#story-root');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good thought. It must replace the #story-root after each navigation.

But as long as you use this in the action function you don't need to call loadElementFromURL.

Suggested change
await this.loadElementFromURL(url, '#story-root');

Comment on lines 80 to 82
await common.disableAnimations(
'http://localhost:9001/?path=/story/area-chart--with-negative-and-positive&knob-Y scale=log',
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to repeat the URL navigation again. The disableAnimations method can just be used as a helper functions in the action.

Suggested change
await common.disableAnimations(
'http://localhost:9001/?path=/story/area-chart--with-negative-and-positive&knob-Y scale=log',
);
await common.disableAnimations();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Good point - please see 5bdb611

Comment on lines 93 to 95
await common.disableAnimations(
'http://localhost:9001/?path=/story/area-chart--with-negative-and-positive&knob-Y scale=log',
);
Copy link
Collaborator

@nickofthyme nickofthyme Dec 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above. Lmk if this doesn't work.

Suggested change
await common.disableAnimations(
'http://localhost:9001/?path=/story/area-chart--with-negative-and-positive&knob-Y scale=log',
);
await common.disableAnimations();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works! Thank you! Please see 5bdb611

Comment on lines 96 to 98
beforeEach(async () => {
await common.disableAnimations('http://localhost:9001/?path=/story/legend--right');
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call - totally not needed - removed in 5bdb611

@rshen91 rshen91 requested a review from nickofthyme December 6, 2020 19:46
Copy link
Member

@markov00 markov00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, tested locally and works perfectly.

@@ -383,6 +440,13 @@ class CommonPage {
});
}

async disableAnimations() {
// await this.loadElementFromURL(url, '#story-root');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed in 55f1628 thanks!

it('shows only positive values when hiding negative one', async () => {
const action = async () => {
await common.disableAnimations();
// 'http://localhost:9001/?path=/story/area-chart--with-negative-and-positive&knob-Y scale=log',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove these commented URLs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed in 55f1628 thanks!

Copy link
Collaborator

@nickofthyme nickofthyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The final result is SUPER clean and smooth, way to go!

I have a few nits about the vrt helper methods. Also, I wonder if we could move the mouse before the tab to show the focus state only and not the focused and hover state.

image

@@ -0,0 +1,76 @@
@import '../node_modules/@elastic/eui/src/theme_light.scss';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like you are using this file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed in a5acd93

@@ -121,7 +131,7 @@ type ScreenshotElementAtUrlOptions = ScreenshotDOMElementOptions & {
/**
* any desired action to be performed after loading url, prior to screenshot
*/
action?: () => void | Promise<void>;
action?: () => void | Promise<void> | Iterable<unknown>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for?

Comment on lines 20 to 21
// eslint-disable-next-line eslint-comments/disable-enable-pair
/* eslint-disable no-await-in-loop */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you just disable the line not the whole file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep this makes sense - made changes in 02a06fe

if (actionLabel === 'tab') {
let i = 0;
while (i < count) {
await page.keyboard.press('Tab');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await page.keyboard.press('Tab');
// eslint-disable-next-line no-await-in-loop
await page.keyboard.press('Tab');

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed in a5acd93

} else if (actionLabel === 'enter') {
let i = 0;
while (i < count) {
await page.keyboard.press('Enter');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await page.keyboard.press('Enter');
// eslint-disable-next-line no-await-in-loop
await page.keyboard.press('Enter');

) {
const action = async () => {
await this.disableAnimations();
await this.clickMouseRelativeToDOMElement({ top: 242, left: 910 }, this.chartSelector);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a generic method, why are there specific top and left values? Is the purpose of this to just click the element to the tap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! Just to make sure that storybook tabbing doesn't go down all the individual stories in the pane before reaching the iframe

@rshen91 rshen91 merged commit 87c227d into elastic:master Dec 9, 2020
@rshen91 rshen91 deleted the legend-keyboard branch December 9, 2020 19:55
github-actions bot pushed a commit that referenced this pull request Jan 30, 2021
# [24.5.0](v24.4.0...v24.5.0) (2021-01-30)

### Bug Fixes

* add theme min radius to point shape ([#996](#996)) ([eb37175](eb37175))
* align tooltip z-index to EUI tooltip z-index ([#931](#931)) ([ffd626b](ffd626b))
* chart state and series functions cleanup ([#989](#989)) ([944ac6c](944ac6c))
* create unique ids for dot icons ([#971](#971)) ([e1ce768](e1ce768))
* external tooltip legend extra value sync ([#993](#993)) ([13ad05a](13ad05a))
* **legend:** disable focus and keyboard navigation for legend in partition ch… ([#952](#952)) ([03bd2f7](03bd2f7))
* **legend:** hierarchical legend order should follow the tree paths ([#947](#947)) ([f9218ad](f9218ad)), closes [#944](#944)
* **legend:** remove ids for circles ([#973](#973)) ([b3f4f90](b3f4f90))

### Features

* **cursor:** improve theme styling for crosshair ([#980](#980)) ([6c4dafd](6c4dafd))
* **legend:**  display pie chart legend extra ([#939](#939)) ([d14de01](d14de01))
* **legend:** add keyboard navigation ([#880](#880)) ([87c227d](87c227d))
* **partition:** Flame and icicle chart ([#965](#965)) ([3df73d0](3df73d0))
* **partition:** legend hover options ([#978](#978)) ([f810d94](f810d94))
* **xy:** support multiple point shapes on line, area and bubble charts ([#988](#988)) ([1392b7d](1392b7d))
@markov00
Copy link
Member

🎉 This PR is included in version 24.5.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@markov00 markov00 added the released Issue released publicly label Jan 30, 2021
AMoo-Miki pushed a commit to AMoo-Miki/OpenSearch-Dashboards that referenced this pull request Feb 10, 2022
# [24.5.0](elastic/elastic-charts@v24.4.0...v24.5.0) (2021-01-30)

### Bug Fixes

* add theme min radius to point shape ([opensearch-project#996](elastic/elastic-charts#996)) ([98089a9](elastic/elastic-charts@98089a9))
* align tooltip z-index to EUI tooltip z-index ([opensearch-project#931](elastic/elastic-charts#931)) ([f7f1f6f](elastic/elastic-charts@f7f1f6f))
* chart state and series functions cleanup ([opensearch-project#989](elastic/elastic-charts#989)) ([42a7af0](elastic/elastic-charts@42a7af0))
* create unique ids for dot icons ([opensearch-project#971](elastic/elastic-charts#971)) ([0b3e00f](elastic/elastic-charts@0b3e00f))
* external tooltip legend extra value sync ([opensearch-project#993](elastic/elastic-charts#993)) ([7e1096e](elastic/elastic-charts@7e1096e))
* **legend:** disable focus and keyboard navigation for legend in partition ch… ([opensearch-project#952](elastic/elastic-charts#952)) ([dfff3e2](elastic/elastic-charts@dfff3e2))
* **legend:** hierarchical legend order should follow the tree paths ([opensearch-project#947](elastic/elastic-charts#947)) ([7b70186](elastic/elastic-charts@7b70186)), closes [opensearch-project#944](elastic/elastic-charts#944)
* **legend:** remove ids for circles ([opensearch-project#973](elastic/elastic-charts#973)) ([ed98481](elastic/elastic-charts@ed98481))

### Features

* **cursor:** improve theme styling for crosshair ([opensearch-project#980](elastic/elastic-charts#980)) ([0248ad6](elastic/elastic-charts@0248ad6))
* **legend:**  display pie chart legend extra ([opensearch-project#939](elastic/elastic-charts#939)) ([672a4df](elastic/elastic-charts@672a4df))
* **legend:** add keyboard navigation ([opensearch-project#880](elastic/elastic-charts#880)) ([b471a94](elastic/elastic-charts@b471a94))
* **partition:** Flame and icicle chart ([opensearch-project#965](elastic/elastic-charts#965)) ([9e8b1f7](elastic/elastic-charts@9e8b1f7))
* **partition:** legend hover options ([opensearch-project#978](elastic/elastic-charts#978)) ([acd1339](elastic/elastic-charts@acd1339))
* **xy:** support multiple point shapes on line, area and bubble charts ([opensearch-project#988](elastic/elastic-charts#988)) ([4f23b4f](elastic/elastic-charts@4f23b4f))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:accessibility Accessibility related issue :legend Legend related issue released Issue released publicly
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Keyboard navigation for legend (beta)
6 participants