React Native accessibility (#539)

* React Native accessibility

* First round of changes

* Latest update

* Checkpoint

* Wrap up

* Lint

* Remove unhelpful image hints

* Fix navigation

* Fix rebase and lint

* Mitigate an known issue with the password entry in login

* Fix composer dismiss

* Remove focus on input elements for web

* Remove i and npm

* pls work

* Remove stray declaration

* Regenerate yarn.lock

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
Ollie H 2023-05-01 18:38:47 -07:00 committed by GitHub
parent c75c888de2
commit 83959c595d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
86 changed files with 2479 additions and 1827 deletions

View file

@ -26,6 +26,7 @@ export type ButtonType =
| 'secondary-light'
| 'default-light'
// TODO: Enforce that button always has a label
export function Button({
type = 'primary',
label,
@ -131,7 +132,8 @@ export function Button({
<Pressable
style={[typeOuterStyle, styles.outer, style]}
onPress={onPressWrapped}
testID={testID}>
testID={testID}
accessibilityRole="button">
{label ? (
<Text type="button" style={[typeLabelStyle, labelStyle]}>
{label}

View file

@ -1,4 +1,4 @@
import React, {useRef} from 'react'
import React, {PropsWithChildren, useMemo, useRef} from 'react'
import {
Dimensions,
StyleProp,
@ -39,6 +39,19 @@ type MaybeDropdownItem = DropdownItem | false | undefined
export type DropdownButtonType = ButtonType | 'bare'
interface DropdownButtonProps {
testID?: string
type?: DropdownButtonType
style?: StyleProp<ViewStyle>
items: MaybeDropdownItem[]
label?: string
menuWidth?: number
children?: React.ReactNode
openToRight?: boolean
rightOffset?: number
bottomOffset?: number
}
export function DropdownButton({
testID,
type = 'bare',
@ -50,18 +63,7 @@ export function DropdownButton({
openToRight = false,
rightOffset = 0,
bottomOffset = 0,
}: {
testID?: string
type?: DropdownButtonType
style?: StyleProp<ViewStyle>
items: MaybeDropdownItem[]
label?: string
menuWidth?: number
children?: React.ReactNode
openToRight?: boolean
rightOffset?: number
bottomOffset?: number
}) {
}: PropsWithChildren<DropdownButtonProps>) {
const ref1 = useRef<TouchableOpacity>(null)
const ref2 = useRef<View>(null)
@ -105,6 +107,18 @@ export function DropdownButton({
)
}
const numItems = useMemo(
() =>
items.filter(item => {
if (item === undefined || item === false) {
return false
}
return isBtn(item)
}).length,
[items],
)
if (type === 'bare') {
return (
<TouchableOpacity
@ -112,7 +126,10 @@ export function DropdownButton({
style={style}
onPress={onPress}
hitSlop={HITSLOP}
ref={ref1}>
ref={ref1}
accessibilityRole="button"
accessibilityLabel={`Opens ${numItems} options`}
accessibilityHint={`Opens ${numItems} options`}>
{children}
</TouchableOpacity>
)
@ -283,9 +300,20 @@ const DropdownItems = ({
const separatorColor =
theme.colorScheme === 'dark' ? pal.borderDark : pal.border
const numItems = items.filter(isBtn).length
return (
<>
<TouchableWithoutFeedback onPress={onOuterPress}>
<TouchableWithoutFeedback
onPress={onOuterPress}
// TODO: Refactor dropdown components to:
// - (On web, if not handled by React Native) use semantic <select />
// and <option /> elements for keyboard navigation out of the box
// - (On mobile) be buttons by default, accept `label` and `nativeID`
// props, and always have an explicit label
accessibilityRole="button"
accessibilityLabel="Toggle dropdown"
accessibilityHint="">
<View style={[styles.bg]} />
</TouchableWithoutFeedback>
<View
@ -301,7 +329,9 @@ const DropdownItems = ({
testID={item.testID}
key={index}
style={[styles.menuItem]}
onPress={() => onPressItem(index)}>
onPress={() => onPressItem(index)}
accessibilityLabel={item.label}
accessibilityHint={`Option ${index + 1} of ${numItems}`}>
{item.icon && (
<FontAwesomeIcon
style={styles.icon}