diff --git a/native/chat/chat-thread-list-search.react.js b/native/chat/chat-thread-list-search.react.js --- a/native/chat/chat-thread-list-search.react.js +++ b/native/chat/chat-thread-list-search.react.js @@ -2,7 +2,13 @@ import * as React from 'react'; import { TextInput as BaseTextInput } from 'react-native'; -import Animated from 'react-native-reanimated'; +import Animated, { + useSharedValue, + interpolate, + useAnimatedStyle, + withTiming, + useDerivedValue, +} from 'react-native-reanimated'; import type { ReactRefSetter } from 'lib/types/react-types.js'; @@ -10,10 +16,7 @@ import Button from '../components/button.react.js'; import Search from '../components/search.react.js'; import { useStyles } from '../themes/colors.js'; -import { AnimatedView, type AnimatedStyleObj } from '../types/styles.js'; -import { animateTowards } from '../utils/animation-utils.js'; - -const { Node, Value, interpolateNode, useValue } = Animated; +import { AnimatedView } from '../types/styles.js'; type Props = { +searchText: string, @@ -40,48 +43,36 @@ } = props; const styles = useStyles(unboundStyles); - const searchCancelButtonOpen: Value = useValue(0); - const searchCancelButtonProgress: Node = React.useMemo( - () => animateTowards(searchCancelButtonOpen, 100), - [searchCancelButtonOpen], - ); - const searchCancelButtonOffset: Node = React.useMemo( - () => - interpolateNode(searchCancelButtonProgress, { - inputRange: [0, 1], - outputRange: [0, 56], - }), - [searchCancelButtonProgress], - ); - + const cancelButtonExpansion = useSharedValue(0); const isActiveOrActivating = searchStatus === 'active' || searchStatus === 'activating'; React.useEffect(() => { if (isActiveOrActivating) { - searchCancelButtonOpen.setValue(1); + cancelButtonExpansion.value = withTiming(1); } else { - searchCancelButtonOpen.setValue(0); + cancelButtonExpansion.value = withTiming(0); } - }, [isActiveOrActivating, searchCancelButtonOpen]); + }, [isActiveOrActivating, cancelButtonExpansion]); - const animatedSearchBoxStyle: AnimatedStyleObj = React.useMemo( - () => ({ - marginRight: searchCancelButtonOffset, - }), - [searchCancelButtonOffset], + const searchCancelButtonOffset = useDerivedValue(() => + interpolate(cancelButtonExpansion.value, [0, 1], [0, 56]), ); + const animatedSearchBoxStyle = useAnimatedStyle(() => ({ + marginRight: searchCancelButtonOffset.value, + })); + const searchBoxStyle = React.useMemo( () => [styles.searchBox, animatedSearchBoxStyle], [animatedSearchBoxStyle, styles.searchBox], ); + const animatedButtonStyle = useAnimatedStyle(() => ({ + opacity: cancelButtonExpansion.value, + })); const buttonStyle = React.useMemo( - () => [ - styles.cancelSearchButtonText, - { opacity: searchCancelButtonProgress }, - ], - [searchCancelButtonProgress, styles.cancelSearchButtonText], + () => [styles.cancelSearchButtonText, animatedButtonStyle], + [animatedButtonStyle, styles.cancelSearchButtonText], ); const innerSearchNode = React.useMemo( diff --git a/native/types/styles.js b/native/types/styles.js --- a/native/types/styles.js +++ b/native/types/styles.js @@ -5,6 +5,7 @@ import Animated, { type ReanimatedAnimationBuilder, type EntryExitAnimationFunction, + type SharedValue, } from 'react-native-reanimated'; import type { ViewStyleObj } from './react-native.js'; @@ -18,23 +19,25 @@ type ImageProps = React.ElementConfig; export type ImageStyle = $PropertyType; +type Value = ?number | Animated.Node | SharedValue; + export type ReanimatedTransform = { - +scale?: ?number | Animated.Node, - +translateX?: ?number | Animated.Node, - +translateY?: ?number | Animated.Node, + +scale?: Value, + +translateX?: Value, + +translateY?: Value, ... }; export type WritableAnimatedStyleObj = { ...ViewStyleObj, - opacity?: ?number | Animated.Node, - height?: ?number | Animated.Node, - width?: ?number | Animated.Node, - marginTop?: ?number | Animated.Node, - marginRight?: ?number | Animated.Node, - marginLeft?: ?number | Animated.Node, - backgroundColor?: ?string | Animated.Node, - bottom?: ?number | Animated.Node, + opacity?: Value, + height?: Value, + width?: Value, + marginTop?: Value, + marginRight?: Value, + marginLeft?: Value, + backgroundColor?: ?string | Animated.Node | SharedValue, + bottom?: Value, transform?: $ReadOnlyArray, ... };