-
Notifications
You must be signed in to change notification settings - Fork 2
Add del tokens a11y #14
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
base: master
Are you sure you want to change the base?
Changes from all commits
4a07799
2754b71
ffdecf1
58bf71b
ae9229f
939f090
3538d30
37b6452
4b6c625
7137f4d
bdd0bab
0829cc6
7da3203
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # A11y Support | ||
|
|
||
| ## Tested devices | ||
| * Google Chrome + ChromeVox | ||
| * Windows + Firefox + NVDA | ||
| * Windows + Firefox + JAWS | ||
|
|
||
| ## What to expect | ||
|
|
||
| ### Navigation | ||
| Tab and Shift + Tab are supported when navigating between tokens, it can't be | ||
| used to navigate menus. | ||
| Navigation inside the menus is entirely done with the arrow keys. | ||
|
|
||
| ### Speech pattern | ||
| A Token should be spoken in its entirety adding a menu notification when the | ||
| dropdown menu is available (expanded and compressed) | ||
|
|
||
| The input itself should notify when the suggestions dropdown is available. | ||
|
|
||
| Inside the suggestions dropdown there are a number of lists with options. | ||
| The desired behaviour is that when focusing an option it is read out with its | ||
| position in the list and the name of the current list. | ||
|
|
||
| Inside the dropdown menu the behaviour is similar, it should read the name of | ||
| the option with the indication of the checked status of the menu item. The | ||
| status is *true* if it's the currently selected facet, it's *false* otherwhise. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,10 @@ import DropdownMenu from './DropdownMenu'; | |
|
|
||
| import onLeftRight from './onLeftRight'; | ||
|
|
||
| // if react-a11y is not used delete line 11 and 12 | ||
| import a11y from 'react-a11y'; | ||
| import ReactDOM from 'react-dom'; | ||
|
|
||
| import { | ||
| BACKSPACE, | ||
| ENTER, | ||
|
|
@@ -29,10 +33,22 @@ import { | |
| isBackward | ||
| } from './key-utils'; | ||
|
|
||
| // Abilitate accessibility test only in development mode | ||
| // a11y(React, { ReactDOM: ReactDOM }); | ||
|
|
||
| export const DIRECTION_NONE = 'none'; | ||
| export const DIRECTION_BACKWARD = 'backward'; | ||
| export const DIRECTION_FORWARD = 'forward'; | ||
|
|
||
| export const UNIQUE_ID = 'fti_'; | ||
|
|
||
| let tokensLength = 0; | ||
| let tempFacet = ''; | ||
| let tempDescription = ''; | ||
| let supportText = ''; | ||
| let tempToken = []; | ||
|
|
||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are variables that are needed for the a11ySupport method |
||
|
|
||
| const INPUT_STYLE = { | ||
| font: 'inherit', | ||
| lineHeight: 'inherit', | ||
|
|
@@ -45,14 +61,25 @@ const INPUT_STYLE = { | |
|
|
||
| const INPUT_SPY_WRAPPER_STYLE = { | ||
| position: 'absolute', | ||
| visibility: 'hidden', | ||
| top: '0px', | ||
| left: '0px', | ||
| width: '100%', | ||
| height: '0px', | ||
| overflow: 'hidden' | ||
| }; | ||
|
|
||
| const A11Y_HELPER_STYLE = { | ||
| position: 'absolute', | ||
| height: '0px', | ||
| width: '0px', | ||
| margin: '0px', | ||
| padding: '0px', | ||
| overflow: 'hidden', | ||
| top: '0px', | ||
| bottom: '0px', | ||
| fontSize: '0px' | ||
| }; | ||
|
|
||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. adds styles for the helpers. |
||
| const INPUT_SPY_STYLE = { | ||
| display: 'block', | ||
| whiteSpace: 'pre', | ||
|
|
@@ -102,7 +129,9 @@ export default class FacetedTokenInput extends Component { | |
| searchText, | ||
| showDropDown, | ||
| focused, | ||
| textDirection | ||
| textDirection, | ||
| selectedSectionIndex, | ||
| selectedIndex | ||
| } = this.state; | ||
|
|
||
| const facetedTokenInputClass = classNames('compound-input', { | ||
|
|
@@ -119,11 +148,30 @@ export default class FacetedTokenInput extends Component { | |
| onFocus={ event => this.onFocus(event) } | ||
| onBlur={ event => this.onBlur(event) } | ||
| > | ||
|
|
||
| { tokens.map(this.renderToken, this) } | ||
|
|
||
|
|
||
| { /* | ||
| I'm an experiment to delete tokens in mobile | ||
| <a | ||
| style={ { width: '20px', background: 'pink', textAlign: 'center', display: (tokens.length) ? 'inline-block' : 'none' } } | ||
| onClick={ event => this.onBackspace() } | ||
| > | ||
| { 'X' } | ||
| </a> | ||
| */ } | ||
|
|
||
| <input | ||
| key="input" | ||
| ref="input" | ||
| role="combobox" | ||
| aria-expanded={ showDropDown } | ||
| aria-autocomplete="list" | ||
| aria-owns="suggestions_box" | ||
| aria-activedescendant={ UNIQUE_ID + 'section_0' + selectedSectionIndex + '_0' + selectedIndex } | ||
| aria-label="input" | ||
| aria-describedby="number_tokens" | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. aria-describedby="number_tokens"this will read the number of tokens in the input |
||
| style={ INPUT_STYLE } | ||
| className="compound-input-field" | ||
| placeholder={ tokens.length ? '' : placeholder } | ||
|
|
@@ -149,10 +197,105 @@ export default class FacetedTokenInput extends Component { | |
| { this.props.children } | ||
|
|
||
| { showDropDown && this.renderDropdown() } | ||
|
|
||
|
|
||
|
|
||
| { /* start test code */ } | ||
|
|
||
| { /* | ||
| the following div needs to be hidden if this code is going into the | ||
| master branch (see A11Y_HELPER_STYLE) | ||
| style={ A11Y_HELPER_STYLE } | ||
| */ } | ||
| <div | ||
| id="a11ysupport" | ||
| role="log" | ||
| aria-live="polite" | ||
| aria-relevant="all" | ||
| aria-atomic={ true } | ||
| style={ A11Y_HELPER_STYLE } | ||
| > | ||
|
|
||
| { /* | ||
| <span id="tagsupport"> | ||
| simply add all the tokens that exist in the input | ||
|
|
||
| <p></p> | ||
|
|
||
| this adds only the last token, it doesn't solve the current | ||
| problem since the additions count from the second one onwards | ||
|
|
||
| (tokens.length) ? this.a11ySupport(tokens[tokens.length - 1], tokens.length - 1) : '' | ||
|
|
||
| <div aria-live="polite" aria-atomic="true"> | ||
| pierpaolo.ramon aggiunto. Premi backspace per rimuovere il destinatario. | ||
| </div> | ||
|
|
||
|
|
||
| { tokens.map(this.a11ySupport, this) } | ||
| </span> | ||
| */ } | ||
|
|
||
| { this.a11ySupport() } | ||
| </div> | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this container is a live region and should read addition and removals of tokens. |
||
|
|
||
| { /* | ||
| this adds a string that thanks to aria-describedby present in the | ||
| input reads out the number of tokens present in the input in addition | ||
| to the specifics of the input | ||
| */ } | ||
| <div id="number_tokens" style={ A11Y_HELPER_STYLE }> | ||
| { tokens.length } | ||
| { ' tokens in input' } | ||
| </div> | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this regulate the exact phrase that gets read to specify the number of tokens in the input |
||
|
|
||
| { /* end test code */ } | ||
|
|
||
|
|
||
|
|
||
| </div> | ||
| ); | ||
| } | ||
|
|
||
|
|
||
| // start experimental method | ||
|
|
||
| // this should add a node that should be detected by aria-live="true" | ||
| a11ySupport() { | ||
| const { tokens } = this.state; | ||
| const { facet, description } = this.props.renderToken(tokens[tokens.length - 1] || []); | ||
|
|
||
| if (tokens.length === tokensLength + 1) { | ||
| supportText = 'added'; | ||
| tempFacet = facet; | ||
| tempDescription = description; | ||
| tempToken[tokens.length - 1] = { facet, description }; | ||
| } | ||
| else if (tokens.length === tokensLength - 1) { | ||
| supportText = 'deleted'; | ||
| tempFacet = tempToken[tokens.length].facet; | ||
| tempDescription = tempToken[tokens.length].description; | ||
| } | ||
|
|
||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if a token is added I need the support text to be 'added' and I need to store the token in a temporary array. |
||
| tokensLength = tokens.length; | ||
|
|
||
| return ( | ||
| <span | ||
| key={ 'test' + tokensLength } | ||
| > | ||
| { tempFacet } | ||
| { ' ' } | ||
| { tempDescription } | ||
| { ' ' } | ||
| { supportText } | ||
| </span> | ||
| ); | ||
| } | ||
|
|
||
| // end experimental method | ||
|
|
||
|
|
||
| renderDropdown() { | ||
| const { dropdownSections } = this.props; | ||
|
|
||
|
|
@@ -223,7 +366,9 @@ export default class FacetedTokenInput extends Component { | |
| if (noSelection || this.isInTokenSelection(tokens.length)) { | ||
| this.refs.input.focus(); | ||
| } | ||
| else if (tokenSelectionDirection === DIRECTION_NONE) { | ||
| else if (tokenSelectionDirection === DIRECTION_NONE && | ||
| this.refs['token' + tokenSelectionStart]) { | ||
|
|
||
| this.refs['token' + tokenSelectionStart].focus(); | ||
| } | ||
| else { | ||
|
|
@@ -272,9 +417,19 @@ export default class FacetedTokenInput extends Component { | |
|
|
||
| const searchText = this.refs.input.value; | ||
|
|
||
| if (searchText) { | ||
| this.setState({ | ||
| showDropDown: true | ||
| }); | ||
| } | ||
| else { | ||
| this.setState({ | ||
| showDropDown: false | ||
| }); | ||
| } | ||
|
|
||
| this.setState({ | ||
| searchText: searchText, | ||
| showDropDown: true, | ||
| selectedSectionIndex: -1, | ||
| selectedIndex: -1 | ||
| }); | ||
|
|
@@ -425,7 +580,8 @@ export default class FacetedTokenInput extends Component { | |
| tokenSelectionStart | ||
| } = this.state; | ||
|
|
||
| const keyDirection = isForward(event, dir || textDirection) ? DIRECTION_FORWARD | ||
| const keyDirection = isForward(event, dir || textDirection) | ||
| ? DIRECTION_FORWARD | ||
| : isBackward(event, dir || textDirection) ? DIRECTION_BACKWARD | ||
| : DIRECTION_NONE; | ||
|
|
||
|
|
@@ -521,7 +677,9 @@ export default class FacetedTokenInput extends Component { | |
| }); | ||
| } | ||
|
|
||
| if (event.target !== this.refs.input) { | ||
| if (event.target !== this.refs.input || | ||
| (event.target === this.refs.input && !searchText)) { | ||
|
|
||
| event.preventDefault(); | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is some documentation for the accessibility support