Commit 4fe35ea4 authored by Zach Pomerantz's avatar Zach Pomerantz Committed by GitHub

fix: max on WebKit (#3349)

* chore: add walletconnect to cosmos

* fix: onClickMax for TokenInput

* chore: add setImmediate
parent 0d852b61
......@@ -69,14 +69,10 @@ export default function Input({ disabled, focused }: InputProps) {
const mockApproved = true
// account for gas needed if using max on native token
const maxAmount = useMemo(() => maxAmountSpend(balance), [balance])
const onMax = useMemo(() => {
if (maxAmount?.greaterThan(0)) {
return () => updateSwapInputAmount(maxAmount.toExact())
}
return
}, [maxAmount, updateSwapInputAmount])
const max = useMemo(() => {
const maxAmount = maxAmountSpend(balance)
return maxAmount?.greaterThan(0) ? maxAmount.toExact() : undefined
}, [balance])
const balanceColor = useMemo(() => {
const insufficientBalance =
......@@ -90,8 +86,8 @@ export default function Input({ disabled, focused }: InputProps) {
<TokenInput
currency={swapInputCurrency}
amount={(swapInputAmount !== undefined ? swapInputAmount : swapInputCurrencyAmount?.toSignificant(6)) ?? ''}
max={max}
disabled={disabled}
onMax={onMax}
onChangeInput={updateSwapInputAmount}
onChangeCurrency={updateSwapInputCurrency}
loading={isLoading}
......
import 'setimmediate'
import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import { loadingOpacityCss } from 'lib/css/loading'
import styled, { keyframes, ThemedText } from 'lib/theme'
import { FocusEvent, ReactNode, useCallback, useRef, useState } from 'react'
import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import Button from '../Button'
import Column from '../Column'
......@@ -50,8 +52,8 @@ const MaxButton = styled(Button)`
interface TokenInputProps {
currency?: Currency
amount: string
max?: string
disabled?: boolean
onMax?: () => void
onChangeInput: (input: string) => void
onChangeCurrency: (currency: Currency) => void
loading?: boolean
......@@ -61,38 +63,49 @@ interface TokenInputProps {
export default function TokenInput({
currency,
amount,
max,
disabled,
onMax,
onChangeInput,
onChangeCurrency,
loading,
children,
}: TokenInputProps) {
const max = useRef<HTMLButtonElement>(null)
const [showMax, setShowMax] = useState(false)
const onFocus = useCallback(() => setShowMax(Boolean(onMax)), [onMax])
const onBlur = useCallback((e: FocusEvent) => {
if (e.relatedTarget !== max.current && e.relatedTarget !== input.current) {
setShowMax(false)
}
}, [])
const input = useRef<HTMLInputElement>(null)
const onSelect = useCallback(
(currency: Currency) => {
onChangeCurrency(currency)
setTimeout(() => input.current?.focus(), 0)
setImmediate(() => input.current?.focus())
},
[onChangeCurrency]
)
const maxButton = useRef<HTMLButtonElement>(null)
const hasMax = useMemo(() => Boolean(max && max !== amount), [max, amount])
const [showMax, setShowMax] = useState<boolean>(hasMax)
useEffect(() => setShowMax((hasMax && input.current?.contains(document.activeElement)) ?? false), [hasMax])
const onBlur = useCallback((e) => {
// Filters out clicks on input or maxButton, because onBlur fires before onClickMax.
if (!input.current?.contains(e.relatedTarget) && !maxButton.current?.contains(e.relatedTarget)) {
setShowMax(false)
}
}, [])
const onClickMax = useCallback(() => {
onChangeInput(max || '')
setShowMax(false)
setImmediate(() => {
input.current?.focus()
// Brings the start of the input into view. NB: This only works for clicks, not eg keyboard interactions.
input.current?.setSelectionRange(0, null)
})
}, [max, onChangeInput])
return (
<Column gap={0.25}>
<TokenInputRow gap={0.5} onBlur={onBlur}>
<ThemedText.H2>
<ValueInput
value={amount}
onFocus={onFocus}
onFocus={() => setShowMax(hasMax)}
onChange={onChangeInput}
disabled={disabled || !currency}
$loading={Boolean(loading)}
......@@ -100,8 +113,9 @@ export default function TokenInput({
></ValueInput>
</ThemedText.H2>
{showMax && (
<MaxButton onClick={onMax} ref={max}>
<ThemedText.ButtonMedium>
<MaxButton onClick={onClickMax} ref={maxButton}>
{/* Without a tab index, Safari would not populate the FocusEvent.relatedTarget needed by onBlur. */}
<ThemedText.ButtonMedium tabIndex={-1}>
<Trans>Max</Trans>
</ThemedText.ButtonMedium>
</MaxButton>
......
import { initializeConnector } from '@web3-react/core'
import { MetaMask } from '@web3-react/metamask'
import { Connector } from '@web3-react/types'
import { WalletConnect } from '@web3-react/walletconnect'
import { SupportedChainId } from 'constants/chains'
import { INFURA_NETWORK_URLS } from 'constants/infura'
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from 'constants/locales'
import Widget from 'lib/components/Widget'
import { darkTheme, defaultTheme, lightTheme } from 'lib/theme'
import { ReactNode, useEffect, useMemo } from 'react'
import { ReactNode, useEffect, useState } from 'react'
import { useSelect, useValue } from 'react-cosmos/fixture'
export const [metaMask] = initializeConnector<MetaMask>((actions) => new MetaMask(actions))
const [metaMask] = initializeConnector<MetaMask>((actions) => new MetaMask(actions))
const [walletConnect] = initializeConnector<WalletConnect>(
(actions) => new WalletConnect(actions, { rpc: INFURA_NETWORK_URLS })
)
export default function Wrapper({ children }: { children: ReactNode }) {
const [width] = useValue('width', { defaultValue: 360 })
......@@ -27,21 +32,40 @@ export default function Wrapper({ children }: { children: ReactNode }) {
options: [NO_JSON_RPC, ...Object.values(INFURA_NETWORK_URLS).sort()],
})
const NO_PROVIDER = 'None'
const NO_CONNECTOR = 'None'
const META_MASK = 'MetaMask'
const [providerType] = useSelect('Provider', {
defaultValue: NO_PROVIDER,
options: [NO_PROVIDER, META_MASK],
const WALLET_CONNECT = 'WalletConnect'
const [connectorType] = useSelect('Provider', {
defaultValue: NO_CONNECTOR,
options: [NO_CONNECTOR, META_MASK, WALLET_CONNECT],
})
const provider = useMemo(() => {
switch (providerType) {
const [connector, setConnector] = useState<Connector>()
useEffect(() => {
let stale = false
activateConnector(connectorType)
return () => {
stale = true
}
async function activateConnector(connectorType: 'None' | 'MetaMask' | 'WalletConnect') {
let connector: Connector
switch (connectorType) {
case META_MASK:
metaMask.activate()
return metaMask.provider
default:
return undefined
await metaMask.activate()
connector = metaMask
break
case WALLET_CONNECT:
await walletConnect.activate()
connector = walletConnect
}
if (!stale) {
setConnector((oldConnector) => {
oldConnector?.deactivate?.()
return connector
})
}
}
}, [providerType])
}, [connectorType])
return (
<Widget
......@@ -49,7 +73,7 @@ export default function Wrapper({ children }: { children: ReactNode }) {
theme={theme}
locale={locale}
jsonRpcEndpoint={jsonRpcEndpoint === NO_JSON_RPC ? undefined : jsonRpcEndpoint}
provider={provider}
provider={connector?.provider}
>
{children}
</Widget>
......
......@@ -5648,6 +5648,13 @@
"@ethersproject/providers" "^5.4.5"
"@web3-react/types" "^8.0.16-alpha.0"
"@web3-react/walletconnect@8.0.16-alpha.0":
version "8.0.16-alpha.0"
resolved "https://registry.yarnpkg.com/@web3-react/walletconnect/-/walletconnect-8.0.16-alpha.0.tgz#63e69261ec0029db362bc740db90c7ed5c31c144"
integrity sha512-ZE1fuPw+rAirw4dTz+/bhgoZWv9opw+eu3XZuDeyee+IWd80U2GYHZtztyF+0RRTRm7A+dRfXx9I2tsnmoF1sw==
dependencies:
"@web3-react/types" "^8.0.16-alpha.0"
"@webassemblyjs/ast@1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment