A11y improvements (#755)

* improve screen reading for menu values

* clean up Drop down component

* typo
main
Michael Fix 6 years ago committed by GitHub
parent 4e1b6259e6
commit 94b30c3c36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -33,6 +33,7 @@ class BackgroundSelect extends React.PureComponent {
return ( return (
<div className="bg-select-container"> <div className="bg-select-container">
<Button <Button
title="Background Menu"
border border
center center
selected={isVisible} selected={isVisible}

@ -1,4 +1,5 @@
import React from 'react' import React from 'react'
import VisuallyHidden from '@reach/visually-hidden'
import { COLORS } from '../lib/constants' import { COLORS } from '../lib/constants'
@ -19,9 +20,11 @@ const Button = ({
style = {}, style = {},
flex = 1, flex = 1,
padding = 0, padding = 0,
margin = 0 margin = 0,
title
}) => ( }) => (
<button id={id} onClick={onClick} className={className} disabled={disabled} style={style}> <button id={id} onClick={onClick} className={className} disabled={disabled} style={style}>
{title && <VisuallyHidden>{title}</VisuallyHidden>}
{children} {children}
<style jsx> <style jsx>
{` {`

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import Downshift from 'downshift' import Downshift from 'downshift'
import matchSorter from 'match-sorter' import matchSorter from 'match-sorter'
import VisuallyHidden from '@reach/visually-hidden'
import { Down as ArrowDown } from './svg/Arrows' import { Down as ArrowDown } from './svg/Arrows'
import CheckMark from './svg/Checkmark' import CheckMark from './svg/Checkmark'
import { COLORS } from '../lib/constants' import { COLORS } from '../lib/constants'
@ -56,11 +57,63 @@ class Dropdown extends React.PureComponent {
userInputtedValue = '' userInputtedValue = ''
renderDropdown = ({
isOpen,
highlightedIndex,
selectedItem,
getRootProps,
getToggleButtonProps,
getInputProps,
getItemProps
}) => {
const { list, color, itemWrapper, icon, disableInput, title } = this.props
const { itemsToShow } = this.state
const minWidth = calcMinWidth(itemsToShow)
const labelId = title ? `${title.toLowerCase()}-dropdown` : undefined
return (
<DropdownContainer {...getRootProps({ refKey: 'innerRef' })} minWidth={minWidth}>
{title && <VisuallyHidden id={labelId}>{title}</VisuallyHidden>}
<DropdownIcon isOpen={isOpen}>{icon}</DropdownIcon>
<SelectedItem
getToggleButtonProps={getToggleButtonProps}
getInputProps={getInputProps}
isOpen={isOpen}
color={color}
hasIcon={!!icon}
disabled={disableInput}
>
{selectedItem.name}
</SelectedItem>
{isOpen ? (
<List color={color}>
{list.map((item, index) => (
<ListItem
key={index}
color={color}
item={item}
itemWrapper={itemWrapper}
{...getItemProps({
item,
isSelected: selectedItem.name === item.name,
isHighlighted: highlightedIndex === index
})}
>
{item.name}
</ListItem>
))}
</List>
) : null}
</DropdownContainer>
)
}
render() { render() {
const { innerRef, color, selected, onChange, itemWrapper, icon, disableInput } = this.props const { innerRef, selected, onChange, title } = this.props
const { itemsToShow, inputValue } = this.state const { itemsToShow, inputValue } = this.state
const minWidth = calcMinWidth(itemsToShow) const labelId = title ? `${title.toLowerCase()}-dropdown` : undefined
return ( return (
<Downshift <Downshift
@ -71,66 +124,14 @@ class Dropdown extends React.PureComponent {
itemToString={item => item.name} itemToString={item => item.name}
onChange={onChange} onChange={onChange}
onUserAction={this.onUserAction} onUserAction={this.onUserAction}
labelId={labelId}
> >
{renderDropdown({ {this.renderDropdown}
color,
list: itemsToShow,
selected,
minWidth,
itemWrapper,
icon,
disableInput
})}
</Downshift> </Downshift>
) )
} }
} }
const renderDropdown = ({ color, list, minWidth, itemWrapper, icon, disableInput }) => ({
isOpen,
highlightedIndex,
selectedItem,
getRootProps,
getToggleButtonProps,
getInputProps,
getItemProps
}) => {
return (
<DropdownContainer {...getRootProps({ refKey: 'innerRef' })} minWidth={minWidth}>
<DropdownIcon isOpen={isOpen}>{icon}</DropdownIcon>
<SelectedItem
getToggleButtonProps={getToggleButtonProps}
getInputProps={getInputProps}
isOpen={isOpen}
color={color}
hasIcon={!!icon}
disabled={disableInput}
>
{selectedItem.name}
</SelectedItem>
{isOpen ? (
<ListItems color={color}>
{list.map((item, index) => (
<ListItem
key={index}
color={color}
item={item}
itemWrapper={itemWrapper}
{...getItemProps({
item,
isSelected: selectedItem.name === item.name,
isHighlighted: highlightedIndex === index
})}
>
{item.name}
</ListItem>
))}
</ListItems>
) : null}
</DropdownContainer>
)
}
const DropdownContainer = ({ children, innerRef, minWidth, ...rest }) => { const DropdownContainer = ({ children, innerRef, minWidth, ...rest }) => {
return ( return (
<div {...rest} ref={innerRef} className="dropdown-container"> <div {...rest} ref={innerRef} className="dropdown-container">
@ -173,9 +174,9 @@ const DropdownIcon = ({ children, isOpen }) => {
</style> </style>
</div> </div>
) )
} else {
return null
} }
return null
} }
const SelectedItem = ({ const SelectedItem = ({
@ -245,7 +246,7 @@ const SelectedItem = ({
) )
} }
const ListItems = ({ children, color }) => { const List = ({ children, color }) => {
return ( return (
<ul role="listbox" className="dropdown-list"> <ul role="listbox" className="dropdown-list">
{children} {children}

@ -332,6 +332,7 @@ class Editor extends React.Component {
themes={this.props.themes} themes={this.props.themes}
/> />
<Dropdown <Dropdown
title="Language"
icon={languageIcon} icon={languageIcon}
selected={ selected={
LANGUAGE_NAME_HASH[language] || LANGUAGE_NAME_HASH[language] ||

@ -354,6 +354,7 @@ class Settings extends React.PureComponent {
return ( return (
<div className="settings-container" ref={this.settingsRef}> <div className="settings-container" ref={this.settingsRef}>
<Button <Button
title="Settings Menu"
border border
center center
selected={isVisible} selected={isVisible}

@ -103,6 +103,7 @@ class Themes extends React.PureComponent {
return ( return (
<div className="themes"> <div className="themes">
<Dropdown <Dropdown
title="Theme"
innerRef={this.dropdown} innerRef={this.dropdown}
icon={themeIcon} icon={themeIcon}
disableInput={isVisible} disableInput={isVisible}

@ -21,6 +21,7 @@
}, },
"dependencies": { "dependencies": {
"@dawnlabs/tacklebox": "^0.0.10", "@dawnlabs/tacklebox": "^0.0.10",
"@reach/visually-hidden": "^0.1.4",
"axios": "^0.18.0", "axios": "^0.18.0",
"codemirror": "^5.42.2", "codemirror": "^5.42.2",
"codemirror-graphql": "^0.8.3", "codemirror-graphql": "^0.8.3",

@ -930,6 +930,11 @@
"@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-lib-coverage" "^2.0.0"
"@types/yargs" "^12.0.9" "@types/yargs" "^12.0.9"
"@reach/visually-hidden@^0.1.4":
version "0.1.4"
resolved "https://registry.yarnpkg.com/@reach/visually-hidden/-/visually-hidden-0.1.4.tgz#0dc4ecedf523004337214187db70a46183bd945b"
integrity sha512-QHbzXjflSlCvDd6vJwdwx16mSB+vUCCQMiU/wK/CgVNPibtpEiIbisyxkpZc55DyDFNUIqP91rSUsNae+ogGDQ==
"@samverschueren/stream-to-observable@^0.3.0": "@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"

Loading…
Cancel
Save