Open
Description
Description
When calling presentCustomInputComponent in iOS native code to display a custom keyboard, the following line in Objective-C:
RCTBridge* bridge = [self.bridge valueForKey:@"parentBridge"];
Related to
- Components
- Demo
- Docs
- Typings
Steps to reproduce
- Register a keyboard component using KeyboardRegistry.registerKeyboard("unicorn.ImagesKeyboard", () => ImagesKeyboard).
- Call CustomInputControllerTemp.presentCustomInputComponent(...) from JS.
- In native code (presentCustomInputComponent), parentBridge is nil.
- The keyboard view shows but is blank (white).
Expected behavior
Actual behavior
More Info
Code snippet
import React from "react"
import { ScrollView, StyleProp, ViewStyle } from "react-native"
import { Keyboard, View, Text, Image, Spacings } from "react-native-ui-lib"
import _ from "lodash"
const KeyboardRegistry = Keyboard.KeyboardRegistry
const images: string[] = [
"https://images.pexels.com/photos/1148521/pexels-photo-1148521.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=200",
"https://images.pexels.com/photos/1528975/pexels-photo-1528975.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=200",
"https://images.pexels.com/photos/1495580/pexels-photo-1495580.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=200",
"https://images.pexels.com/photos/943150/pexels-photo-943150.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=200",
"https://images.pexels.com/photos/1769408/pexels-photo-1769408.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=200",
]
function ImagesKeyboard() {
return (
<View flex>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ padding: Spacings.s4 } as StyleProp<ViewStyle>}
>
{images.map((image, i) => (
<Image
key={i}
source={{ uri: image }}
style={{ height: "100%", width: 200 }}
marginR-s4
/>
))}
</ScrollView>
</View>
)
}
function CustomKeyboard() {
return (
<View flex bg-violet80 center>
<Text h2>Custom Keyboard</Text>
</View>
)
}
// Register keyboards with registry
KeyboardRegistry.registerKeyboard("unicorn.ImagesKeyboard", () => ImagesKeyboard())
KeyboardRegistry.registerKeyboard("unicorn.CustomKeyboard", () => CustomKeyboard())
import { AppStackScreenProps } from "@/navigators"
import { observer } from "mobx-react-lite"
import React, { useCallback, useRef, useState } from "react"
import { StyleSheet, TextInput } from "react-native"
import {
Button,
Colors,
Constants,
Keyboard,
Spacings,
Switch,
Text,
View,
} from "react-native-ui-lib"
import "./CustomKeyboard"
const KeyboardAccessoryView = Keyboard.KeyboardAccessoryView
const KeyboardUtils = Keyboard.KeyboardUtils
const KeyboardRegistry = Keyboard.KeyboardRegistry
const TrackInteractive = true
const demoKeyboards = [
{
id: "unicorn.ImagesKeyboard",
},
{
id: "unicorn.CustomKeyboard",
},
]
export const ConversationDetailScreen = observer(
({ route }: AppStackScreenProps<"ConversationDetail">) => {
const [customKeyboard, setCustomKeyboard] = useState<any>({})
const [receivedKeyboardData, setReceivedKeyboardData] = useState<string | undefined>()
const [useSafeArea, setUseSafeArea] = useState<boolean>(true)
const [keyboardOpenState, setKeyboardOpenState] = useState<boolean>(false)
const [keyboardAccessoryViewHeight, setKeyboardAccessoryViewHeight] = useState<
number | undefined
>()
const textInputRef = useRef(null)
const textInputRef2 = useRef(null)
const onKeyboardItemSelected = useCallback((component?: string, args?: any) => {
const receivedData = `onItemSelected from "${component}"\nreceived params: ${JSON.stringify(args)}`
setReceivedKeyboardData(receivedData)
}, [])
const onKeyboardResigned = useCallback(() => {
resetKeyboardView()
}, [])
const isCustomKeyboardOpen = useCallback(() => {
return keyboardOpenState && !_.isEmpty(customKeyboard)
}, [keyboardOpenState, customKeyboard])
const resetKeyboardView = useCallback(() => {
setCustomKeyboard({})
}, [])
const dismissKeyboard = useCallback(() => {
KeyboardUtils.dismiss()
}, [])
const toggleUseSafeArea = useCallback(() => {
setUseSafeArea((prev) => !prev)
if (isCustomKeyboardOpen()) {
dismissKeyboard()
showLastKeyboard()
}
}, [isCustomKeyboardOpen, dismissKeyboard])
const showLastKeyboard = useCallback(() => {
setCustomKeyboard({})
setTimeout(() => {
setKeyboardOpenState(true)
setCustomKeyboard((prev: any) => ({ ...prev }))
}, 500)
}, [])
const showKeyboardView = useCallback((component: string, title?: string) => {
setKeyboardOpenState(true)
setCustomKeyboard({
component,
initialProps: { title },
})
}, [])
const onHeightChanged = useCallback((height: number) => {
if (Constants.isIOS) {
setKeyboardAccessoryViewHeight(height)
}
}, [])
const renderKeyboardAccessoryViewContent = useCallback(
() => (
<View style={styles.keyboardContainer} paddingV-s4>
<View bg-white row spread centerV paddingH-s5 paddingV-s3>
<TextInput ref={textInputRef} placeholder="Test" onFocus={resetKeyboardView} />
<Button link grey10 onPress={KeyboardUtils.dismiss} marginL-s2 label="Test" />
</View>
<View row paddingH-s4 marginT-s2 spread>
<View row>
{demoKeyboards.map((keyboard, index) => (
<Button
key={`${keyboard.id}_${index}`}
grey10
link
onPress={() => showKeyboardView(keyboard.id)}
marginR-s2
label="Test"
/>
))}
</View>
<Button grey10 label="Reset" link onPress={resetKeyboardView} />
</View>
</View>
),
[showKeyboardView, resetKeyboardView],
)
const requestShowKeyboard = useCallback(() => {
KeyboardRegistry.requestShowKeyboard("unicorn.ImagesKeyboard")
}, [])
const onRequestShowKeyboard = useCallback(() => {
setCustomKeyboard({
component: "unicorn.ImagesKeyboard",
initialProps: { title: "Keyboard 1 opened by button" },
})
}, [])
const safeAreaSwitchToggle = useCallback(() => {
if (!Constants.isIOS) {
return null
}
return (
<View center>
<View style={styles.separatorLine} />
<View centerV row margin-10>
<Text text80 grey40>
Safe Area Enabled:
</Text>
<Switch value={useSafeArea} onValueChange={toggleUseSafeArea} marginL-14 />
</View>
<View style={styles.separatorLine} />
</View>
)
}, [useSafeArea, toggleUseSafeArea])
return (
<View flex style={{ marginTop: 100 }}>
<Button
grey10
link
onPress={() => showKeyboardView("unicorn.ImagesKeyboard")}
label="Test213"
/>
<View flex>
<KeyboardAccessoryView
renderContent={renderKeyboardAccessoryViewContent}
onHeightChanged={onHeightChanged}
trackInteractive={TrackInteractive}
kbInputRef={textInputRef}
kbComponent={customKeyboard.component}
kbInitialProps={customKeyboard.initialProps}
onItemSelected={onKeyboardItemSelected}
onKeyboardResigned={onKeyboardResigned}
onRequestShowKeyboard={onRequestShowKeyboard}
useSafeArea={useSafeArea}
addBottomView={useSafeArea}
allowHitsOutsideBounds
/>
</View>
</View>
)
},
)
const styles = StyleSheet.create({
scrollContainer: {
paddingHorizontal: Spacings.s5,
flex: 1,
justifyContent: "center",
},
textField: {
flex: 1,
backgroundColor: Colors.grey60,
paddingVertical: Spacings.s2,
paddingHorizontal: Spacings.s4,
borderRadius: 8,
},
button: {
padding: Spacings.s2,
},
keyboardContainer: {
backgroundColor: Colors.white,
borderWidth: 1,
borderColor: Colors.grey60,
},
separatorLine: {
flex: 1,
height: 1,
backgroundColor: Colors.grey80,
},
})
Screenshots/Video
Environment
- React Native version: 0.76.9
- React Native UI Lib version: 7.44.0
Affected platforms
- Android
- iOS
- Web