From 3b898fd63fc8fc5d6b5dc25e7c0a26d51553678a Mon Sep 17 00:00:00 2001 From: Jon Tzeng Date: Thu, 28 Nov 2024 17:06:09 -0800 Subject: [PATCH] Implement iOS "Cancel" button --- CHANGELOG.md | 1 + .../WalletListModal.test.tsx.snap | 484 ++++++++++------- ...reateWalletSelectCryptoScene.test.tsx.snap | 488 +++++++++++------- src/components/themed/SimpleTextInput.tsx | 180 ++++--- 4 files changed, 706 insertions(+), 447 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a270d16d0d..867693adc1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- changed: (iOS) `SimpleTextInput` back chevron replaced with "Cancel" button - added: `isBuiltInAsset` param for 'Exchange_Shift_Success' tracking event ## 4.17.2 diff --git a/src/__tests__/modals/__snapshots__/WalletListModal.test.tsx.snap b/src/__tests__/modals/__snapshots__/WalletListModal.test.tsx.snap index 807061b8050..7f6204ad04a 100644 --- a/src/__tests__/modals/__snapshots__/WalletListModal.test.tsx.snap +++ b/src/__tests__/modals/__snapshots__/WalletListModal.test.tsx.snap @@ -163,6 +163,8 @@ exports[`WalletListModal should render with loading props 1`] = ` + - - -  - - - -  +  - - - + + +  + + + + + + + + testID="undefined.clearIcon" + > + + +  + + + -  + Cancel diff --git a/src/__tests__/scenes/__snapshots__/CreateWalletSelectCryptoScene.test.tsx.snap b/src/__tests__/scenes/__snapshots__/CreateWalletSelectCryptoScene.test.tsx.snap index 370529d99b1..b6afe2599b3 100644 --- a/src/__tests__/scenes/__snapshots__/CreateWalletSelectCryptoScene.test.tsx.snap +++ b/src/__tests__/scenes/__snapshots__/CreateWalletSelectCryptoScene.test.tsx.snap @@ -296,6 +296,8 @@ exports[`CreateWalletSelectCrypto should render with loading props 1`] = ` + - - -  - - - -  +  - - - + + +  + + + + + + + + accessibilityValue={ + { + "max": undefined, + "min": undefined, + "now": undefined, + "text": undefined, + } + } + accessible={true} + collapsable={false} + focusable={true} + hitSlop={17} + onClick={[Function]} + onResponderGrant={[Function]} + onResponderMove={[Function]} + onResponderRelease={[Function]} + onResponderTerminate={[Function]} + onResponderTerminationRequest={[Function]} + onStartShouldSetResponder={[Function]} + style={ + { + "margin": -22, + "opacity": 1, + "padding": 22, + } + } + testID="undefined.clearIcon" + > + + +  + + + -  + Cancel diff --git a/src/components/themed/SimpleTextInput.tsx b/src/components/themed/SimpleTextInput.tsx index 8a641c881d2..631aac9c1a9 100644 --- a/src/components/themed/SimpleTextInput.tsx +++ b/src/components/themed/SimpleTextInput.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useMemo } from 'react' -import { TextInput, TouchableOpacity, View } from 'react-native' +import { Platform, TextInput, TouchableOpacity, View } from 'react-native' import Animated, { interpolate, interpolateColor, @@ -15,6 +15,7 @@ import Animated, { import { useHandler } from '../../hooks/useHandler' import { MarginRemProps, useMarginRemStyle } from '../../hooks/useMarginRemStyle' +import { lstrings } from '../../locales/strings' import { EdgeTouchableWithoutFeedback } from '../common/EdgeTouchableWithoutFeedback' import { styled, styledWithRef } from '../hoc/styled' import { AnimatedIconComponent, ChevronBackAnimated, CloseIconAnimated } from '../icons/ThemedIcons' @@ -172,7 +173,7 @@ export const SimpleTextInput = React.forwardRef interpolate(focusAnimation.value, [0, 1], [0, themeRem])) + const backIconSize = useDerivedValue(() => (Platform.OS === 'ios' ? 0 : interpolate(focusAnimation.value, [0, 1], [0, themeRem]))) const leftIconSize = useDerivedValue(() => (hasIcon ? (hasValue ? 0 : interpolate(focusAnimation.value, [0, 1], [themeRem, 0])) : 0)) const rightIconSize = useDerivedValue(() => (hasValue ? themeRem : focusAnimation.value * themeRem)) @@ -188,58 +189,71 @@ export const SimpleTextInput = React.forwardRef focus()}> - - {Icon == null ? null : } - - - - - - - - - - - - - - - - + + + {Icon == null ? null : } + + + + + + + + + + + + + + + + + {Platform.OS === 'ios' && ( + + + + {lstrings.string_cancel_cap} + + + + )} + ) }) const ContainerView = styled(View)({ - flexDirection: 'row' + flexDirection: 'row', + alignItems: 'center', + flex: 1 }) const InputContainerView = styled(Animated.View)<{ @@ -268,19 +282,23 @@ const InputContainerView = styled(Animated.View)<{ borderRadius: theme.rem(theme.textInputBorderRadius), flexDirection: 'row', flexGrow: 1, + flexShrink: 1, paddingHorizontal: theme.rem(1), paddingVertical: theme.rem(0.75) }, - useAnimatedStyle(() => ({ - backgroundColor: interpolateInputBackgroundColor(focusAnimation, disableAnimation), - borderColor: interpolateOutlineColor(focusAnimation, disableAnimation), - opacity: interpolate(scale.value, [1, 0.5], [1, 0]), - transform: [ - { - scale: interpolate(scale.value, [1, 0], [1, 0.75]) - } - ] - })) + useAnimatedStyle(() => { + 'worklet' + return { + backgroundColor: interpolateInputBackgroundColor(focusAnimation, disableAnimation), + borderColor: interpolateOutlineColor(focusAnimation, disableAnimation), + opacity: interpolate(scale.value, [1, 0.5], [1, 0]), + transform: [ + { + scale: interpolate(scale.value, [1, 0], [1, 0.75]) + } + ] + } + }) ] }) @@ -324,11 +342,55 @@ const InputField = styledWithRef(AnimatedTextInput)<{ }) const TouchContainer = styled(TouchableOpacity)(theme => ({ - // Increase tappable area with padding, while net 0 with negative margin to visually appear as if 0 margins/padding padding: theme.rem(1), margin: -theme.rem(1) })) +const CancelButton = styled(Animated.View)<{ + focusAnimation: SharedValue +}>(theme => ({ focusAnimation }) => { + const width = theme.rem(4) + return [ + { + marginLeft: theme.rem(0.5), + justifyContent: 'center', + alignItems: 'center', + height: theme.rem(3.5) + }, + useAnimatedStyle(() => { + 'worklet' + return { + width: interpolate(focusAnimation.value, [0, 1], [0, width]), + opacity: focusAnimation.value + } + }) + ] +}) + +const CancelText = styled(Animated.Text)<{ + focusAnimation: SharedValue +}>(theme => ({ focusAnimation }) => { + 'worklet' + return [ + { + color: theme.primaryText, + fontFamily: theme.fontFaceDefault, + fontSize: theme.rem(1), + includeFontPadding: false, + textAlign: 'center', + whiteSpace: 'nowrap', + minWidth: theme.rem(4), + flexShrink: 0 + }, + useAnimatedStyle(() => { + 'worklet' + return { + color: interpolateColor(focusAnimation.value, [0, 1], [theme.textInputIconColor, theme.textInputIconColorFocused]) + } + }) + ] +}) + function useAnimatedColorInterpolateFn(fromColor: string, toColor: string, disabledColor: string) { const interpolateFn = useMemo(() => { return (focusValue: SharedValue, disabledValue: SharedValue) => {