Pass through a11y props

This commit is contained in:
Eric Bailey
2024-03-05 12:14:40 -06:00
parent 4cdb72f944
commit 076fa9dddd
4 changed files with 28 additions and 26 deletions
+17 -16
View File
@@ -1,7 +1,8 @@
import React from 'react' import React from 'react'
import {View, Pressable} from 'react-native' import {View, Pressable} from 'react-native'
import {atoms as a, useTheme, ViewStyleProp} from '#/alf' import {logger} from '#/logger'
import {atoms as a, useTheme} from '#/alf'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
import {useInteractionState} from '#/components/hooks/useInteractionState' import {useInteractionState} from '#/components/hooks/useInteractionState'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
@@ -9,7 +10,7 @@ import {Text} from '#/components/Typography'
import {Context} from '#/components/Menu/context' import {Context} from '#/components/Menu/context'
import { import {
ContextType, ContextType,
TriggerChildProps, TriggerProps,
ItemProps, ItemProps,
GroupProps, GroupProps,
ItemTextProps, ItemTextProps,
@@ -39,11 +40,7 @@ export function Root({
return <Context.Provider value={context}>{children}</Context.Provider> return <Context.Provider value={context}>{children}</Context.Provider>
} }
export function Trigger({ export function Trigger({children, label}: TriggerProps) {
children,
}: ViewStyleProp & {
children(props: TriggerChildProps): React.ReactNode
}) {
const {control} = React.useContext(Context) const {control} = React.useContext(Context)
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
const { const {
@@ -52,11 +49,7 @@ export function Trigger({
onOut: onPressOut, onOut: onPressOut,
} = useInteractionState() } = useInteractionState()
if (!control) { const child = children({
throw new Error('Menu.Trigger must be used within a Menu.Root')
}
return children({
isNative: true, isNative: true,
control, control,
state: { state: {
@@ -72,15 +65,23 @@ export function Trigger({
onPressOut, onPressOut,
}, },
}) })
if (!React.isValidElement(child)) {
logger.error(
'Menu.Trigger children must be a function that returns a valid element',
)
return null
}
return React.cloneElement(child, {
...child.props,
accessibilityLabel: label,
})
} }
export function Outer({children}: React.PropsWithChildren<{}>) { export function Outer({children}: React.PropsWithChildren<{}>) {
const {control} = React.useContext(Context) const {control} = React.useContext(Context)
if (!control) {
throw new Error('Menu.Outer must be used within a Menu.Root')
}
return ( return (
<Dialog.Outer control={control}> <Dialog.Outer control={control}>
<Dialog.Handle /> <Dialog.Handle />
+6 -9
View File
@@ -4,12 +4,12 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
import {useInteractionState} from '#/components/hooks/useInteractionState' import {useInteractionState} from '#/components/hooks/useInteractionState'
import {atoms as a, useTheme, flatten, web, ViewStyleProp} from '#/alf' import {atoms as a, useTheme, flatten, web} from '#/alf'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import { import {
ContextType, ContextType,
TriggerChildProps, TriggerProps,
ItemProps, ItemProps,
GroupProps, GroupProps,
ItemTextProps, ItemTextProps,
@@ -76,12 +76,7 @@ export function Root({
) )
} }
export function Trigger({ export function Trigger({children, label, style}: TriggerProps) {
children,
style,
}: ViewStyleProp & {
children(props: TriggerChildProps): React.ReactNode
}) {
const {control} = React.useContext(Context) const {control} = React.useContext(Context)
const { const {
state: hovered, state: hovered,
@@ -93,6 +88,8 @@ export function Trigger({
return ( return (
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<Pressable <Pressable
accessibilityHint=""
accessibilityLabel={label}
onFocus={onFocus} onFocus={onFocus}
onBlur={onBlur} onBlur={onBlur}
style={flatten([style, web({outline: 0})])} style={flatten([style, web({outline: 0})])}
@@ -123,7 +120,7 @@ export function Outer({children}: React.PropsWithChildren<{}>) {
return ( return (
<DropdownMenu.Portal> <DropdownMenu.Portal>
<DropdownMenu.Content sideOffset={5} loop> <DropdownMenu.Content sideOffset={5} loop aria-label="Test">
<View style={[a.rounded_sm, a.p_xs, t.atoms.bg_contrast_50]}> <View style={[a.rounded_sm, a.p_xs, t.atoms.bg_contrast_50]}>
{children} {children}
</View> </View>
+4
View File
@@ -8,6 +8,10 @@ export type ContextType = {
control: Dialog.DialogOuterProps['control'] control: Dialog.DialogOuterProps['control']
} }
export type TriggerProps = ViewStyleProp & {
children(props: TriggerChildProps): React.ReactNode
label: string
}
export type TriggerChildProps = export type TriggerChildProps =
| { | {
isNative: true isNative: true
+1 -1
View File
@@ -16,7 +16,7 @@ export function Menus() {
<View style={[a.gap_md]}> <View style={[a.gap_md]}>
<View style={[a.flex_row, a.align_start]}> <View style={[a.flex_row, a.align_start]}>
<Menu.Root control={menuControl}> <Menu.Root control={menuControl}>
<Menu.Trigger style={[a.flex_1]}> <Menu.Trigger label="Open basic menu" style={[a.flex_1]}>
{({state, handlers}) => { {({state, handlers}) => {
return ( return (
<Text <Text