Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/src/constants/screenNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ export enum ScreenNames {
KEYBOARD_EXTENDER = "KEYBOARD_EXTENDER",
CHAT_KIT = "CHAT_KIT",
AI_LEGEND_LIST_CHAT = "AI_LEGEND_LIST_CHAT",
KEYBOARD_EFFECTS = "KEYBOARD_EFFECTS",
}
7 changes: 7 additions & 0 deletions example/src/navigation/ExamplesStack/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import KeyboardAnimation from "../../screens/Examples/KeyboardAnimation";
import KeyboardAvoidingViewExample from "../../screens/Examples/KeyboardAvoidingView";
import KeyboardAvoidingViewAutomaticExample from "../../screens/Examples/KeyboardAvoidingViewAutomatic";
import KeyboardChatScrollViewPlayground from "../../screens/Examples/KeyboardChatScrollView";
import KeyboardEffectsExample from "../../screens/Examples/KeyboardEffects";
import KeyboardExtender from "../../screens/Examples/KeyboardExtender";
import KeyboardSharedTransitionExample from "../../screens/Examples/KeyboardSharedTransitions";
import UseKeyboardState from "../../screens/Examples/KeyboardStateHook";
Expand Down Expand Up @@ -62,6 +63,7 @@ export type ExamplesStackParamList = {
[ScreenNames.KEYBOARD_EXTENDER]: undefined;
[ScreenNames.CHAT_KIT]: undefined;
[ScreenNames.AI_LEGEND_LIST_CHAT]: undefined;
[ScreenNames.KEYBOARD_EFFECTS]: undefined;
};

const Stack = createStackNavigator<ExamplesStackParamList>();
Expand Down Expand Up @@ -208,6 +210,11 @@ const ExamplesStack = () => (
name={ScreenNames.AI_LEGEND_LIST_CHAT}
options={options[ScreenNames.AI_LEGEND_LIST_CHAT]}
/>
<Stack.Screen
component={KeyboardEffectsExample}
name={ScreenNames.KEYBOARD_EFFECTS}
options={options[ScreenNames.KEYBOARD_EFFECTS]}
/>
</Stack.Navigator>
);

Expand Down
3 changes: 3 additions & 0 deletions example/src/navigation/ExamplesStack/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,7 @@ export const options = {
[ScreenNames.AI_LEGEND_LIST_CHAT]: {
title: "AI LegendList Chat",
},
[ScreenNames.KEYBOARD_EFFECTS]: {
title: "Keyboard Effects",
},
};
150 changes: 150 additions & 0 deletions example/src/screens/Examples/KeyboardEffects/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import React, { useCallback, useMemo, useState } from "react";
import {
Image,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
import { KeyboardEffects } from "react-native-keyboard-controller";
import { SafeAreaView } from "react-native-safe-area-context";

const GIF_SOURCE = {
uri: "https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExbG1hdjU0bDBqZ3dha3NoNXF0YTY5ajNhNTdmMmV5azZsMHhlc21pMyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/dAWZiSMbMvObDWP3aA/giphy.gif",
};

const COLORS = [
"#FF6B6B",
"#4ECDC4",
"#45B7D1",
"#96CEB4",
"#FFEAA7",
"#DDA0DD",
];

type ColorButtonProps = {
color: string;
index: number;
selectedIndex: number;
onSelect: (index: number) => void;
};

const ColorButton = ({
color,
index,
selectedIndex,
onSelect,
}: ColorButtonProps) => {
const onPress = useCallback(() => onSelect(index), [index, onSelect]);
const buttonStyle = useMemo(
() => [
styles.colorButton,
{ backgroundColor: color },
index === selectedIndex && styles.selectedColor,
],
[color, index, selectedIndex],
);

return <TouchableOpacity style={buttonStyle} onPress={onPress} />;
};

const KeyboardEffectsExample = () => {
const [colorIndex, setColorIndex] = useState(0);
const [showGif, setShowGif] = useState(false);

const toggleGif = useCallback(() => setShowGif((v) => !v), []);

const colorEffectStyle = useMemo(
() => [styles.fill, { backgroundColor: COLORS[colorIndex] }],
[colorIndex],
);

return (
<>
<SafeAreaView style={styles.container}>
<View style={styles.controls}>
<View style={styles.colorPicker}>
{COLORS.map((color, index) => (
<ColorButton
key={color}
color={color}
index={index}
selectedIndex={colorIndex}
onSelect={setColorIndex}
/>
))}
</View>
<TouchableOpacity style={styles.toggleButton} onPress={toggleGif}>
<Text style={styles.toggleButtonText}>
{showGif ? "GIF" : "Color"}
</Text>
</TouchableOpacity>
</View>
<TextInput
placeholder="Tap to open keyboard..."
style={styles.textInput}
/>
</SafeAreaView>
<KeyboardEffects>
{showGif ? (
<Image source={GIF_SOURCE} style={styles.fill} />
) : (
<View style={colorEffectStyle} />
)}
</KeyboardEffects>
</>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "space-between",
},
controls: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: 12,
padding: 16,
},
colorPicker: {
flexDirection: "row",
gap: 12,
},
colorButton: {
width: 40,
height: 40,
borderRadius: 20,
},
selectedColor: {
borderWidth: 3,
borderColor: "#333",
},
toggleButton: {
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 20,
borderWidth: 2,
borderColor: "#ccc",
},
toggleButtonText: {
fontWeight: "600",
color: "#333",
},
textInput: {
height: 50,
paddingHorizontal: 16,
marginHorizontal: 16,
marginBottom: 16,
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
},
fill: {
flex: 1,
},
});

export default KeyboardEffectsExample;
6 changes: 6 additions & 0 deletions example/src/screens/Examples/Main/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,10 @@ export const examples: Example[] = [
info: ScreenNames.AI_LEGEND_LIST_CHAT,
icons: "🤖 💬",
},
{
title: "Keyboard Effects",
testID: "keyboard_effects",
info: ScreenNames.KEYBOARD_EFFECTS,
icons: "🌈",
},
];
63 changes: 63 additions & 0 deletions src/components/KeyboardEffects/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { forwardRef, useMemo } from "react";
import { Platform, View as RNView, StyleSheet } from "react-native";

import { KEYBOARD_BORDER_RADIUS } from "../../constants";
import KeyboardStickyView from "../KeyboardStickyView";

import type { KeyboardStickyViewProps } from "../KeyboardStickyView";
import type { View } from "react-native";

const KEYBOARD_HAS_ROUNDED_CORNERS =
Platform.OS === "ios" && parseInt(Platform.Version, 10) >= 26;

export type KeyboardEffectsProps = KeyboardStickyViewProps;

/**
* A component that renders content behind the keyboard. Since the keyboard
* is translucent, the content (colors, gradients, animations) will blend
* through and create visual effects on the keyboard.
*
* On iOS 26+ the keyboard has rounded corners, and the effect view
* automatically matches that shape.
*
* @returns A view component positioned behind the keyboard.
* @example
* ```tsx
* <KeyboardEffects>
* <View style={{ flex: 1, backgroundColor: "purple" }} />
* </KeyboardEffects>
* ```
*/
const KeyboardEffects = forwardRef<
View,
React.PropsWithChildren<KeyboardEffectsProps>
>(({ children, ...props }, ref) => {
const containerStyle = useMemo(
() => [styles.container, KEYBOARD_HAS_ROUNDED_CORNERS && styles.rounded],
[],
);

return (
<KeyboardStickyView ref={ref} {...props}>
<RNView style={containerStyle}>{children}</RNView>
</KeyboardStickyView>
);
});

const styles = StyleSheet.create({
container: {
position: "absolute",
bottom: 0,
top: 0,
left: 0,
right: 0,
height: 999,
},
rounded: {
borderTopLeftRadius: KEYBOARD_BORDER_RADIUS,
borderTopRightRadius: KEYBOARD_BORDER_RADIUS,
overflow: "hidden",
},
});

export default KeyboardEffects;
2 changes: 2 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export {
DefaultKeyboardToolbarTheme,
} from "./KeyboardToolbar";
export { default as KeyboardChatScrollView } from "./KeyboardChatScrollView";
export { default as KeyboardEffects } from "./KeyboardEffects";
export type { KeyboardAvoidingViewProps } from "./KeyboardAvoidingView";
export type { KeyboardStickyViewProps } from "./KeyboardStickyView";
export type { KeyboardEffectsProps } from "./KeyboardEffects";
export type {
KeyboardAwareScrollViewMode,
KeyboardAwareScrollViewProps,
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export {
// keyboard toolbar
KeyboardToolbar,
DefaultKeyboardToolbarTheme,
KeyboardEffects,
} from "./components";
export type {
KeyboardChatScrollViewProps,
Expand All @@ -24,5 +25,6 @@ export type {
KeyboardAwareScrollViewProps,
KeyboardAwareScrollViewRef,
KeyboardToolbarProps,
KeyboardEffectsProps,
} from "./components";
export { OverKeyboardView, KeyboardExtender } from "./views";
Loading