fix(app): stop composer flickering during keyboard changes
Keep layout-only styles on stable React Native style IDs when they share Reanimated hosts with keyboard transforms. This prevents style regeneration from disturbing the animated native views while preserving keyboard and safe-area behavior.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef } from "react";
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
||||||
import { Keyboard, ScrollView, Text, View } from "react-native";
|
import { Keyboard, ScrollView, StyleSheet as RNStyleSheet, Text, View } from "react-native";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import ReanimatedAnimated from "react-native-reanimated";
|
import ReanimatedAnimated from "react-native-reanimated";
|
||||||
import { StyleSheet } from "react-native-unistyles";
|
import { StyleSheet } from "react-native-unistyles";
|
||||||
@@ -665,7 +665,11 @@ export function WorkspaceDraftAgentTab({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const inputAreaWrapperStyle = useMemo(
|
const inputAreaWrapperStyle = useMemo(
|
||||||
() => [styles.inputAreaWrapper, { paddingBottom: insets.bottom }, composerKeyboardStyle],
|
() => [
|
||||||
|
animatedStaticStyles.inputAreaWrapper,
|
||||||
|
{ paddingBottom: insets.bottom },
|
||||||
|
composerKeyboardStyle,
|
||||||
|
],
|
||||||
[insets.bottom, composerKeyboardStyle],
|
[insets.bottom, composerKeyboardStyle],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -772,6 +776,12 @@ export function WorkspaceDraftAgentTab({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const animatedStaticStyles = RNStyleSheet.create({
|
||||||
|
inputAreaWrapper: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const styles = StyleSheet.create((theme) => ({
|
const styles = StyleSheet.create((theme) => ({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -795,10 +805,6 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
configSection: {
|
configSection: {
|
||||||
gap: theme.spacing[3],
|
gap: theme.spacing[3],
|
||||||
},
|
},
|
||||||
inputAreaWrapper: {
|
|
||||||
width: "100%",
|
|
||||||
backgroundColor: theme.colors.surface0,
|
|
||||||
},
|
|
||||||
importPillRow: {
|
importPillRow: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
paddingHorizontal: theme.spacing[4],
|
paddingHorizontal: theme.spacing[4],
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
Pressable,
|
Pressable,
|
||||||
Text,
|
Text,
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
|
StyleSheet as RNStyleSheet,
|
||||||
type PressableStateCallbackType,
|
type PressableStateCallbackType,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import type { TFunction } from "i18next";
|
import type { TFunction } from "i18next";
|
||||||
@@ -1916,7 +1917,7 @@ export function Composer({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const composerContainerStyle = useMemo(
|
const composerContainerStyle = useMemo(
|
||||||
() => [styles.container, keyboardAnimatedStyle],
|
() => [animatedStaticStyles.container, keyboardAnimatedStyle],
|
||||||
[keyboardAnimatedStyle],
|
[keyboardAnimatedStyle],
|
||||||
);
|
);
|
||||||
const inputAreaContainerStyle = useMemo(
|
const inputAreaContainerStyle = useMemo(
|
||||||
@@ -2077,11 +2078,14 @@ export function Composer({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create((theme: Theme) => ({
|
const animatedStaticStyles = RNStyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const styles = StyleSheet.create((theme: Theme) => ({
|
||||||
borderSeparator: {
|
borderSeparator: {
|
||||||
height: theme.borderWidth[1],
|
height: theme.borderWidth[1],
|
||||||
backgroundColor: theme.colors.border,
|
backgroundColor: theme.colors.border,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import React, {
|
|||||||
useSyncExternalStore,
|
useSyncExternalStore,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ActivityIndicator, Text, View } from "react-native";
|
import { ActivityIndicator, StyleSheet as RNStyleSheet, Text, View } from "react-native";
|
||||||
import ReanimatedAnimated from "react-native-reanimated";
|
import ReanimatedAnimated from "react-native-reanimated";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import { StyleSheet, withUnistyles } from "react-native-unistyles";
|
import { StyleSheet, withUnistyles } from "react-native-unistyles";
|
||||||
@@ -1024,7 +1024,7 @@ function ChatAgentContent({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const animatedContentStyle = useMemo(
|
const animatedContentStyle = useMemo(
|
||||||
() => [styles.content, animatedKeyboardStyle],
|
() => [animatedStaticStyles.content, animatedKeyboardStyle],
|
||||||
[animatedKeyboardStyle],
|
[animatedKeyboardStyle],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1468,7 +1468,11 @@ function ActiveAgentComposer({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const inputAreaStyle = useMemo(
|
const inputAreaStyle = useMemo(
|
||||||
() => [styles.inputAreaWrapper, { paddingBottom: insets.bottom }, composerKeyboardStyle],
|
() => [
|
||||||
|
animatedStaticStyles.inputAreaWrapper,
|
||||||
|
{ paddingBottom: insets.bottom },
|
||||||
|
composerKeyboardStyle,
|
||||||
|
],
|
||||||
[insets.bottom, composerKeyboardStyle],
|
[insets.bottom, composerKeyboardStyle],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1593,6 +1597,15 @@ const foregroundColorMapping = (theme: Theme) => ({
|
|||||||
color: theme.colors.foreground,
|
color: theme.colors.foreground,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const animatedStaticStyles = RNStyleSheet.create({
|
||||||
|
content: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
inputAreaWrapper: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const styles = StyleSheet.create((theme) => ({
|
const styles = StyleSheet.create((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -1607,13 +1620,6 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
...(isWeb ? { userSelect: "none" as const } : {}),
|
...(isWeb ? { userSelect: "none" as const } : {}),
|
||||||
},
|
},
|
||||||
content: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
inputAreaWrapper: {
|
|
||||||
width: "100%",
|
|
||||||
backgroundColor: theme.colors.surface0,
|
|
||||||
},
|
|
||||||
historySyncOverlay: {
|
historySyncOverlay: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 0,
|
top: 0,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "r
|
|||||||
import type { ReactElement, RefObject } from "react";
|
import type { ReactElement, RefObject } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import type { TFunction } from "i18next";
|
import type { TFunction } from "i18next";
|
||||||
import { Pressable, Text, View } from "react-native";
|
import { Pressable, StyleSheet as RNStyleSheet, Text, View } from "react-native";
|
||||||
import type { PressableStateCallbackType } from "react-native";
|
import type { PressableStateCallbackType } from "react-native";
|
||||||
import ReanimatedAnimated from "react-native-reanimated";
|
import ReanimatedAnimated from "react-native-reanimated";
|
||||||
import { StyleSheet, useUnistyles, withUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles, withUnistyles } from "react-native-unistyles";
|
||||||
@@ -2034,7 +2034,7 @@ export function NewWorkspaceScreen({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const centeredStyle = useMemo(
|
const centeredStyle = useMemo(
|
||||||
() => [styles.centered, composerKeyboardStyle],
|
() => [animatedStaticStyles.centered, composerKeyboardStyle],
|
||||||
[composerKeyboardStyle],
|
[composerKeyboardStyle],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2163,6 +2163,13 @@ export function NewWorkspaceScreen({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const animatedStaticStyles = RNStyleSheet.create({
|
||||||
|
centered: {
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: MAX_CONTENT_WIDTH,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const styles = StyleSheet.create((theme) => ({
|
const styles = StyleSheet.create((theme) => ({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -2181,10 +2188,6 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
contentCompact: {
|
contentCompact: {
|
||||||
justifyContent: "flex-end",
|
justifyContent: "flex-end",
|
||||||
},
|
},
|
||||||
centered: {
|
|
||||||
width: "100%",
|
|
||||||
maxWidth: MAX_CONTENT_WIDTH,
|
|
||||||
},
|
|
||||||
composerTitleContainer: {
|
composerTitleContainer: {
|
||||||
marginBottom: theme.spacing[8],
|
marginBottom: theme.spacing[8],
|
||||||
paddingLeft: theme.spacing[6],
|
paddingLeft: theme.spacing[6],
|
||||||
|
|||||||
Reference in New Issue
Block a user