From f3f17d6f6dc1417938999028cc4c26e29a732430 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Tue, 19 May 2026 15:18:07 +0200 Subject: [PATCH 1/3] fix: remove react-native-keyboard-controller remnants --- .gitignore | 2 + examples/ExpoMessaging/package.json | 2 +- examples/ExpoMessaging/yarn.lock | 7 ++ package/package.json | 5 -- .../AttachmentPicker/AttachmentPicker.tsx | 16 +---- package/src/components/Channel/Channel.tsx | 2 +- .../components/ImageGallery/ImageGallery.tsx | 2 +- .../KeyboardCompatibleView.tsx | 6 ++ .../KeyboardControllerAvoidingView.tsx | 69 ------------------- package/src/components/Message/Message.tsx | 2 +- .../UIComponents/BottomSheetModal.tsx | 20 +++--- .../componentsContext/defaultComponents.ts | 2 +- .../MessageInputContext.tsx | 2 +- .../src/hooks/useAfterKeyboardOpenCallback.ts | 5 +- package/src/hooks/useKeyboardVisibility.ts | 36 +++------- 15 files changed, 42 insertions(+), 136 deletions(-) delete mode 100644 package/src/components/KeyboardCompatibleView/KeyboardControllerAvoidingView.tsx diff --git a/.gitignore b/.gitignore index 3895765f2f..ca66e76e98 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ index.android.bundle *.DSYM.zip **/metrics/ package/shared-native/.sync-state/ + +.claude/worktrees diff --git a/examples/ExpoMessaging/package.json b/examples/ExpoMessaging/package.json index 1664d6fd02..a6b6998349 100644 --- a/examples/ExpoMessaging/package.json +++ b/examples/ExpoMessaging/package.json @@ -52,8 +52,8 @@ "react-native-safe-area-context": "~5.6.2", "react-native-screens": "~4.23.0", "react-native-svg": "15.15.3", - "react-native-web": "^0.21.0", "react-native-teleport": "^1.0.2", + "react-native-web": "^0.21.0", "react-native-worklets": "0.7.2", "stream-chat-expo": "link:../../package/expo-package", "stream-chat-react-native-core": "link:../../package" diff --git a/examples/ExpoMessaging/yarn.lock b/examples/ExpoMessaging/yarn.lock index 099e0cadf4..e4cd81d90e 100644 --- a/examples/ExpoMessaging/yarn.lock +++ b/examples/ExpoMessaging/yarn.lock @@ -5526,6 +5526,13 @@ react-native-is-edge-to-edge@1.2.1, react-native-is-edge-to-edge@^1.2.1: resolved "https://registry.yarnpkg.com/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz#64e10851abd9d176cbf2b40562f751622bde3358" integrity sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q== +react-native-keyboard-controller@^1.21.7: + version "1.21.7" + resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.21.7.tgz#2e9c6ab2d309a81d678420dcaaa7314b0324d42d" + integrity sha512-gs+8nI8HYnRdDt4NWbk1iVuS6kDLf2taJvp+h/TjM1FBdtnQmlYLJ6buNiUqSnkIH4OFEAxdNr3/GOOYdLfkUQ== + dependencies: + react-native-is-edge-to-edge "^1.2.1" + react-native-lightbox@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/react-native-lightbox/-/react-native-lightbox-0.7.0.tgz#e52b4d7fcc141f59d7b23f0180de535e35b20ec9" diff --git a/package/package.json b/package/package.json index 4cc0500837..96eee94d36 100644 --- a/package/package.json +++ b/package/package.json @@ -94,7 +94,6 @@ "emoji-mart": ">=5.4.0", "react-native": ">=0.73.0", "react-native-gesture-handler": ">=2.18.0", - "react-native-keyboard-controller": ">=1.20.2", "react-native-reanimated": ">=3.16.0", "react-native-safe-area-context": ">=5.4.1", "react-native-svg": ">=15.8.0", @@ -112,9 +111,6 @@ }, "@emoji-mart/data": { "optional": true - }, - "react-native-keyboard-controller": { - "optional": true } }, "devDependencies": { @@ -163,7 +159,6 @@ "react-native": "0.80.2", "react-native-builder-bob": "0.40.11", "react-native-gesture-handler": "^2.26.0", - "react-native-keyboard-controller": "^1.20.2", "react-native-reanimated": "3.18.0", "react-native-safe-area-context": "^5.6.1", "react-native-svg": "15.12.0", diff --git a/package/src/components/AttachmentPicker/AttachmentPicker.tsx b/package/src/components/AttachmentPicker/AttachmentPicker.tsx index 3b8586e82f..4df1abec1b 100644 --- a/package/src/components/AttachmentPicker/AttachmentPicker.tsx +++ b/package/src/components/AttachmentPicker/AttachmentPicker.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { BackHandler, - EmitterSubscription, Keyboard, Platform, View, @@ -21,7 +20,6 @@ import { useComponentsContext } from '../../contexts/componentsContext/Component import { useTheme } from '../../contexts/themeContext/ThemeContext'; import { useStableCallback } from '../../hooks'; import { BottomSheet } from '../BottomSheetCompatibility/BottomSheet'; -import { KeyboardControllerPackage } from '../KeyboardCompatibleView/KeyboardControllerAvoidingView'; dayjs.extend(duration); @@ -78,18 +76,10 @@ export const AttachmentPicker = () => { } closePicker(); }; - let keyboardSubscription: EmitterSubscription | null = null; - if (KeyboardControllerPackage?.KeyboardEvents) { - keyboardSubscription = KeyboardControllerPackage.KeyboardEvents.addListener( - 'keyboardWillShow', - onKeyboardOpenHandler, - ); - } else { - const keyboardShowEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'; - keyboardSubscription = Keyboard.addListener(keyboardShowEvent, onKeyboardOpenHandler); - } + const keyboardShowEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'; + const keyboardSubscription = Keyboard.addListener(keyboardShowEvent, onKeyboardOpenHandler); return () => { - keyboardSubscription?.remove(); + keyboardSubscription.remove(); }; }, [attachmentPickerStore, closePicker]); diff --git a/package/src/components/Channel/Channel.tsx b/package/src/components/Channel/Channel.tsx index dc6724f327..2ea9bc41af 100644 --- a/package/src/components/Channel/Channel.tsx +++ b/package/src/components/Channel/Channel.tsx @@ -114,7 +114,7 @@ import { } from '../../utils/utils'; import { NotificationAnnouncer } from '../Accessibility/NotificationAnnouncer'; import { AttachmentPicker } from '../AttachmentPicker/AttachmentPicker'; -import type { KeyboardCompatibleViewProps } from '../KeyboardCompatibleView/KeyboardControllerAvoidingView'; +import type { KeyboardCompatibleViewProps } from '../KeyboardCompatibleView/KeyboardCompatibleView'; import { Emoji } from '../MessageMenu/EmojiPickerList'; import { emojis } from '../MessageMenu/emojis'; import { toUnicodeScalarString } from '../MessageMenu/utils/toUnicodeScalarString'; diff --git a/package/src/components/ImageGallery/ImageGallery.tsx b/package/src/components/ImageGallery/ImageGallery.tsx index d3af58ec2d..a07076bc59 100644 --- a/package/src/components/ImageGallery/ImageGallery.tsx +++ b/package/src/components/ImageGallery/ImageGallery.tsx @@ -36,7 +36,7 @@ import { useViewport } from '../../hooks/useViewport'; import { IconProps } from '../../icons/utils/base'; import { ImageGalleryState } from '../../state-store/image-gallery-state-store'; import { FileTypes } from '../../types/types'; -import { dismissKeyboard } from '../KeyboardCompatibleView/KeyboardControllerAvoidingView'; +import { dismissKeyboard } from '../KeyboardCompatibleView/KeyboardCompatibleView'; import { BottomSheetModal } from '../UIComponents'; export type ImageGalleryActionHandler = () => Promise | void; diff --git a/package/src/components/KeyboardCompatibleView/KeyboardCompatibleView.tsx b/package/src/components/KeyboardCompatibleView/KeyboardCompatibleView.tsx index 52f599ea16..2371c6e364 100644 --- a/package/src/components/KeyboardCompatibleView/KeyboardCompatibleView.tsx +++ b/package/src/components/KeyboardCompatibleView/KeyboardCompatibleView.tsx @@ -22,6 +22,12 @@ import { import { KeyboardProvider } from '../../contexts/keyboardContext/KeyboardContext'; +export type KeyboardCompatibleViewProps = KeyboardAvoidingViewProps; + +export const dismissKeyboard = () => { + Keyboard.dismiss(); +}; + type State = { bottom: number; }; diff --git a/package/src/components/KeyboardCompatibleView/KeyboardControllerAvoidingView.tsx b/package/src/components/KeyboardCompatibleView/KeyboardControllerAvoidingView.tsx deleted file mode 100644 index fd31080d70..0000000000 --- a/package/src/components/KeyboardCompatibleView/KeyboardControllerAvoidingView.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import React, { useEffect } from 'react'; - -import { - Keyboard, - KeyboardAvoidingViewProps as ReactNativeKeyboardAvoidingViewProps, -} from 'react-native'; - -import { KeyboardCompatibleView as KeyboardCompatibleViewDefault } from './KeyboardCompatibleView'; - -type ExtraKeyboardControllerProps = { - behavior?: 'translate-with-padding'; -}; - -type KeyboardControllerModule = typeof import('react-native-keyboard-controller'); - -const optionalRequire = (): T | undefined => { - try { - return require('react-native-keyboard-controller') as T; - } catch { - return undefined; - } -}; - -export type KeyboardCompatibleViewProps = ReactNativeKeyboardAvoidingViewProps & - ExtraKeyboardControllerProps; - -const KeyboardControllerPackage = optionalRequire(); - -const { AndroidSoftInputModes, KeyboardController, KeyboardProvider, KeyboardAvoidingView } = - KeyboardControllerPackage ?? {}; - -export const KeyboardCompatibleView = (props: KeyboardCompatibleViewProps) => { - const { behavior = 'translate-with-padding', children, ...rest } = props; - - useEffect(() => { - if (AndroidSoftInputModes) { - KeyboardController?.setInputMode(AndroidSoftInputModes.SOFT_INPUT_ADJUST_RESIZE); - } - - return () => KeyboardController?.setDefaultMode(); - }, []); - - if (KeyboardProvider && KeyboardAvoidingView) { - return ( - - {/* @ts-expect-error - The reason is that react-native-keyboard-controller's KeyboardAvoidingViewProps is a discriminated union, not a simple behavior union so it complains about the `position` value passed. */} - - {children} - - - ); - } - const compatibleBehavior = behavior === 'translate-with-padding' ? 'padding' : behavior; - - return ( - - {children} - - ); -}; - -export const dismissKeyboard = () => { - if (KeyboardControllerPackage?.KeyboardController) { - KeyboardControllerPackage?.KeyboardController.dismiss(); - } - Keyboard.dismiss(); -}; - -export { KeyboardControllerPackage }; diff --git a/package/src/components/Message/Message.tsx b/package/src/components/Message/Message.tsx index 316979be3f..57768e813e 100644 --- a/package/src/components/Message/Message.tsx +++ b/package/src/components/Message/Message.tsx @@ -77,7 +77,7 @@ import { MessageStatusTypes, } from '../../utils/utils'; import type { Thumbnail } from '../Attachment/utils/buildGallery/types'; -import { dismissKeyboard } from '../KeyboardCompatibleView/KeyboardControllerAvoidingView'; +import { dismissKeyboard } from '../KeyboardCompatibleView/KeyboardCompatibleView'; import { BottomSheetModal } from '../UIComponents'; const createMessageOverlayId = (messageId?: string) => diff --git a/package/src/components/UIComponents/BottomSheetModal.tsx b/package/src/components/UIComponents/BottomSheetModal.tsx index 843aec89b8..fd19576292 100644 --- a/package/src/components/UIComponents/BottomSheetModal.tsx +++ b/package/src/components/UIComponents/BottomSheetModal.tsx @@ -19,7 +19,6 @@ import { View, } from 'react-native'; import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler'; -import type { KeyboardEventData } from 'react-native-keyboard-controller'; import Animated, { Easing, FadeIn, @@ -43,7 +42,6 @@ import { BottomSheetProvider } from '../../contexts/bottomSheetContext/BottomShe import { useTheme } from '../../contexts/themeContext/ThemeContext'; import { useStableCallback } from '../../hooks'; import { primitives } from '../../theme'; -import { KeyboardControllerPackage } from '../KeyboardCompatibleView/KeyboardControllerAvoidingView'; export type BottomSheetModalProps = { /** @@ -377,18 +375,16 @@ const BottomSheetModalInner = (props: PropsWithChildren) const listeners: EventSubscription[] = []; - if (KeyboardControllerPackage?.KeyboardEvents) { - const keyboardDidShowKC = (event: KeyboardEventData) => { - animateKeyboardOffset(event.height); - }; - + if (Platform.OS === 'ios') { + listeners.push( + Keyboard.addListener('keyboardWillShow', keyboardDidShowRN), + Keyboard.addListener('keyboardWillHide', keyboardDidHide), + ); + } else { listeners.push( - KeyboardControllerPackage.KeyboardEvents.addListener('keyboardDidShow', keyboardDidShowKC), - KeyboardControllerPackage.KeyboardEvents.addListener('keyboardDidHide', keyboardDidHide), + Keyboard.addListener('keyboardDidShow', keyboardDidShowRN), + Keyboard.addListener('keyboardDidHide', keyboardDidHide), ); - } else if (Platform.OS === 'ios') { - listeners.push(Keyboard.addListener('keyboardWillShow', keyboardDidShowRN)); - listeners.push(Keyboard.addListener('keyboardWillHide', keyboardDidHide)); } return () => listeners.forEach((l) => l.remove()); diff --git a/package/src/contexts/componentsContext/defaultComponents.ts b/package/src/contexts/componentsContext/defaultComponents.ts index 6735fba586..4aac65dee5 100644 --- a/package/src/contexts/componentsContext/defaultComponents.ts +++ b/package/src/contexts/componentsContext/defaultComponents.ts @@ -50,7 +50,7 @@ import { ImageGalleryGrid } from '../../components/ImageGallery/components/Image import { EmptyStateIndicator } from '../../components/Indicators/EmptyStateIndicator'; import { LoadingErrorIndicator } from '../../components/Indicators/LoadingErrorIndicator'; import { LoadingIndicator } from '../../components/Indicators/LoadingIndicator'; -import { KeyboardCompatibleView } from '../../components/KeyboardCompatibleView/KeyboardControllerAvoidingView'; +import { KeyboardCompatibleView } from '../../components/KeyboardCompatibleView/KeyboardCompatibleView'; import { Message } from '../../components/Message/Message'; import { MessagePinnedHeader } from '../../components/Message/MessageItemView/Headers/MessagePinnedHeader'; import { MessageReminderHeader } from '../../components/Message/MessageItemView/Headers/MessageReminderHeader'; diff --git a/package/src/contexts/messageInputContext/MessageInputContext.tsx b/package/src/contexts/messageInputContext/MessageInputContext.tsx index af240756a0..dd6ad459ac 100644 --- a/package/src/contexts/messageInputContext/MessageInputContext.tsx +++ b/package/src/contexts/messageInputContext/MessageInputContext.tsx @@ -23,7 +23,7 @@ import { import { useCreateMessageInputContext } from './hooks/useCreateMessageInputContext'; import { useMessageComposer } from './hooks/useMessageComposer'; -import { dismissKeyboard } from '../../components/KeyboardCompatibleView/KeyboardControllerAvoidingView'; +import { dismissKeyboard } from '../../components/KeyboardCompatibleView/KeyboardCompatibleView'; import { parseLinksFromText } from '../../components/Message/MessageItemView/utils/parseLinks'; import { useAudioRecorder } from '../../components/MessageInput/hooks/useAudioRecorder'; import { useNotificationApi } from '../../components/Notifications'; diff --git a/package/src/hooks/useAfterKeyboardOpenCallback.ts b/package/src/hooks/useAfterKeyboardOpenCallback.ts index 199bd92cc4..9ac6a78a8e 100644 --- a/package/src/hooks/useAfterKeyboardOpenCallback.ts +++ b/package/src/hooks/useAfterKeyboardOpenCallback.ts @@ -3,7 +3,6 @@ import { EventSubscription, Keyboard, Platform } from 'react-native'; import { useStableCallback } from './useStableCallback'; -import { KeyboardControllerPackage } from '../components/KeyboardCompatibleView/KeyboardControllerAvoidingView'; import { useMessageInputContext } from '../contexts/messageInputContext/MessageInputContext'; /** @@ -50,9 +49,7 @@ export const useAfterKeyboardOpenCallback = ( const keyboardEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'; - keyboardSubscriptionRef.current = KeyboardControllerPackage?.KeyboardEvents - ? KeyboardControllerPackage.KeyboardEvents.addListener(keyboardEvent, runCallback) - : Keyboard.addListener(keyboardEvent, runCallback); + keyboardSubscriptionRef.current = Keyboard.addListener(keyboardEvent, runCallback); inputBoxRef.current.focus(); }); diff --git a/package/src/hooks/useKeyboardVisibility.ts b/package/src/hooks/useKeyboardVisibility.ts index cffd977b31..2218f6321a 100644 --- a/package/src/hooks/useKeyboardVisibility.ts +++ b/package/src/hooks/useKeyboardVisibility.ts @@ -1,7 +1,5 @@ import { useEffect, useState } from 'react'; -import { EventSubscription, Keyboard, Platform } from 'react-native'; - -import { KeyboardControllerPackage } from '../components/KeyboardCompatibleView/KeyboardControllerAvoidingView'; +import { Keyboard, Platform } from 'react-native'; /** * A custom hook that provides a boolean value indicating whether the keyboard is visible. @@ -11,30 +9,14 @@ export const useKeyboardVisibility = () => { const [isKeyboardVisible, setIsKeyboardVisible] = useState(false); useEffect(() => { - const listeners: EventSubscription[] = []; - if (KeyboardControllerPackage?.KeyboardEvents) { - listeners.push( - KeyboardControllerPackage.KeyboardEvents.addListener('keyboardWillShow', () => - setIsKeyboardVisible(true), - ), - ); - listeners.push( - KeyboardControllerPackage.KeyboardEvents.addListener('keyboardWillHide', () => - setIsKeyboardVisible(false), - ), - ); - } else { - listeners.push( - Keyboard.addListener(Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow', () => - setIsKeyboardVisible(true), - ), - ); - listeners.push( - Keyboard.addListener(Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide', () => - setIsKeyboardVisible(false), - ), - ); - } + const listeners = [ + Keyboard.addListener(Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow', () => + setIsKeyboardVisible(true), + ), + Keyboard.addListener(Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide', () => + setIsKeyboardVisible(false), + ), + ]; return () => listeners.forEach((listener) => listener.remove()); }, []); From 19e8452d4e0d3688cbff4d04b0c58502407a5391 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Tue, 19 May 2026 16:01:41 +0200 Subject: [PATCH 2/3] fix: update package.json --- examples/ExpoMessaging/package.json | 1 + examples/ExpoMessaging/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/ExpoMessaging/package.json b/examples/ExpoMessaging/package.json index a6b6998349..b57ba6ed16 100644 --- a/examples/ExpoMessaging/package.json +++ b/examples/ExpoMessaging/package.json @@ -47,6 +47,7 @@ "react-dom": "19.2.0", "react-native": "0.83.2", "react-native-gesture-handler": "~2.30.0", + "react-native-keyboard-controller": "1.20.7", "react-native-maps": "1.26.20", "react-native-reanimated": "4.2.1", "react-native-safe-area-context": "~5.6.2", diff --git a/examples/ExpoMessaging/yarn.lock b/examples/ExpoMessaging/yarn.lock index e4cd81d90e..d307548819 100644 --- a/examples/ExpoMessaging/yarn.lock +++ b/examples/ExpoMessaging/yarn.lock @@ -5526,10 +5526,10 @@ react-native-is-edge-to-edge@1.2.1, react-native-is-edge-to-edge@^1.2.1: resolved "https://registry.yarnpkg.com/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz#64e10851abd9d176cbf2b40562f751622bde3358" integrity sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q== -react-native-keyboard-controller@^1.21.7: - version "1.21.7" - resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.21.7.tgz#2e9c6ab2d309a81d678420dcaaa7314b0324d42d" - integrity sha512-gs+8nI8HYnRdDt4NWbk1iVuS6kDLf2taJvp+h/TjM1FBdtnQmlYLJ6buNiUqSnkIH4OFEAxdNr3/GOOYdLfkUQ== +react-native-keyboard-controller@1.20.7: + version "1.20.7" + resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.20.7.tgz#e1be1c15a5eb10b96a40a0812d8472e6e4bd8f29" + integrity sha512-G8S5jz1FufPrcL1vPtReATx+jJhT/j+sTqxMIb30b1z7cYEfMlkIzOCyaHgf6IMB2KA9uBmnA5M6ve2A9Ou4kw== dependencies: react-native-is-edge-to-edge "^1.2.1" From 85570ae678dae2b2f8874544ba20444aaf0e8904 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Tue, 19 May 2026 16:11:42 +0200 Subject: [PATCH 3/3] fix: bottom sheet modal listeners --- package/src/components/UIComponents/BottomSheetModal.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/package/src/components/UIComponents/BottomSheetModal.tsx b/package/src/components/UIComponents/BottomSheetModal.tsx index fd19576292..337f4d3f2a 100644 --- a/package/src/components/UIComponents/BottomSheetModal.tsx +++ b/package/src/components/UIComponents/BottomSheetModal.tsx @@ -380,11 +380,6 @@ const BottomSheetModalInner = (props: PropsWithChildren) Keyboard.addListener('keyboardWillShow', keyboardDidShowRN), Keyboard.addListener('keyboardWillHide', keyboardDidHide), ); - } else { - listeners.push( - Keyboard.addListener('keyboardDidShow', keyboardDidShowRN), - Keyboard.addListener('keyboardDidHide', keyboardDidHide), - ); } return () => listeners.forEach((l) => l.remove());