diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js --- a/native/chat/chat-input-bar.react.js +++ b/native/chat/chat-input-bar.react.js @@ -16,10 +16,14 @@ View, } from 'react-native'; import { TextInputKeyboardMangerIOS } from 'react-native-keyboard-input'; -import Animated, { - EasingNode, +import { + Easing, FadeInDown, FadeOutDown, + interpolate, + useAnimatedStyle, + useSharedValue, + withTiming, } from 'react-native-reanimated'; import { @@ -109,33 +113,19 @@ import type { ImagePasteEvent, LayoutEvent } from '../types/react-native.js'; import { AnimatedView, type ViewStyle } from '../types/styles.js'; import Alert from '../utils/alert.js'; -import { runTiming } from '../utils/animation-utils.js'; import { exitEditAlert } from '../utils/edit-messages-utils.js'; import { mentionTypeaheadTooltipActions, nativeMentionTypeaheadRegex, } from '../utils/typeahead-utils.js'; -const { - Value, - Clock, - block, - set, - cond, - neq, - sub, - interpolateNode, - stopClock, - useValue, -} = Animated; - const expandoButtonsAnimationConfig = { duration: 150, - easing: EasingNode.inOut(EasingNode.ease), + easing: Easing.inOut(Easing.ease), }; const sendButtonAnimationConfig = { duration: 150, - easing: EasingNode.inOut(EasingNode.ease), + easing: Easing.inOut(Easing.ease), }; const unboundStyles = { @@ -407,128 +397,36 @@ const isExitingDuringEditModeRef = React.useRef(false); - const expandoButtonsOpen = useValue(1); - const targetExpandoButtonsOpen = useValue(1); + const expandoButtonsOpen = useSharedValue(1); const initialSendButtonContainerOpen = trimMessage(draft) ? 1 : 0; - const sendButtonContainerOpen = useValue(initialSendButtonContainerOpen); - const targetSendButtonContainerOpen = useValue( + const sendButtonContainerOpen = useSharedValue( initialSendButtonContainerOpen, ); - const iconsOpacity = React.useMemo(() => { - const prevTargetExpandoButtonsOpen = new Value(1); - const expandoButtonClock = new Clock(); - return block([ - cond(neq(targetExpandoButtonsOpen, prevTargetExpandoButtonsOpen), [ - stopClock(expandoButtonClock), - set(prevTargetExpandoButtonsOpen, targetExpandoButtonsOpen), - ]), - cond( - neq(expandoButtonsOpen, targetExpandoButtonsOpen), - set( - expandoButtonsOpen, - runTiming( - expandoButtonClock, - expandoButtonsOpen, - targetExpandoButtonsOpen, - true, - expandoButtonsAnimationConfig, - ), - ), - ), - expandoButtonsOpen, - ]); - }, [expandoButtonsOpen, targetExpandoButtonsOpen]); - - const expandoButtonsWidth = React.useMemo( - () => - interpolateNode(iconsOpacity, { - inputRange: [0, 1], - outputRange: [26, 66], - }), - [iconsOpacity], - ); - - const expandOpacity = React.useMemo( - () => sub(1, iconsOpacity), - [iconsOpacity], - ); - - const sendButtonContainerWidth = React.useMemo(() => { - const prevTargetSendButtonContainerOpen = new Value( - initialSendButtonContainerOpen, - ); - const sendButtonClock = new Clock(); - const animatedSendButtonContainerOpen = block([ - cond( - neq(targetSendButtonContainerOpen, prevTargetSendButtonContainerOpen), - [ - stopClock(sendButtonClock), - set(prevTargetSendButtonContainerOpen, targetSendButtonContainerOpen), - ], - ), - cond( - neq(sendButtonContainerOpen, targetSendButtonContainerOpen), - set( - sendButtonContainerOpen, - runTiming( - sendButtonClock, - sendButtonContainerOpen, - targetSendButtonContainerOpen, - true, - sendButtonAnimationConfig, - ), - ), - ), - sendButtonContainerOpen, - ]); - - return interpolateNode(animatedSendButtonContainerOpen, { - inputRange: [0, 1], - outputRange: [4, 38], - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [sendButtonContainerOpen, targetSendButtonContainerOpen]); + const cameraRollIconStyle = useAnimatedStyle(() => ({ + ...unboundStyles.cameraRollIcon, + opacity: expandoButtonsOpen.value, + })); - const cameraRollIconStyle = React.useMemo( - () => ({ - ...unboundStyles.cameraRollIcon, - opacity: iconsOpacity, - }), - [iconsOpacity], - ); + const cameraIconStyle = useAnimatedStyle(() => ({ + ...unboundStyles.cameraIcon, + opacity: expandoButtonsOpen.value, + })); - const cameraIconStyle = React.useMemo( - () => ({ - ...unboundStyles.cameraIcon, - opacity: iconsOpacity, - }), - [iconsOpacity], - ); + const expandoButtonsStyle = useAnimatedStyle(() => ({ + ...unboundStyles.expandoButtons, + width: interpolate(expandoButtonsOpen.value, [0, 1], [26, 66]), + })); - const expandoButtonsStyle = React.useMemo( - () => ({ - ...unboundStyles.expandoButtons, - width: expandoButtonsWidth, - }), - [expandoButtonsWidth], - ); + const expandIconStyle = useAnimatedStyle(() => ({ + ...unboundStyles.expandIcon, + opacity: 1 - expandoButtonsOpen.value, + })); - const expandIconStyle = React.useMemo( - () => ({ - ...unboundStyles.expandIcon, - opacity: expandOpacity, - }), - [expandOpacity], - ); - - const sendButtonContainerStyle = React.useMemo( - () => ({ - width: sendButtonContainerWidth, - }), - [sendButtonContainerWidth], - ); + const sendButtonContainerStyle = useAnimatedStyle(() => ({ + width: interpolate(sendButtonContainerOpen.value, [0, 1], [4, 38]), + })); const shouldShowTextInput = React.useCallback(() => { if (currentUserIsVoiced) { @@ -554,32 +452,31 @@ }, [messageEditingContext?.editState, threadInfo.id]); const immediatelyShowSendButton = React.useCallback(() => { - sendButtonContainerOpen.setValue(1); - targetSendButtonContainerOpen.setValue(1); - }, [sendButtonContainerOpen, targetSendButtonContainerOpen]); + sendButtonContainerOpen.value = 1; + }, [sendButtonContainerOpen]); const updateSendButton = React.useCallback( (currentText: string) => { const targetValue = currentText === '' ? 0 : 1; - targetSendButtonContainerOpen.setValue(targetValue); - if (!shouldShowTextInput()) { - sendButtonContainerOpen.setValue(targetValue); + if (shouldShowTextInput()) { + sendButtonContainerOpen.value = withTiming( + targetValue, + sendButtonAnimationConfig, + ); + } else { + sendButtonContainerOpen.value = targetValue; } }, - [ - sendButtonContainerOpen, - shouldShowTextInput, - targetSendButtonContainerOpen, - ], + [sendButtonContainerOpen, shouldShowTextInput], ); const expandButtons = React.useCallback(() => { if (buttonsExpanded || isEditMode()) { return; } - targetExpandoButtonsOpen.setValue(1); + expandoButtonsOpen.value = withTiming(1, expandoButtonsAnimationConfig); setButtonsExpanded(true); - }, [buttonsExpanded, isEditMode, targetExpandoButtonsOpen]); + }, [buttonsExpanded, expandoButtonsOpen, isEditMode]); const hideButtons = React.useCallback(() => { if ( @@ -589,20 +486,19 @@ ) { return; } - targetExpandoButtonsOpen.setValue(0); + expandoButtonsOpen.value = withTiming(0, expandoButtonsAnimationConfig); setButtonsExpanded(false); }, [ buttonsExpanded, + expandoButtonsOpen, keyboardState?.mediaGalleryOpen, keyboardState?.systemKeyboardShowing, - targetExpandoButtonsOpen, ]); const immediatelyHideButtons = React.useCallback(() => { - expandoButtonsOpen.setValue(0); - targetExpandoButtonsOpen.setValue(0); + expandoButtonsOpen.value = 0; setButtonsExpanded(false); - }, [expandoButtonsOpen, targetExpandoButtonsOpen]); + }, [expandoButtonsOpen]); const textInputRef = React.useRef>(); const clearableTextInputRef = React.useRef();