import BigNumber from 'bignumber.js' import React, { useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { Platform, TextInput as RNTextInput, StyleProp, StyleSheet, Text, View, ViewStyle, } from 'react-native' import SkeletonPlaceholder from 'react-native-skeleton-placeholder' import TextInput from 'src/components/TextInput' import TokenDisplay from 'src/components/TokenDisplay' import TokenIcon, { IconSize } from 'src/components/TokenIcon' import Touchable from 'src/components/Touchable' import DownArrowIcon from 'src/icons/DownArrowIcon' import { NETWORK_NAMES } from 'src/shared/conts' import Colors from 'src/styles/colors' import { typeScale } from 'src/styles/fonts' import { Spacing } from 'src/styles/styles' import { TokenBalance } from 'src/tokens/slice' interface Props { onInputChange?(value: string): void inputValue?: string | null parsedInputValue?: BigNumber | null onSelectToken(): void token?: TokenBalance loading: boolean autoFocus?: boolean inputError?: boolean style?: StyleProp buttonPlaceholder: string editable?: boolean borderRadius?: number } const SwapAmountInput = ({ onInputChange, inputValue, parsedInputValue, onSelectToken, token, loading, autoFocus, inputError, style, buttonPlaceholder, editable = true, borderRadius, }: Props) => { const { t } = useTranslation() // the startPosition and textInputRef variables exist to ensure TextInput // displays the start of the value for long values on Android // https://github.com/facebook/react-native/issues/14845 const [startPosition, setStartPosition] = useState(0) const textInputRef = useRef(null) const handleSetStartPosition = (value?: number) => { if (Platform.OS === 'android') { setStartPosition(value) } } const touchableBorderStyle = token ? { borderTopLeftRadius: borderRadius, borderTopRightRadius: borderRadius, } : borderRadius return ( {token ? ( {token.symbol} {t('swapScreen.onNetwork', { networkName: NETWORK_NAMES[token.networkId] })} ) : ( {buttonPlaceholder} )} {token && ( { handleSetStartPosition(undefined) onInputChange?.(value) }} value={inputValue || undefined} placeholder="0" // hide input when loading so that the value is not visible under the loader style={{ opacity: loading ? 0 : 1 }} editable={editable && !loading} keyboardType="decimal-pad" // Work around for RN issue with Samsung keyboards // https://github.com/facebook/react-native/issues/22005 autoCapitalize="words" autoFocus={autoFocus} // unset lineHeight to allow ellipsis on long inputs on iOS inputStyle={[styles.inputText, inputError ? styles.inputError : {}]} testID="SwapAmountInput/Input" onBlur={() => { handleSetStartPosition(0) }} onFocus={() => { handleSetStartPosition(inputValue?.length ?? 0) }} onSelectionChange={() => { handleSetStartPosition(undefined) }} selection={ Platform.OS === 'android' && typeof startPosition === 'number' ? { start: startPosition } : undefined } /> {loading && ( )} {!loading && parsedInputValue?.gt(0) && token && ( )} )} ) } const styles = StyleSheet.create({ container: { backgroundColor: Colors.backgroundSecondary, borderColor: Colors.borderPrimary, borderWidth: 1, }, tokenInfo: { alignItems: 'center', flexDirection: 'row', }, contentContainer: { height: 64, paddingHorizontal: Spacing.Regular16, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, bottomContainer: { borderColor: Colors.borderPrimary, borderTopWidth: 1, }, inputContainer: { flex: 1, }, inputError: { color: Colors.errorPrimary, }, inputText: { ...typeScale.titleSmall, fontSize: 26, lineHeight: undefined, paddingVertical: Spacing.Smallest8, }, loaderContainer: { paddingVertical: Spacing.Small12, }, loader: { height: '100%', width: '100%', }, tokenName: { ...typeScale.labelSemiBoldXSmall, paddingHorizontal: 4, }, tokenNetwork: { ...typeScale.bodyXSmall, color: Colors.contentSecondary, paddingHorizontal: 4, }, tokenInfoText: { paddingLeft: Spacing.Smallest8, }, tokenNamePlaceholder: { ...typeScale.labelMedium, paddingHorizontal: 4, color: Colors.contentSecondary, }, fiatValue: { ...typeScale.bodyXSmall, paddingLeft: Spacing.Smallest8, maxWidth: '40%', color: Colors.contentSecondary, paddingVertical: Spacing.Smallest8, }, }) export default SwapAmountInput