Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Add a11y context (#4586)

* Add a11y context

* Feedback

authored by

Eric Bailey and committed by
GitHub
4bba5979 4d8537bc

+111 -40
+24 -21
src/App.native.tsx
··· 24 24 import {s} from '#/lib/styles' 25 25 import {ThemeProvider} from '#/lib/ThemeContext' 26 26 import {logger} from '#/logger' 27 + import {Provider as A11yProvider} from '#/state/a11y' 27 28 import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' 28 29 import {Provider as DialogStateProvider} from '#/state/dialogs' 29 30 import {Provider as InvitesStateProvider} from '#/state/invites' ··· 152 153 * that is set up in the InnerApp component above. 153 154 */ 154 155 return ( 155 - <KeyboardProvider enabled={false} statusBarTranslucent={true}> 156 - <SessionProvider> 157 - <ShellStateProvider> 158 - <PrefsStateProvider> 159 - <InvitesStateProvider> 160 - <ModalStateProvider> 161 - <DialogStateProvider> 162 - <LightboxStateProvider> 163 - <I18nProvider> 164 - <PortalProvider> 165 - <InnerApp /> 166 - </PortalProvider> 167 - </I18nProvider> 168 - </LightboxStateProvider> 169 - </DialogStateProvider> 170 - </ModalStateProvider> 171 - </InvitesStateProvider> 172 - </PrefsStateProvider> 173 - </ShellStateProvider> 174 - </SessionProvider> 175 - </KeyboardProvider> 156 + <A11yProvider> 157 + <KeyboardProvider enabled={false} statusBarTranslucent={true}> 158 + <SessionProvider> 159 + <ShellStateProvider> 160 + <PrefsStateProvider> 161 + <InvitesStateProvider> 162 + <ModalStateProvider> 163 + <DialogStateProvider> 164 + <LightboxStateProvider> 165 + <I18nProvider> 166 + <PortalProvider> 167 + <InnerApp /> 168 + </PortalProvider> 169 + </I18nProvider> 170 + </LightboxStateProvider> 171 + </DialogStateProvider> 172 + </ModalStateProvider> 173 + </InvitesStateProvider> 174 + </PrefsStateProvider> 175 + </ShellStateProvider> 176 + </SessionProvider> 177 + </KeyboardProvider> 178 + </A11yProvider> 176 179 ) 177 180 } 178 181
+22 -19
src/App.web.tsx
··· 13 13 import {Provider as StatsigProvider} from '#/lib/statsig/statsig' 14 14 import {ThemeProvider} from '#/lib/ThemeContext' 15 15 import {logger} from '#/logger' 16 + import {Provider as A11yProvider} from '#/state/a11y' 16 17 import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' 17 18 import {Provider as DialogStateProvider} from '#/state/dialogs' 18 19 import {Provider as InvitesStateProvider} from '#/state/invites' ··· 135 136 * that is set up in the InnerApp component above. 136 137 */ 137 138 return ( 138 - <SessionProvider> 139 - <ShellStateProvider> 140 - <PrefsStateProvider> 141 - <InvitesStateProvider> 142 - <ModalStateProvider> 143 - <DialogStateProvider> 144 - <LightboxStateProvider> 145 - <I18nProvider> 146 - <PortalProvider> 147 - <InnerApp /> 148 - </PortalProvider> 149 - </I18nProvider> 150 - </LightboxStateProvider> 151 - </DialogStateProvider> 152 - </ModalStateProvider> 153 - </InvitesStateProvider> 154 - </PrefsStateProvider> 155 - </ShellStateProvider> 156 - </SessionProvider> 139 + <A11yProvider> 140 + <SessionProvider> 141 + <ShellStateProvider> 142 + <PrefsStateProvider> 143 + <InvitesStateProvider> 144 + <ModalStateProvider> 145 + <DialogStateProvider> 146 + <LightboxStateProvider> 147 + <I18nProvider> 148 + <PortalProvider> 149 + <InnerApp /> 150 + </PortalProvider> 151 + </I18nProvider> 152 + </LightboxStateProvider> 153 + </DialogStateProvider> 154 + </ModalStateProvider> 155 + </InvitesStateProvider> 156 + </PrefsStateProvider> 157 + </ShellStateProvider> 158 + </SessionProvider> 159 + </A11yProvider> 157 160 ) 158 161 } 159 162
+65
src/state/a11y.tsx
··· 1 + import React from 'react' 2 + import {AccessibilityInfo} from 'react-native' 3 + import {isReducedMotion} from 'react-native-reanimated' 4 + 5 + import {isWeb} from '#/platform/detection' 6 + 7 + const Context = React.createContext({ 8 + reduceMotionEnabled: false, 9 + screenReaderEnabled: false, 10 + }) 11 + 12 + export function useA11y() { 13 + return React.useContext(Context) 14 + } 15 + 16 + export function Provider({children}: React.PropsWithChildren<{}>) { 17 + const [reduceMotionEnabled, setReduceMotionEnabled] = React.useState(() => 18 + isReducedMotion(), 19 + ) 20 + const [screenReaderEnabled, setScreenReaderEnabled] = React.useState(false) 21 + 22 + React.useEffect(() => { 23 + const reduceMotionChangedSubscription = AccessibilityInfo.addEventListener( 24 + 'reduceMotionChanged', 25 + enabled => { 26 + setReduceMotionEnabled(enabled) 27 + }, 28 + ) 29 + const screenReaderChangedSubscription = AccessibilityInfo.addEventListener( 30 + 'screenReaderChanged', 31 + enabled => { 32 + setScreenReaderEnabled(enabled) 33 + }, 34 + ) 35 + 36 + ;(async () => { 37 + const [_reduceMotionEnabled, _screenReaderEnabled] = await Promise.all([ 38 + AccessibilityInfo.isReduceMotionEnabled(), 39 + AccessibilityInfo.isScreenReaderEnabled(), 40 + ]) 41 + setReduceMotionEnabled(_reduceMotionEnabled) 42 + setScreenReaderEnabled(_screenReaderEnabled) 43 + })() 44 + 45 + return () => { 46 + reduceMotionChangedSubscription.remove() 47 + screenReaderChangedSubscription.remove() 48 + } 49 + }, []) 50 + 51 + const ctx = React.useMemo(() => { 52 + return { 53 + reduceMotionEnabled, 54 + /** 55 + * Always returns true on web. For now, we're using this for mobile a11y, 56 + * so we reset to false on web. 57 + * 58 + * @see https://github.com/necolas/react-native-web/discussions/2072 59 + */ 60 + screenReaderEnabled: isWeb ? false : screenReaderEnabled, 61 + } 62 + }, [reduceMotionEnabled, screenReaderEnabled]) 63 + 64 + return <Context.Provider value={ctx}>{children}</Context.Provider> 65 + }