diff options
author | Samuel Newman <mozzius@protonmail.com> | 2024-11-25 20:30:15 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-25 20:30:15 +0000 |
commit | b0c36383a9a7304f94c2bb19f7cc4b37e0b4f637 (patch) | |
tree | 4001655a33bb300b99dbc81096ccc27fe4f712bd /src/lib/hooks | |
parent | 6c81090021222263dbf1d546216ea0da95029738 (diff) | |
download | voidsky-b0c36383a9a7304f94c2bb19f7cc4b37e0b4f637.tar.zst |
Ensure react-native-keyboard-controller enabled state doesn't get overwritten (#6727)
* revert to prev state instead of false * add dep array * use ref counting approach * patch keyboard controller to allow changing the enabled prop * remove state from patch * change patched prop name * remove Math.max check, log if < 0 * use noop provider * rm patch, use `useRef` * Style nits * Rm on web --------- Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Diffstat (limited to 'src/lib/hooks')
-rw-r--r-- | src/lib/hooks/useEnableKeyboardController.tsx | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/src/lib/hooks/useEnableKeyboardController.tsx b/src/lib/hooks/useEnableKeyboardController.tsx new file mode 100644 index 000000000..c7205d016 --- /dev/null +++ b/src/lib/hooks/useEnableKeyboardController.tsx @@ -0,0 +1,110 @@ +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useRef, +} from 'react' +import { + KeyboardProvider, + useKeyboardController, +} from 'react-native-keyboard-controller' +import {useFocusEffect} from '@react-navigation/native' + +import {IS_DEV} from '#/env' + +const KeyboardControllerRefCountContext = createContext<{ + incrementRefCount: () => void + decrementRefCount: () => void +}>({ + incrementRefCount: () => {}, + decrementRefCount: () => {}, +}) + +export function KeyboardControllerProvider({ + children, +}: { + children: React.ReactNode +}) { + return ( + <KeyboardProvider + enabled={false} + // I don't think this is necessary, but Chesterton's fence and all that -sfn + statusBarTranslucent={true}> + <KeyboardControllerProviderInner> + {children} + </KeyboardControllerProviderInner> + </KeyboardProvider> + ) +} + +function KeyboardControllerProviderInner({ + children, +}: { + children: React.ReactNode +}) { + const {setEnabled} = useKeyboardController() + const refCount = useRef(0) + + const value = useMemo( + () => ({ + incrementRefCount: () => { + refCount.current++ + setEnabled(refCount.current > 0) + }, + decrementRefCount: () => { + refCount.current-- + setEnabled(refCount.current > 0) + + if (IS_DEV && refCount.current < 0) { + console.error('KeyboardController ref count < 0') + } + }, + }), + [setEnabled], + ) + + return ( + <KeyboardControllerRefCountContext.Provider value={value}> + {children} + </KeyboardControllerRefCountContext.Provider> + ) +} + +export function useEnableKeyboardController(shouldEnable: boolean) { + const {incrementRefCount, decrementRefCount} = useContext( + KeyboardControllerRefCountContext, + ) + + useEffect(() => { + if (!shouldEnable) { + return + } + incrementRefCount() + return () => { + decrementRefCount() + } + }, [shouldEnable, incrementRefCount, decrementRefCount]) +} + +/** + * Like `useEnableKeyboardController`, but using `useFocusEffect` + */ +export function useEnableKeyboardControllerScreen(shouldEnable: boolean) { + const {incrementRefCount, decrementRefCount} = useContext( + KeyboardControllerRefCountContext, + ) + + useFocusEffect( + useCallback(() => { + if (!shouldEnable) { + return + } + incrementRefCount() + return () => { + decrementRefCount() + } + }, [shouldEnable, incrementRefCount, decrementRefCount]), + ) +} |