Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix reactivity of dialogs (Dialogs Pt. 1) (#3146)

* Improve a11y on ios

* Format

* Remove android

* Fix android

* Revert some changes

* use sharedvalue for `importantForAccessibility`

* add back `isOpen`

* fix some more types

---------

Co-authored-by: Eric Bailey <git@esb.lol>

authored by

Hailey
Eric Bailey
and committed by
GitHub
0f9f08b1 8f623c3b

+49 -38
+2 -4
src/components/Dialog/context.ts
··· 21 21 open: () => {}, 22 22 close: () => {}, 23 23 }) 24 - const {activeDialogs, openDialogs} = useDialogStateContext() 25 - const isOpen = openDialogs.includes(id) 24 + const {activeDialogs} = useDialogStateContext() 26 25 27 26 React.useEffect(() => { 28 27 activeDialogs.current.set(id, control) ··· 36 35 () => ({ 37 36 id, 38 37 ref: control, 39 - isOpen, 40 38 open: () => { 41 39 control.current.open() 42 40 }, ··· 44 42 control.current.close(cb) 45 43 }, 46 44 }), 47 - [id, control, isOpen], 45 + [id, control], 48 46 ) 49 47 }
+1 -1
src/components/Dialog/types.ts
··· 22 22 export type DialogControlProps = DialogControlRefProps & { 23 23 id: string 24 24 ref: React.RefObject<DialogControlRefProps> 25 - isOpen: boolean 25 + isOpen?: boolean 26 26 } 27 27 28 28 export type DialogContextProps = {
+41 -19
src/state/dialogs/index.tsx
··· 1 1 import React from 'react' 2 + import {SharedValue, useSharedValue} from 'react-native-reanimated' 2 3 import {DialogControlRefProps} from '#/components/Dialog' 3 4 import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context' 4 5 5 - const DialogContext = React.createContext<{ 6 + interface IDialogContext { 6 7 /** 7 8 * The currently active `useDialogControl` hooks. 8 9 */ ··· 13 14 * The currently open dialogs, referenced by their IDs, generated from 14 15 * `useId`. 15 16 */ 16 - openDialogs: string[] 17 - }>({ 18 - activeDialogs: { 19 - current: new Map(), 20 - }, 21 - openDialogs: [], 22 - }) 17 + openDialogs: React.MutableRefObject<Set<string>> 18 + /** 19 + * The counterpart to `accessibilityViewIsModal` for Android. This property 20 + * applies to the parent of all non-modal views, and prevents TalkBack from 21 + * navigating within content beneath an open dialog. 22 + * 23 + * @see https://reactnative.dev/docs/accessibility#importantforaccessibility-android 24 + */ 25 + importantForAccessibility: SharedValue<'auto' | 'no-hide-descendants'> 26 + } 27 + 28 + const DialogContext = React.createContext<IDialogContext>({} as IDialogContext) 23 29 24 30 const DialogControlContext = React.createContext<{ 25 31 closeAllDialogs(): boolean ··· 41 47 const activeDialogs = React.useRef< 42 48 Map<string, React.MutableRefObject<DialogControlRefProps>> 43 49 >(new Map()) 44 - const [openDialogs, setOpenDialogs] = React.useState<string[]>([]) 50 + const openDialogs = React.useRef<Set<string>>(new Set()) 51 + const importantForAccessibility = useSharedValue< 52 + 'auto' | 'no-hide-descendants' 53 + >('auto') 45 54 46 55 const closeAllDialogs = React.useCallback(() => { 47 56 activeDialogs.current.forEach(dialog => dialog.current.close()) 48 - return openDialogs.length > 0 49 - }, [openDialogs]) 57 + return openDialogs.current.size > 0 58 + }, []) 50 59 51 60 const setDialogIsOpen = React.useCallback( 52 61 (id: string, isOpen: boolean) => { 53 - setOpenDialogs(prev => { 54 - const filtered = prev.filter(dialogId => dialogId !== id) as string[] 55 - return isOpen ? [...filtered, id] : filtered 56 - }) 62 + if (isOpen) { 63 + openDialogs.current.add(id) 64 + importantForAccessibility.value = 'no-hide-descendants' 65 + } else { 66 + openDialogs.current.delete(id) 67 + if (openDialogs.current.size < 1) { 68 + importantForAccessibility.value = 'auto' 69 + } 70 + } 57 71 }, 58 - [setOpenDialogs], 72 + [importantForAccessibility], 59 73 ) 60 74 61 - const context = React.useMemo( 62 - () => ({activeDialogs, openDialogs}), 63 - [openDialogs], 75 + const context = React.useMemo<IDialogContext>( 76 + () => ({ 77 + activeDialogs: { 78 + current: new Map(), 79 + }, 80 + openDialogs: { 81 + current: new Set(), 82 + }, 83 + importantForAccessibility, 84 + }), 85 + [importantForAccessibility], 64 86 ) 65 87 const controls = React.useMemo( 66 88 () => ({closeAllDialogs, setDialogIsOpen}),
+5 -14
src/view/shell/index.tsx
··· 30 30 import * as notifications from 'lib/notifications/notifications' 31 31 import {Outlet as PortalOutlet} from '#/components/Portal' 32 32 import {MutedWordsDialog} from '#/components/dialogs/MutedWords' 33 - import {useDialogStateContext} from '#/state/dialogs' 33 + import {useDialogStateContext} from 'state/dialogs' 34 + import Animated from 'react-native-reanimated' 34 35 35 36 function ShellInner() { 36 37 const isDrawerOpen = useIsDrawerOpen() ··· 54 55 const canGoBack = useNavigationState(state => !isStateAtTabRoot(state)) 55 56 const {hasSession, currentAccount} = useSession() 56 57 const closeAnyActiveElement = useCloseAnyActiveElement() 58 + const {importantForAccessibility} = useDialogStateContext() 57 59 // start undefined 58 60 const currentAccountDid = React.useRef<string | undefined>(undefined) 59 - const {openDialogs} = useDialogStateContext() 60 61 61 62 React.useEffect(() => { 62 63 let listener = {remove() {}} ··· 80 81 } 81 82 }, [currentAccount]) 82 83 83 - /** 84 - * The counterpart to `accessibilityViewIsModal` for Android. This property 85 - * applies to the parent of all non-modal views, and prevents TalkBack from 86 - * navigating within content beneath an open dialog. 87 - * 88 - * @see https://reactnative.dev/docs/accessibility#importantforaccessibility-android 89 - */ 90 - const importantForAccessibility = 91 - openDialogs.length > 0 ? 'no-hide-descendants' : undefined 92 - 93 84 return ( 94 85 <> 95 - <View 86 + <Animated.View 96 87 style={containerPadding} 97 88 importantForAccessibility={importantForAccessibility}> 98 89 <ErrorBoundary> ··· 106 97 <TabsNavigator /> 107 98 </Drawer> 108 99 </ErrorBoundary> 109 - </View> 100 + </Animated.View> 110 101 <Composer winHeight={winDim.height} /> 111 102 <ModalsContainer /> 112 103 <MutedWordsDialog />