Skip to content

Commit

Permalink
swap paste button in output field (#5804)
Browse files Browse the repository at this point in the history
* paste

* remove console.log

* better

* colors

* ok

* review

* comment

* Revert "Lint on pre-commit (#5836)"

This reverts commit d56ed46.

* fix dupes

---------

Co-authored-by: Matthew Wall <[email protected]>
  • Loading branch information
greg-schrammel and walmat authored Jun 15, 2024
1 parent 47cbd3c commit 3de6fe7
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 60 deletions.
71 changes: 47 additions & 24 deletions src/__swaps__/screens/Swap/components/SearchInput.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
import { LIGHT_SEPARATOR_COLOR, SEPARATOR_COLOR, THICK_BORDER_WIDTH } from '@/__swaps__/screens/Swap/constants';
import { NavigationSteps, useSwapContext } from '@/__swaps__/screens/Swap/providers/swap-provider';
import { ExtendedAnimatedAssetWithColors } from '@/__swaps__/types/assets';
import { opacity } from '@/__swaps__/utils/swaps';
import { Input } from '@/components/inputs';
import { AnimatedText, Bleed, Box, Column, Columns, Text, useColorMode, useForegroundColor } from '@/design-system';
import * as i18n from '@/languages';
import { userAssetsStore } from '@/state/assets/userAssets';
import { useSwapsStore } from '@/state/swaps/swapsStore';
import Clipboard from '@react-native-clipboard/clipboard';
import React from 'react';
import Animated, {
SharedValue,
Expand All @@ -7,18 +17,10 @@ import Animated, {
useAnimatedReaction,
useAnimatedStyle,
useDerivedValue,
useSharedValue,
} from 'react-native-reanimated';
import { Input } from '@/components/inputs';
import { AnimatedText, Bleed, Box, Column, Columns, Text, useColorMode, useForegroundColor } from '@/design-system';
import { LIGHT_SEPARATOR_COLOR, SEPARATOR_COLOR, THICK_BORDER_WIDTH } from '@/__swaps__/screens/Swap/constants';
import { opacity } from '@/__swaps__/utils/swaps';
import { NavigationSteps, useSwapContext } from '@/__swaps__/screens/Swap/providers/swap-provider';
import { userAssetsStore } from '@/state/assets/userAssets';
import { ExtendedAnimatedAssetWithColors } from '@/__swaps__/types/assets';
import { GestureHandlerV1Button } from './GestureHandlerV1Button';
import { useDebouncedCallback } from 'use-debounce';
import { useSwapsStore } from '@/state/swaps/swapsStore';
import * as i18n from '@/languages';
import { GestureHandlerV1Button } from './GestureHandlerV1Button';

const AnimatedInput = Animated.createAnimatedComponent(Input);

Expand Down Expand Up @@ -55,25 +57,28 @@ export const SearchInput = ({
const labelQuaternary = useForegroundColor('labelQuaternary');

const btnText = useDerivedValue(() => {
if ((inputProgress.value === 2 && !output) || (outputProgress.value === 2 && output)) {
if (
(inputProgress.value === NavigationSteps.SEARCH_FOCUSED && !output) ||
(outputProgress.value === NavigationSteps.SEARCH_FOCUSED && output)
) {
return CANCEL_LABEL;
}

if ((output && internalSelectedOutputAsset.value) || !output) {
return CLOSE_LABEL;
}

// ⚠️ TODO: Add paste functionality to the asset to buy list when no asset is selected
// return PASTE_LABEL;
return PASTE_LABEL;
});

const buttonVisibilityStyle = useAnimatedStyle(() => {
const isSearchFocused = (output ? outputProgress : inputProgress).value === NavigationSteps.SEARCH_FOCUSED;
const isAssetSelected = output ? internalSelectedOutputAsset.value : internalSelectedInputAsset.value;
const isInputSearchFocused = inputProgress.value === NavigationSteps.SEARCH_FOCUSED;
const isInputAssetSelected = !!internalSelectedOutputAsset.value;
const isVisible = output || isInputSearchFocused || isInputAssetSelected;

return {
opacity: isSearchFocused || isAssetSelected ? 1 : 0,
pointerEvents: isSearchFocused || isAssetSelected ? 'auto' : 'none',
opacity: isVisible ? 1 : 0,
pointerEvents: isVisible ? 'auto' : 'none',
};
});

Expand All @@ -90,12 +95,12 @@ export const SearchInput = ({
(output && outputProgress.value === NavigationSteps.SEARCH_FOCUSED)
);

const pastedSearchInputValue = useSharedValue('');
const searchInputValue = useAnimatedProps(() => {
// Removing the value when the input is focused allows the input to be reset to the correct value on blur
const query = isSearchFocused.value ? undefined : '';

return {
text: query,
text: pastedSearchInputValue.value || query,
defaultValue: '',
};
});
Expand All @@ -104,12 +109,24 @@ export const SearchInput = ({
() => isSearchFocused.value,
(focused, prevFocused) => {
if (focused === false && prevFocused === true) {
pastedSearchInputValue.value = '';
if (output) runOnJS(onOutputSearchQueryChange)('');
else runOnJS(onInputSearchQueryChange)('');
}
}
);

const onPaste = () => {
Clipboard.getString().then(text => {
// to prevent users from mistakingly pasting long ass texts when copying the wrong thing
// we slice the string to 42 which is the size of a eth address,
// no token name query search should be that big anyway
const v = text.trim().slice(0, 42);
pastedSearchInputValue.value = v;
useSwapsStore.setState({ outputSearchQuery: v });
});
};

return (
<Box paddingHorizontal="20px" width="full">
<Columns alignHorizontal="justify" alignVertical="center" space="20px">
Expand Down Expand Up @@ -178,14 +195,20 @@ export const SearchInput = ({
<Column width="content">
<Animated.View style={buttonVisibilityStyle}>
<GestureHandlerV1Button
onPressJS={() => (output ? outputSearchRef : inputSearchRef).current?.blur()}
onPressJS={() => {
(output ? outputSearchRef : inputSearchRef).current?.blur();
}}
onPressWorklet={() => {
'worklet';
const isSearchFocused =
(output && outputProgress.value === NavigationSteps.SEARCH_FOCUSED) ||
(!output && inputProgress.value === NavigationSteps.SEARCH_FOCUSED);
if (output && outputProgress.value === NavigationSteps.TOKEN_LIST_FOCUSED && !internalSelectedOutputAsset.value) {
runOnJS(onPaste)();
}

if (isSearchFocused || (output && internalSelectedOutputAsset.value) || (!output && internalSelectedInputAsset.value)) {
if (
isSearchFocused.value ||
(output && internalSelectedOutputAsset.value) ||
(!output && internalSelectedInputAsset.value)
) {
handleExitSearchWorklet();
}
}}
Expand Down
33 changes: 18 additions & 15 deletions src/__swaps__/screens/Swap/hooks/useAnimatedSwapStyles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/* eslint-disable no-nested-ternary */
import { SharedValue, interpolate, useAnimatedStyle, withSpring, withTiming } from 'react-native-reanimated';
import { globalColors, useColorMode } from '@/design-system';
import {
BASE_INPUT_HEIGHT,
BOTTOM_ACTION_BAR_HEIGHT,
Expand All @@ -14,14 +12,17 @@ import {
fadeConfig,
springConfig,
} from '@/__swaps__/screens/Swap/constants';
import { getColorValueForThemeWorklet, opacityWorklet } from '@/__swaps__/utils/swaps';
import { SwapWarningType, useSwapWarning } from '@/__swaps__/screens/Swap/hooks/useSwapWarning';
import { ExtendedAnimatedAssetWithColors } from '@/__swaps__/types/assets';
import { getColorValueForThemeWorklet, opacityWorklet } from '@/__swaps__/utils/swaps';
import { spinnerExitConfig } from '@/components/animations/AnimatedSpinner';
import { NavigationSteps } from './useSwapNavigation';
import { globalColors, useColorMode } from '@/design-system';
import { foregroundColors } from '@/design-system/color/palettes';
import { IS_ANDROID } from '@/env';
import { safeAreaInsetValues } from '@/utils';
import { ExtendedAnimatedAssetWithColors } from '@/__swaps__/types/assets';
import { getSoftMenuBarHeight } from 'react-native-extra-dimensions-android';
import { SharedValue, interpolate, useAnimatedStyle, useDerivedValue, withSpring, withTiming } from 'react-native-reanimated';
import { NavigationSteps } from './useSwapNavigation';
import { ChainId } from '@/__swaps__/types/chains';

const INSET_BOTTOM = IS_ANDROID ? getSoftMenuBarHeight() - 24 : safeAreaInsetValues.bottom + 16;
Expand Down Expand Up @@ -213,9 +214,15 @@ export function useAnimatedSwapStyles({
};
});

const isPasteMode = useDerivedValue(
() => outputProgress.value === NavigationSteps.TOKEN_LIST_FOCUSED && !internalSelectedOutputAsset.value
);

const searchOutputAssetButtonStyle = useAnimatedStyle(() => {
const color = isPasteMode.value ? foregroundColors.blue : internalSelectedOutputAsset.value?.highContrastColor;

return {
color: getColorValueForThemeWorklet(internalSelectedOutputAsset.value?.highContrastColor, isDarkMode, true),
color: getColorValueForThemeWorklet(color, isDarkMode, true),
};
});

Expand Down Expand Up @@ -245,16 +252,12 @@ export function useAnimatedSwapStyles({
});

const searchOutputAssetButtonWrapperStyle = useAnimatedStyle(() => {
const color = isPasteMode.value ? foregroundColors.blue : internalSelectedOutputAsset.value?.highContrastColor;

return {
backgroundColor: opacityWorklet(
getColorValueForThemeWorklet(internalSelectedOutputAsset.value?.highContrastColor, isDarkMode, true),
isDarkMode ? 0.1 : 0.08
),
borderColor: opacityWorklet(
getColorValueForThemeWorklet(internalSelectedOutputAsset.value?.highContrastColor, isDarkMode, true),
isDarkMode ? 0.06 : 0.01
),
borderWidth: THICK_BORDER_WIDTH,
backgroundColor: opacityWorklet(getColorValueForThemeWorklet(color, isDarkMode, true), isDarkMode ? 0.1 : 0.08),
borderColor: opacityWorklet(getColorValueForThemeWorklet(color, isDarkMode, true), isDarkMode ? 0.06 : 0.01),
borderWidth: isPasteMode.value ? 0 : THICK_BORDER_WIDTH,
};
});

Expand Down
12 changes: 6 additions & 6 deletions src/__swaps__/utils/swaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ import {
} from '@/__swaps__/screens/Swap/constants';
import { chainNameFromChainId, chainNameFromChainIdWorklet } from '@/__swaps__/utils/chains';
import { ChainId, ChainName } from '@/__swaps__/types/chains';
import { RainbowConfig } from '@/model/remoteConfig';
import { CrosschainQuote, ETH_ADDRESS, Quote, QuoteParams, SwapType, WRAPPED_ASSET } from '@rainbow-me/swaps';
import { isLowerCaseMatch } from '@/__swaps__/utils/strings';
import { AddressOrEth, ExtendedAnimatedAssetWithColors, ParsedSearchAsset } from '../types/assets';
import { inputKeys } from '../types/swap';
import { swapsStore } from '../../state/swaps/swapsStore';
import { BigNumberish } from '@ethersproject/bignumber';
import { TokenColors } from '@/graphql/__generated__/metadata';
import { RainbowConfig } from '@/model/remoteConfig';
import { userAssetsStore } from '@/state/assets/userAssets';
import { colors } from '@/styles';
import { BigNumberish } from '@ethersproject/bignumber';
import { CrosschainQuote, ETH_ADDRESS, Quote, QuoteParams, SwapType, WRAPPED_ASSET } from '@rainbow-me/swaps';
import { swapsStore } from '../../state/swaps/swapsStore';
import { AddressOrEth, ExtendedAnimatedAssetWithColors, ParsedSearchAsset } from '../types/assets';
import { inputKeys } from '../types/swap';
import { convertAmountToRawAmount } from './numbers';
import {
ceilWorklet,
Expand Down
34 changes: 19 additions & 15 deletions src/design-system/color/palettes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export type BackgroundColorValue = {
mode: ColorMode;
};

export const backgroundColors: Record<BackgroundColor, BackgroundColorValue | ContextualColorValue<BackgroundColorValue>> = {
export const backgroundColors: Record<BackgroundColor, ContextualColorValue<BackgroundColorValue>> = {
'surfacePrimary': {
light: {
color: globalColors.white100,
Expand Down Expand Up @@ -400,8 +400,14 @@ export const backgroundColors: Record<BackgroundColor, BackgroundColorValue | Co
},
},
'swap (Deprecated)': {
color: deprecatedColors.swapPurple,
mode: 'darkTinted',
dark: {
color: deprecatedColors.swapPurple,
mode: 'darkTinted',
},
light: {
color: deprecatedColors.swapPurple,
mode: 'darkTinted',
},
},
};

Expand Down Expand Up @@ -462,13 +468,9 @@ export type ForegroundColor =
| 'blast'
| 'degen';

function selectBackgroundAsForeground(backgroundName: BackgroundColor): string | ContextualColorValue<string> {
function selectBackgroundAsForeground(backgroundName: BackgroundColor): ContextualColorValue<string> {
const bg = backgroundColors[backgroundName];

if ('color' in bg) {
return bg.color;
}

return {
dark: bg.dark.color,
light: bg.light.color,
Expand All @@ -477,7 +479,7 @@ function selectBackgroundAsForeground(backgroundName: BackgroundColor): string |
};
}

export const foregroundColors: Record<ForegroundColor, string | ContextualColorValue<string>> = {
export const foregroundColors: Record<ForegroundColor, ContextualColorValue<string>> = {
'label': {
light: globalColors.grey100,
dark: globalColors.white100,
Expand Down Expand Up @@ -632,12 +634,18 @@ export const foregroundColors: Record<ForegroundColor, string | ContextualColorV
darkTinted: deprecatedColors.white80,
light: deprecatedColors.grey80,
},
'shadowNear': globalColors.grey100,
'shadowNear': {
light: globalColors.grey100,
dark: globalColors.grey100,
},
'shadowFar': {
dark: globalColors.grey100,
light: '#25292E',
},
'swap (Deprecated)': deprecatedColors.swapPurple,
'swap (Deprecated)': {
light: deprecatedColors.swapPurple,
dark: deprecatedColors.swapPurple,
},
'mainnet': {
light: '#6D6D6D',
dark: '#999BA1',
Expand Down Expand Up @@ -715,10 +723,6 @@ export type Palette = {
function createPalette(colorMode: ColorMode): Palette {
return {
backgroundColors: mapValues(backgroundColors, value => {
if ('color' in value) {
return value;
}

if (colorMode === 'darkTinted') {
return value.darkTinted ?? value.dark;
}
Expand Down

0 comments on commit 3de6fe7

Please sign in to comment.