Skip to content

Commit 949d5b5

Browse files
committed
feat: KeyboardEffects
1 parent ba41d5d commit 949d5b5

8 files changed

Lines changed: 165 additions & 0 deletions

File tree

example/src/constants/screenNames.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ export enum ScreenNames {
3030
KEYBOARD_EXTENDER = "KEYBOARD_EXTENDER",
3131
CHAT_KIT = "CHAT_KIT",
3232
AI_LEGEND_LIST_CHAT = "AI_LEGEND_LIST_CHAT",
33+
KEYBOARD_EFFECTS = "KEYBOARD_EFFECTS",
3334
}

example/src/navigation/ExamplesStack/index.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import KeyboardAnimation from "../../screens/Examples/KeyboardAnimation";
1616
import KeyboardAvoidingViewExample from "../../screens/Examples/KeyboardAvoidingView";
1717
import KeyboardAvoidingViewAutomaticExample from "../../screens/Examples/KeyboardAvoidingViewAutomatic";
1818
import KeyboardChatScrollViewPlayground from "../../screens/Examples/KeyboardChatScrollView";
19+
import KeyboardEffectsExample from "../../screens/Examples/KeyboardEffects";
1920
import KeyboardExtender from "../../screens/Examples/KeyboardExtender";
2021
import KeyboardSharedTransitionExample from "../../screens/Examples/KeyboardSharedTransitions";
2122
import UseKeyboardState from "../../screens/Examples/KeyboardStateHook";
@@ -62,6 +63,7 @@ export type ExamplesStackParamList = {
6263
[ScreenNames.KEYBOARD_EXTENDER]: undefined;
6364
[ScreenNames.CHAT_KIT]: undefined;
6465
[ScreenNames.AI_LEGEND_LIST_CHAT]: undefined;
66+
[ScreenNames.KEYBOARD_EFFECTS]: undefined;
6567
};
6668

6769
const Stack = createStackNavigator<ExamplesStackParamList>();
@@ -208,6 +210,11 @@ const ExamplesStack = () => (
208210
name={ScreenNames.AI_LEGEND_LIST_CHAT}
209211
options={options[ScreenNames.AI_LEGEND_LIST_CHAT]}
210212
/>
213+
<Stack.Screen
214+
component={KeyboardEffectsExample}
215+
name={ScreenNames.KEYBOARD_EFFECTS}
216+
options={options[ScreenNames.KEYBOARD_EFFECTS]}
217+
/>
211218
</Stack.Navigator>
212219
);
213220

example/src/navigation/ExamplesStack/options.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,7 @@ export const options = {
9494
[ScreenNames.AI_LEGEND_LIST_CHAT]: {
9595
title: "AI LegendList Chat",
9696
},
97+
[ScreenNames.KEYBOARD_EFFECTS]: {
98+
title: "Keyboard Effects",
99+
},
97100
};
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React, { useState } from "react";
2+
import { StyleSheet, TextInput, TouchableOpacity, View } from "react-native";
3+
import { KeyboardEffects } from "react-native-keyboard-controller";
4+
import { SafeAreaView } from "react-native-safe-area-context";
5+
6+
const COLORS = [
7+
"#FF6B6B",
8+
"#4ECDC4",
9+
"#45B7D1",
10+
"#96CEB4",
11+
"#FFEAA7",
12+
"#DDA0DD",
13+
];
14+
15+
const KeyboardEffectsExample = () => {
16+
const [colorIndex, setColorIndex] = useState(0);
17+
18+
return (
19+
<>
20+
<SafeAreaView style={styles.container}>
21+
<View style={styles.colorPicker}>
22+
{COLORS.map((color, index) => (
23+
<TouchableOpacity
24+
key={color}
25+
style={[
26+
styles.colorButton,
27+
{ backgroundColor: color },
28+
index === colorIndex && styles.selectedColor,
29+
]}
30+
onPress={() => setColorIndex(index)}
31+
/>
32+
))}
33+
</View>
34+
<TextInput
35+
placeholder="Tap to open keyboard..."
36+
style={styles.textInput}
37+
/>
38+
</SafeAreaView>
39+
<KeyboardEffects>
40+
<View
41+
style={[styles.effect, { backgroundColor: COLORS[colorIndex] }]}
42+
/>
43+
</KeyboardEffects>
44+
</>
45+
);
46+
};
47+
48+
const styles = StyleSheet.create({
49+
container: {
50+
flex: 1,
51+
justifyContent: "space-between",
52+
},
53+
colorPicker: {
54+
flexDirection: "row",
55+
justifyContent: "center",
56+
gap: 12,
57+
padding: 16,
58+
},
59+
colorButton: {
60+
width: 40,
61+
height: 40,
62+
borderRadius: 20,
63+
},
64+
selectedColor: {
65+
borderWidth: 3,
66+
borderColor: "#333",
67+
},
68+
textInput: {
69+
height: 50,
70+
paddingHorizontal: 16,
71+
marginHorizontal: 16,
72+
marginBottom: 16,
73+
borderWidth: 1,
74+
borderColor: "#ccc",
75+
borderRadius: 8,
76+
},
77+
effect: {
78+
flex: 1,
79+
},
80+
});
81+
82+
export default KeyboardEffectsExample;

example/src/screens/Examples/Main/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,10 @@ export const examples: Example[] = [
171171
info: ScreenNames.AI_LEGEND_LIST_CHAT,
172172
icons: "🤖 💬",
173173
},
174+
{
175+
title: "Keyboard Effects",
176+
testID: "keyboard_effects",
177+
info: ScreenNames.KEYBOARD_EFFECTS,
178+
icons: "🌈",
179+
},
174180
];
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React, { forwardRef, useMemo } from "react";
2+
import { Platform, StyleSheet, View as RNView } from "react-native";
3+
4+
import KeyboardStickyView from "../KeyboardStickyView";
5+
6+
import type { KeyboardStickyViewProps } from "../KeyboardStickyView";
7+
import type { View } from "react-native";
8+
9+
const KEYBOARD_HAS_ROUNDED_CORNERS =
10+
Platform.OS === "ios" && parseInt(Platform.Version, 10) >= 26;
11+
12+
export type KeyboardEffectsProps = KeyboardStickyViewProps;
13+
14+
/**
15+
* A component that renders content behind the keyboard. Since the keyboard
16+
* is translucent, the content (colors, gradients, animations) will blend
17+
* through and create visual effects on the keyboard.
18+
*
19+
* On iOS 26+ the keyboard has rounded corners, and the effect view
20+
* automatically matches that shape.
21+
*
22+
* @returns A view component positioned behind the keyboard.
23+
* @example
24+
* ```tsx
25+
* <KeyboardEffects>
26+
* <View style={{ flex: 1, backgroundColor: "purple" }} />
27+
* </KeyboardEffects>
28+
* ```
29+
*/
30+
const KeyboardEffects = forwardRef<
31+
View,
32+
React.PropsWithChildren<KeyboardEffectsProps>
33+
>(({ children, ...props }, ref) => {
34+
const containerStyle = useMemo(
35+
() => [styles.container, KEYBOARD_HAS_ROUNDED_CORNERS && styles.rounded],
36+
[],
37+
);
38+
39+
return (
40+
<KeyboardStickyView ref={ref} {...props}>
41+
<RNView style={containerStyle}>{children}</RNView>
42+
</KeyboardStickyView>
43+
);
44+
});
45+
46+
const styles = StyleSheet.create({
47+
container: {
48+
position: "absolute",
49+
bottom: 0,
50+
top: 0,
51+
left: 0,
52+
right: 0,
53+
height: 999,
54+
},
55+
rounded: {
56+
borderTopLeftRadius: 30,
57+
borderTopRightRadius: 30,
58+
overflow: "hidden",
59+
},
60+
});
61+
62+
export default KeyboardEffects;

src/components/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ export {
66
DefaultKeyboardToolbarTheme,
77
} from "./KeyboardToolbar";
88
export { default as KeyboardChatScrollView } from "./KeyboardChatScrollView";
9+
export { default as KeyboardEffects } from "./KeyboardEffects";
910
export type { KeyboardAvoidingViewProps } from "./KeyboardAvoidingView";
1011
export type { KeyboardStickyViewProps } from "./KeyboardStickyView";
12+
export type { KeyboardEffectsProps } from "./KeyboardEffects";
1113
export type {
1214
KeyboardAwareScrollViewProps,
1315
KeyboardAwareScrollViewRef,

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ export {
1515
// keyboard toolbar
1616
KeyboardToolbar,
1717
DefaultKeyboardToolbarTheme,
18+
KeyboardEffects,
1819
} from "./components";
1920
export type {
2021
KeyboardChatScrollViewProps,
2122
KeyboardAvoidingViewProps,
2223
KeyboardStickyViewProps,
24+
KeyboardEffectsProps,
2325
KeyboardAwareScrollViewProps,
2426
KeyboardAwareScrollViewRef,
2527
KeyboardToolbarProps,

0 commit comments

Comments
 (0)