Skip to content

Commit

Permalink
fix: max on WebKit (#3349)
Browse files Browse the repository at this point in the history
* chore: add walletconnect to cosmos

* fix: onClickMax for TokenInput

* chore: add setImmediate
  • Loading branch information
zzmp authored Feb 23, 2022
1 parent 0d852b6 commit 4fe35ea
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 41 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@uniswap/v3-core": "1.0.0",
"@uniswap/v3-periphery": "^1.1.1",
"@web3-react/metamask": "8.0.16-alpha.0",
"@web3-react/walletconnect": "8.0.16-alpha.0",
"web3-react-abstract-connector": "npm:@web3-react/abstract-connector@^6.0.7",
"web3-react-fortmatic-connector": "npm:@web3-react/fortmatic-connector@^6.0.9",
"web3-react-injected-connector": "npm:@web3-react/injected-connector@^6.0.7",
Expand Down Expand Up @@ -219,13 +221,13 @@
"react-window": "^1.8.5",
"rebass": "^4.0.7",
"redux": "^4.1.2",
"setimmediate": "^1.0.5",
"styled-components": "^5.3.0",
"tiny-invariant": "^1.2.0",
"wcag-contrast": "^3.0.0",
"@web3-react/core": "8.0.16-alpha.0",
"@web3-react/eip1193": "8.0.16-alpha.0",
"@web3-react/empty": "8.0.17-alpha.0",
"@web3-react/metamask": "8.0.16-alpha.0",
"@web3-react/types": "8.0.16-alpha.0",
"@web3-react/url": "8.0.17-alpha.0",
"wicg-inert": "^3.1.1"
Expand Down
14 changes: 5 additions & 9 deletions src/lib/components/Swap/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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}
Expand Down
46 changes: 30 additions & 16 deletions src/lib/components/Swap/TokenInput.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
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'
Expand Down Expand Up @@ -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
Expand All @@ -61,47 +63,59 @@ 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)}
ref={input}
></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>
Expand Down
54 changes: 39 additions & 15 deletions src/lib/cosmos/components/Widget.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
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 })
Expand All @@ -27,29 +32,48 @@ 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) {
case META_MASK:
metaMask.activate()
return metaMask.provider
default:
return undefined
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:
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
width={width}
theme={theme}
locale={locale}
jsonRpcEndpoint={jsonRpcEndpoint === NO_JSON_RPC ? undefined : jsonRpcEndpoint}
provider={provider}
provider={connector?.provider}
>
{children}
</Widget>
Expand Down
7 changes: 7 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5648,6 +5648,13 @@
"@ethersproject/providers" "^5.4.5"
"@web3-react/types" "^8.0.16-alpha.0"

"@web3-react/[email protected]":
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/[email protected]":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
Expand Down

0 comments on commit 4fe35ea

Please sign in to comment.