about summary refs log tree commit diff
path: root/src/lib/hooks/useEnableKeyboardController.tsx
diff options
context:
space:
mode:
authorSamuel Newman <mozzius@protonmail.com>2024-11-25 20:30:15 +0000
committerGitHub <noreply@github.com>2024-11-25 20:30:15 +0000
commitb0c36383a9a7304f94c2bb19f7cc4b37e0b4f637 (patch)
tree4001655a33bb300b99dbc81096ccc27fe4f712bd /src/lib/hooks/useEnableKeyboardController.tsx
parent6c81090021222263dbf1d546216ea0da95029738 (diff)
downloadvoidsky-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/useEnableKeyboardController.tsx')
-rw-r--r--src/lib/hooks/useEnableKeyboardController.tsx110
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]),
+  )
+}