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 @@ -145,8 +145,18 @@ nativeMentionTypeaheadRegex, } from '../utils/typeahead-utils.js'; -const { Value, Clock, block, set, cond, neq, sub, interpolateNode, stopClock } = - Animated; +const { + Value, + Clock, + block, + set, + cond, + neq, + sub, + interpolateNode, + stopClock, + useValue, +} = Animated; const expandoButtonsAnimationConfig = { duration: 150, @@ -316,6 +326,15 @@ +buttonsExpanded: boolean, +setButtonsExpanded: (expanded: boolean) => void, +isExitingDuringEditModeRef: { current: boolean }, + +expandoButtonsOpen: Value, + +targetExpandoButtonsOpen: Value, + +sendButtonContainerOpen: Value, + +targetSendButtonContainerOpen: Value, + +expandoButtonsStyle: AnimatedViewStyle, + +cameraRollIconStyle: AnimatedViewStyle, + +cameraIconStyle: AnimatedViewStyle, + +expandIconStyle: AnimatedViewStyle, + +sendButtonContainerStyle: AnimatedViewStyle, }; class ChatInputBar extends React.PureComponent { @@ -323,127 +342,10 @@ clearableTextInput: ?ClearableTextInput; selectableTextInput: ?React.ElementRef; - expandoButtonsOpen: Value; - targetExpandoButtonsOpen: Value; - expandoButtonsStyle: AnimatedViewStyle; - cameraRollIconStyle: AnimatedViewStyle; - cameraIconStyle: AnimatedViewStyle; - expandIconStyle: AnimatedViewStyle; - - sendButtonContainerOpen: Value; - targetSendButtonContainerOpen: Value; - sendButtonContainerStyle: AnimatedViewStyle; - clearBeforeRemoveListener: () => void; clearFocusListener: () => void; clearBlurListener: () => void; - constructor(props: Props) { - super(props); - this.setUpActionIconAnimations(); - this.setUpSendIconAnimations(); - } - - setUpActionIconAnimations() { - this.expandoButtonsOpen = new Value(1); - this.targetExpandoButtonsOpen = new Value(1); - const prevTargetExpandoButtonsOpen = new Value(1); - const expandoButtonClock = new Clock(); - const expandoButtonsOpen = block([ - cond(neq(this.targetExpandoButtonsOpen, prevTargetExpandoButtonsOpen), [ - stopClock(expandoButtonClock), - set(prevTargetExpandoButtonsOpen, this.targetExpandoButtonsOpen), - ]), - cond( - neq(this.expandoButtonsOpen, this.targetExpandoButtonsOpen), - set( - this.expandoButtonsOpen, - runTiming( - expandoButtonClock, - this.expandoButtonsOpen, - this.targetExpandoButtonsOpen, - true, - expandoButtonsAnimationConfig, - ), - ), - ), - this.expandoButtonsOpen, - ]); - - this.cameraRollIconStyle = { - ...unboundStyles.cameraRollIcon, - opacity: expandoButtonsOpen, - }; - this.cameraIconStyle = { - ...unboundStyles.cameraIcon, - opacity: expandoButtonsOpen, - }; - - const expandoButtonsWidth = interpolateNode(expandoButtonsOpen, { - inputRange: [0, 1], - outputRange: [26, 66], - }); - this.expandoButtonsStyle = { - ...unboundStyles.expandoButtons, - width: expandoButtonsWidth, - }; - - const expandOpacity = sub(1, expandoButtonsOpen); - this.expandIconStyle = { - ...unboundStyles.expandIcon, - opacity: expandOpacity, - }; - } - - setUpSendIconAnimations() { - const initialSendButtonContainerOpen = trimMessage(this.props.draft) - ? 1 - : 0; - this.sendButtonContainerOpen = new Value(initialSendButtonContainerOpen); - this.targetSendButtonContainerOpen = new Value( - initialSendButtonContainerOpen, - ); - const prevTargetSendButtonContainerOpen = new Value( - initialSendButtonContainerOpen, - ); - const sendButtonClock = new Clock(); - const sendButtonContainerOpen = block([ - cond( - neq( - this.targetSendButtonContainerOpen, - prevTargetSendButtonContainerOpen, - ), - [ - stopClock(sendButtonClock), - set( - prevTargetSendButtonContainerOpen, - this.targetSendButtonContainerOpen, - ), - ], - ), - cond( - neq(this.sendButtonContainerOpen, this.targetSendButtonContainerOpen), - set( - this.sendButtonContainerOpen, - runTiming( - sendButtonClock, - this.sendButtonContainerOpen, - this.targetSendButtonContainerOpen, - true, - sendButtonAnimationConfig, - ), - ), - ), - this.sendButtonContainerOpen, - ]); - - const sendButtonContainerWidth = interpolateNode(sendButtonContainerOpen, { - inputRange: [0, 1], - outputRange: [4, 38], - }); - this.sendButtonContainerStyle = { width: sendButtonContainerWidth }; - } - static mediaGalleryOpen(props: Props): boolean { const { keyboardState } = props; return !!(keyboardState && keyboardState.mediaGalleryOpen); @@ -459,15 +361,15 @@ } immediatelyShowSendButton() { - this.sendButtonContainerOpen.setValue(1); - this.targetSendButtonContainerOpen.setValue(1); + this.props.sendButtonContainerOpen.setValue(1); + this.props.targetSendButtonContainerOpen.setValue(1); } updateSendButton(currentText: string) { - if (this.shouldShowTextInput) { - this.targetSendButtonContainerOpen.setValue(currentText === '' ? 0 : 1); - } else { - this.setUpSendIconAnimations(); + const targetValue = currentText === '' ? 0 : 1; + this.props.targetSendButtonContainerOpen.setValue(targetValue); + if (!this.shouldShowTextInput) { + this.props.sendButtonContainerOpen.setValue(targetValue); } } @@ -775,7 +677,7 @@ activeOpacity={0.4} style={this.props.styles.expandButton} > - + - + {this.props.buttonsExpanded ? expandoButton : null} - + - + - + { + 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 = React.useMemo( + () => ({ + ...unboundStyles.cameraRollIcon, + opacity: iconsOpacity, + }), + [iconsOpacity], + ); + + const cameraIconStyle = React.useMemo( + () => ({ + ...unboundStyles.cameraIcon, + opacity: iconsOpacity, + }), + [iconsOpacity], + ); + + const expandoButtonsStyle = React.useMemo( + () => ({ + ...unboundStyles.expandoButtons, + width: expandoButtonsWidth, + }), + [expandoButtonsWidth], + ); + + const expandIconStyle = React.useMemo( + () => ({ + ...unboundStyles.expandIcon, + opacity: expandOpacity, + }), + [expandOpacity], + ); + + const sendButtonContainerStyle = React.useMemo( + () => ({ + width: sendButtonContainerWidth, + }), + [sendButtonContainerWidth], + ); + return ( ); }