Skip to content
Draft
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
49 changes: 27 additions & 22 deletions FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
TouchableOpacity,
View,
} from "react-native";
import { KeyboardAvoidingView } from "react-native-keyboard-controller";
import {
KeyboardAvoidingView,
KeyboardLayout,
} from "react-native-keyboard-controller";

import Message from "../../../components/Message";
import { history } from "../../../components/Message/data";
Expand All @@ -30,31 +33,33 @@
return (
<>
<KeyboardAvoidingView
behavior="translate-with-padding"
behavior="padding"
keyboardVerticalOffset={headerHeight}
style={styles.container}
testID="flat-list.container"
>
<FlatList
ref={ref}
inverted
contentContainerStyle={styles.contentContainer}
data={reversedMessages}
initialNumToRender={15}
renderItem={RenderItem}
testID="flat-list.chat"
/>
<TextInput style={styles.textInput} testID="flat-list.input" />
<TouchableOpacity
activeOpacity={0.8}
style={styles.fab}
testID="flat-list.scrollToTop"
onPress={() => ref.current?.scrollToEnd()}
>
<View style={styles.circle}>
<Text style={styles.icon}>↑</Text>
</View>
</TouchableOpacity>
<KeyboardLayout>
<FlatList
ref={ref}
inverted
contentContainerStyle={styles.contentContainer}
data={reversedMessages}
initialNumToRender={15}
renderItem={RenderItem}
testID="flat-list.chat"
/>
</KeyboardLayout>
<TextInput style={styles.textInput} testID="flat-list.input" />

Check failure on line 52 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Delete `··`
<TouchableOpacity

Check failure on line 53 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Delete `··`
activeOpacity={0.8}

Check failure on line 54 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Delete `··`
style={styles.fab}

Check failure on line 55 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Delete `··`
testID="flat-list.scrollToTop"

Check failure on line 56 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Delete `··`
onPress={() => ref.current?.scrollToEnd()}

Check failure on line 57 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Replace `············` with `··········`
>

Check failure on line 58 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Delete `··`
<View style={styles.circle}>

Check failure on line 59 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Delete `··`
<Text style={styles.icon}>↑</Text>

Check failure on line 60 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Replace `··············` with `············`
</View>

Check failure on line 61 in FabricExample/src/screens/Examples/ReanimatedChatFlatList/index.tsx

View workflow job for this annotation

GitHub Actions / 🔎 Lint TS

Delete `··`
</TouchableOpacity>
</KeyboardAvoidingView>
</>
);
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"registry": "https://registry.npmjs.org/"
},
"dependencies": {
"react-freeze": "^1.0.4",
"react-native-is-edge-to-edge": "^1.2.1"
},
"devDependencies": {
Expand Down
111 changes: 111 additions & 0 deletions src/components/KeyboardLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React, { useCallback, useEffect, useState } from "react";
import { Freeze } from "react-freeze";
import { StyleSheet, View } from "react-native";

import { KeyboardEvents } from "../../bindings";

// Incomplete type, all accessible properties available at:
// react-native/Libraries/Components/View/фReactNativeViewViewConfig.js
interface ViewConfig extends View {
viewConfig: {
validAttributes: {
style: {
display: boolean | null;
};
};
};
_viewConfig: {
validAttributes: {
style: {
display: boolean | null;
};
};
};
}

/**
* A component that skips rendering its children when the keyboard is animating.
* Skipping these updates can help to deliver smoother animations.
*
* @param props - Properties of the component.
* @param props.children - Children of the component.
* @returns Children that skips rendering while keyboard is animating.
* @example
* ```
* <KeyboardAvoidingView behavior="padding">
* <KeyboardLayout>
* <FlatList />
* </KeyboardLayout>
* </KeyboardAvoidingView>
* ```
*/
const KeyboardLayout = (props: { children: React.ReactNode }) => {
const { children } = props;
const [isFrozen, setFrozen] = useState(false);

const handleRef = useCallback((ref: ViewConfig) => {
// Workaround is necessary to prevent React Native from hiding frozen screens.
// See this PR: https://github.com/grahammendick/navigation/pull/860
if (ref?.viewConfig?.validAttributes?.style) {
ref.viewConfig.validAttributes.style = {
...ref.viewConfig.validAttributes.style,
display: null,
};
} else if (ref?._viewConfig?.validAttributes?.style) {
ref._viewConfig.validAttributes.style = {
...ref._viewConfig.validAttributes.style,
display: null,
};
}
}, []);

useEffect(() => {
const willShowListener = KeyboardEvents.addListener(
"keyboardWillShow",
() => {
setFrozen(true);
},
);
const didHideListener = KeyboardEvents.addListener(
"keyboardDidHide",
() => {
setFrozen(false);
},
);
const willHideListener = KeyboardEvents.addListener(
"keyboardWillHide",
() => {
setFrozen(true);
},
);
const didShowListener = KeyboardEvents.addListener(
"keyboardDidShow",
() => {
setFrozen(false);
},
);

return () => {
willShowListener.remove();
didHideListener.remove();
willHideListener.remove();
didShowListener.remove();
};
}, []);

return (
<Freeze freeze={isFrozen}>
<View ref={handleRef} style={styles.flex}>
{children}
</View>
</Freeze>
);
};

const styles = StyleSheet.create({
flex: {
flex: 1,
},
});

export default KeyboardLayout;
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export {
default as KeyboardToolbar,
DefaultKeyboardToolbarTheme,
} from "./KeyboardToolbar";
export { default as KeyboardLayout } from "./KeyboardLayout";
export type { KeyboardAvoidingViewProps } from "./KeyboardAvoidingView";
export type { KeyboardStickyViewProps } from "./KeyboardStickyView";
export type { KeyboardAwareScrollViewProps } from "./KeyboardAwareScrollView";
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from "./module";
export * from "./types";

export {
KeyboardLayout,
KeyboardAvoidingView,
KeyboardStickyView,
KeyboardAwareScrollView,
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7330,6 +7330,11 @@ react-error-boundary@^3.1.0:
dependencies:
"@babel/runtime" "^7.12.5"

react-freeze@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.4.tgz#cbbea2762b0368b05cbe407ddc9d518c57c6f3ad"
integrity sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==

react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
Expand Down
Loading