Improve dialogs a11y (#3094)

* Improve a11y on ios

* Format

* Remove android

* Fix android
This commit is contained in:
Eric Bailey 2024-03-04 15:37:11 -06:00 committed by GitHub
parent ebd279ed68
commit 6c9d6f5b05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 91 additions and 54 deletions

View file

@ -15,7 +15,7 @@ import {useTheme, atoms as a, flatten} from '#/alf'
import {Portal} from '#/components/Portal'
import {createInput} from '#/components/forms/TextField'
import {logger} from '#/logger'
import {useDialogStateContext} from '#/state/dialogs'
import {useDialogStateControlContext} from '#/state/dialogs'
import {
DialogOuterProps,
@ -82,7 +82,7 @@ export function Outer({
const hasSnapPoints = !!sheetOptions.snapPoints
const insets = useSafeAreaInsets()
const closeCallback = React.useRef<() => void>()
const {openDialogs} = useDialogStateContext()
const {setDialogIsOpen} = useDialogStateControlContext()
/*
* Used to manage open/closed, but index is otherwise handled internally by `BottomSheet`
@ -96,11 +96,11 @@ export function Outer({
const open = React.useCallback<DialogControlProps['open']>(
({index} = {}) => {
openDialogs.current.add(control.id)
setDialogIsOpen(control.id, true)
// can be set to any index of `snapPoints`, but `0` is the first i.e. "open"
setOpenIndex(index || 0)
},
[setOpenIndex, openDialogs, control.id],
[setOpenIndex, setDialogIsOpen, control.id],
)
const close = React.useCallback<DialogControlProps['close']>(cb => {
@ -133,12 +133,12 @@ export function Outer({
closeCallback.current = undefined
}
openDialogs.current.delete(control.id)
setDialogIsOpen(control.id, false)
onClose?.()
setOpenIndex(-1)
}
},
[onClose, setOpenIndex, openDialogs, control.id],
[onClose, setOpenIndex, setDialogIsOpen, control.id],
)
const context = React.useMemo(() => ({close}), [close])
@ -146,38 +146,45 @@ export function Outer({
return (
isOpen && (
<Portal>
<BottomSheet
enableDynamicSizing={!hasSnapPoints}
enablePanDownToClose
keyboardBehavior="interactive"
android_keyboardInputMode="adjustResize"
keyboardBlurBehavior="restore"
topInset={insets.top}
{...sheetOptions}
snapPoints={sheetOptions.snapPoints || ['100%']}
ref={sheet}
index={openIndex}
backgroundStyle={{backgroundColor: 'transparent'}}
backdropComponent={Backdrop}
handleIndicatorStyle={{backgroundColor: t.palette.primary_500}}
handleStyle={{display: 'none'}}
onChange={onChange}>
<Context.Provider value={context}>
<View
style={[
a.absolute,
a.inset_0,
t.atoms.bg,
{
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
height: Dimensions.get('window').height * 2,
},
]}
/>
{children}
</Context.Provider>
</BottomSheet>
<View
// iOS
accessibilityViewIsModal
// Android
importantForAccessibility="yes"
style={[a.absolute, a.inset_0]}>
<BottomSheet
enableDynamicSizing={!hasSnapPoints}
enablePanDownToClose
keyboardBehavior="interactive"
android_keyboardInputMode="adjustResize"
keyboardBlurBehavior="restore"
topInset={insets.top}
{...sheetOptions}
snapPoints={sheetOptions.snapPoints || ['100%']}
ref={sheet}
index={openIndex}
backgroundStyle={{backgroundColor: 'transparent'}}
backdropComponent={Backdrop}
handleIndicatorStyle={{backgroundColor: t.palette.primary_500}}
handleStyle={{display: 'none'}}
onChange={onChange}>
<Context.Provider value={context}>
<View
style={[
a.absolute,
a.inset_0,
t.atoms.bg,
{
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
height: Dimensions.get('window').height * 2,
},
]}
/>
{children}
</Context.Provider>
</BottomSheet>
</View>
</Portal>
)
)

View file

@ -12,7 +12,7 @@ import {DialogOuterProps, DialogInnerProps} from '#/components/Dialog/types'
import {Context} from '#/components/Dialog/context'
import {Button, ButtonIcon} from '#/components/Button'
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
import {useDialogStateContext} from '#/state/dialogs'
import {useDialogStateControlContext} from '#/state/dialogs'
export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
export * from '#/components/Dialog/types'
@ -30,21 +30,21 @@ export function Outer({
const {gtMobile} = useBreakpoints()
const [isOpen, setIsOpen] = React.useState(false)
const [isVisible, setIsVisible] = React.useState(true)
const {openDialogs} = useDialogStateContext()
const {setDialogIsOpen} = useDialogStateControlContext()
const open = React.useCallback(() => {
setIsOpen(true)
openDialogs.current.add(control.id)
}, [setIsOpen, openDialogs, control.id])
setDialogIsOpen(control.id, true)
}, [setIsOpen, setDialogIsOpen, control.id])
const close = React.useCallback(async () => {
setIsVisible(false)
await new Promise(resolve => setTimeout(resolve, 150))
setIsOpen(false)
setIsVisible(true)
openDialogs.current.delete(control.id)
setDialogIsOpen(control.id, false)
onClose?.()
}, [onClose, setIsOpen, openDialogs, control.id])
}, [onClose, setIsOpen, setDialogIsOpen, control.id])
useImperativeHandle(
control.ref,