From 66cce53a516b01e0cf68950273e49c82e6fa8b21 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 23 Feb 2024 12:45:22 +0530 Subject: [PATCH 1/9] add reFocus prop to InputBase --- .../components/scaffold-eth/Input/InputBase.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx b/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx index 73d5a4f8a..b45549c00 100644 --- a/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx @@ -1,10 +1,11 @@ -import { ChangeEvent, ReactNode, useCallback } from "react"; +import { ChangeEvent, ReactNode, useCallback, useEffect, useRef } from "react"; import { CommonInputProps } from "~~/components/scaffold-eth"; type InputBaseProps = CommonInputProps & { error?: boolean; prefix?: ReactNode; suffix?: ReactNode; + reFocus?: boolean; }; export const InputBase = string } | undefined = string>({ @@ -16,7 +17,10 @@ export const InputBase = string } | undefined = str disabled, prefix, suffix, + reFocus, }: InputBaseProps) => { + const inputReft = useRef(null); + let modifier = ""; if (error) { modifier = "border-error"; @@ -31,6 +35,10 @@ export const InputBase = string } | undefined = str [onChange], ); + useEffect(() => { + if (reFocus) inputReft.current?.focus(); + }, [reFocus]); + return (
{prefix} @@ -42,6 +50,7 @@ export const InputBase = string } | undefined = str onChange={handleChange} disabled={disabled} autoComplete="off" + ref={inputReft} /> {suffix}
From 6ee3c8afcbc373912b592eee7224de61e15a4964 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 23 Feb 2024 12:47:58 +0530 Subject: [PATCH 2/9] increase debounce time and pass reFocus when error or null state --- .../scaffold-eth/Input/AddressInput.tsx | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx index 4f057015a..6857ba106 100644 --- a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx @@ -11,22 +11,30 @@ import { CommonInputProps, InputBase, isENS } from "~~/components/scaffold-eth"; export const AddressInput = ({ value, name, placeholder, onChange, disabled }: CommonInputProps
) => { // Debounce the input to keep clean RPC calls when resolving ENS names // If the input is an address, we don't need to debounce it - const _debouncedValue = useDebounce(value, 500); + const _debouncedValue = useDebounce(value, 900); const debouncedValue = isAddress(value) ? value : _debouncedValue; const isDebouncedValueLive = debouncedValue === value; // If the user changes the input after an ENS name is already resolved, we want to remove the stale result const settledValue = isDebouncedValueLive ? debouncedValue : undefined; - const { data: ensAddress, isLoading: isEnsAddressLoading } = useEnsAddress({ + const { + data: ensAddress, + isLoading: isEnsAddressLoading, + isError: ensAddressError, + } = useEnsAddress({ name: settledValue, - enabled: isENS(debouncedValue), + enabled: isDebouncedValueLive && isENS(debouncedValue), chainId: 1, cacheTime: 30_000, }); const [enteredEnsName, setEnteredEnsName] = useState(); - const { data: ensName, isLoading: isEnsNameLoading } = useEnsName({ + const { + data: ensName, + isLoading: isEnsNameLoading, + isError: ensNameError, + } = useEnsName({ address: settledValue as Address, enabled: isAddress(debouncedValue), chainId: 1, @@ -57,6 +65,7 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C [onChange], ); + const reFocus = ensAddressError || ensNameError || ensName === null || ensAddress === null; return ( name={name} @@ -65,8 +74,9 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C value={value as Address} onChange={handleChange} disabled={isEnsAddressLoading || isEnsNameLoading || disabled} + reFocus={reFocus} prefix={ - ensName && ( + ensName ? (
{ensAvatar ? ( @@ -78,6 +88,18 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C ) : null} {enteredEnsName ?? ensName}
+ ) : ( + (isEnsAddressLoading || isEnsNameLoading) && ( +
+
+
+
+
+ Resolving + +
+
+ ) ) } suffix={ From 69f68765828693683180f18bcd1cec036282d223 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 23 Feb 2024 12:53:55 +0530 Subject: [PATCH 3/9] remove deperecated useDebounce hook and use new one --- .../nextjs/components/scaffold-eth/Input/AddressInput.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx index 6857ba106..e92c65015 100644 --- a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from "react"; import { blo } from "blo"; -import { useDebounce } from "usehooks-ts"; +import { useDebounceValue } from "usehooks-ts"; import { Address, isAddress } from "viem"; import { useEnsAddress, useEnsAvatar, useEnsName } from "wagmi"; import { CommonInputProps, InputBase, isENS } from "~~/components/scaffold-eth"; @@ -11,7 +11,7 @@ import { CommonInputProps, InputBase, isENS } from "~~/components/scaffold-eth"; export const AddressInput = ({ value, name, placeholder, onChange, disabled }: CommonInputProps
) => { // Debounce the input to keep clean RPC calls when resolving ENS names // If the input is an address, we don't need to debounce it - const _debouncedValue = useDebounce(value, 900); + const [_debouncedValue] = useDebounceValue(value, 900); const debouncedValue = isAddress(value) ? value : _debouncedValue; const isDebouncedValueLive = debouncedValue === value; From 1052822a720f4c1ba6186b8579586f619bedd0fa Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 23 Feb 2024 12:58:26 +0530 Subject: [PATCH 4/9] refoucs on success --- .../nextjs/components/scaffold-eth/Input/AddressInput.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx index e92c65015..6eb20742e 100644 --- a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx @@ -22,6 +22,7 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C data: ensAddress, isLoading: isEnsAddressLoading, isError: ensAddressError, + isSuccess: ensAddressSuccess, } = useEnsAddress({ name: settledValue, enabled: isDebouncedValueLive && isENS(debouncedValue), @@ -34,6 +35,7 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C data: ensName, isLoading: isEnsNameLoading, isError: ensNameError, + isSuccess: ensNameSuccess, } = useEnsName({ address: settledValue as Address, enabled: isAddress(debouncedValue), @@ -65,7 +67,8 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C [onChange], ); - const reFocus = ensAddressError || ensNameError || ensName === null || ensAddress === null; + const reFocus = + ensAddressError || ensNameError || ensNameSuccess || ensAddressSuccess || ensName === null || ensAddress === null; return ( name={name} From 40c1ce209c7f45adb979835b2c4216a14290dfda Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 23 Feb 2024 13:41:35 +0530 Subject: [PATCH 5/9] update namig for booleans --- .../scaffold-eth/Input/AddressInput.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx index 6eb20742e..b501615f2 100644 --- a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx @@ -21,8 +21,8 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C const { data: ensAddress, isLoading: isEnsAddressLoading, - isError: ensAddressError, - isSuccess: ensAddressSuccess, + isError: isEnsAddressError, + isSuccess: isEnsAddressSuccess, } = useEnsAddress({ name: settledValue, enabled: isDebouncedValueLive && isENS(debouncedValue), @@ -34,8 +34,8 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C const { data: ensName, isLoading: isEnsNameLoading, - isError: ensNameError, - isSuccess: ensNameSuccess, + isError: isEnsNameError, + isSuccess: isEnsNameSuccess, } = useEnsName({ address: settledValue as Address, enabled: isAddress(debouncedValue), @@ -68,7 +68,13 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C ); const reFocus = - ensAddressError || ensNameError || ensNameSuccess || ensAddressSuccess || ensName === null || ensAddress === null; + isEnsAddressError || + isEnsNameError || + isEnsNameSuccess || + isEnsAddressSuccess || + ensName === null || + ensAddress === null; + return ( name={name} From c2f1cf3640d6cf6599f96d70a7c42e0e68955916 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Sat, 24 Feb 2024 01:10:47 +0530 Subject: [PATCH 6/9] fix refocus in b/w address --- .../components/scaffold-eth/Input/InputBase.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx b/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx index b45549c00..ae9b0c5d9 100644 --- a/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, ReactNode, useCallback, useEffect, useRef } from "react"; +import { ChangeEvent, FocusEvent, ReactNode, useCallback, useEffect, useRef } from "react"; import { CommonInputProps } from "~~/components/scaffold-eth"; type InputBaseProps = CommonInputProps & { @@ -35,8 +35,16 @@ export const InputBase = string } | undefined = str [onChange], ); + // Runs only when reFocus prop is passed, usefull for setting the cursor + // at the end of the input. Example AddressInput + const onFocus = (e: FocusEvent) => { + if (reFocus !== undefined) { + console.log("Running OnFocus", reFocus); + e.currentTarget.setSelectionRange(e.currentTarget.value.length, e.currentTarget.value.length); + } + }; useEffect(() => { - if (reFocus) inputReft.current?.focus(); + if (reFocus !== undefined && reFocus === true) inputReft.current?.focus(); }, [reFocus]); return ( @@ -51,6 +59,7 @@ export const InputBase = string } | undefined = str disabled={disabled} autoComplete="off" ref={inputReft} + onFocus={onFocus} /> {suffix} From 6efd33101fbdc0b34e1921e3e48e7ea9f61a4a2e Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Sat, 24 Feb 2024 01:36:42 +0530 Subject: [PATCH 7/9] use skeleton for showing loading UI --- .../scaffold-eth/Input/AddressInput.tsx | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx index b501615f2..d12184573 100644 --- a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx @@ -43,7 +43,7 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C cacheTime: 30_000, }); - const { data: ensAvatar } = useEnsAvatar({ + const { data: ensAvatar, isLoading: isEnsAvtarLoading } = useEnsAvatar({ name: ensName, enabled: Boolean(ensName), chainId: 1, @@ -87,6 +87,7 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C prefix={ ensName ? (
+ {isEnsAvtarLoading &&
} {ensAvatar ? ( { @@ -98,15 +99,10 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C {enteredEnsName ?? ensName}
) : ( - (isEnsAddressLoading || isEnsNameLoading) && ( -
-
-
-
-
- Resolving - -
+ (isEnsNameLoading || isEnsAddressLoading) && ( +
+
+
) ) From 2d04a93c436f85a6299e398b81d0bafd1eecd4dc Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Sat, 24 Feb 2024 01:41:34 +0530 Subject: [PATCH 8/9] remove console.log --- packages/nextjs/components/scaffold-eth/Input/InputBase.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx b/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx index ae9b0c5d9..f38bca217 100644 --- a/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx @@ -39,7 +39,6 @@ export const InputBase = string } | undefined = str // at the end of the input. Example AddressInput const onFocus = (e: FocusEvent) => { if (reFocus !== undefined) { - console.log("Running OnFocus", reFocus); e.currentTarget.setSelectionRange(e.currentTarget.value.length, e.currentTarget.value.length); } }; From 15cfdbfe309aa4192e7d770c17133719bc794b79 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Sat, 24 Feb 2024 01:50:01 +0530 Subject: [PATCH 9/9] revert debounce timming to 500 --- packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx index d12184573..164664466 100644 --- a/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +++ b/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx @@ -11,7 +11,7 @@ import { CommonInputProps, InputBase, isENS } from "~~/components/scaffold-eth"; export const AddressInput = ({ value, name, placeholder, onChange, disabled }: CommonInputProps
) => { // Debounce the input to keep clean RPC calls when resolving ENS names // If the input is an address, we don't need to debounce it - const [_debouncedValue] = useDebounceValue(value, 900); + const [_debouncedValue] = useDebounceValue(value, 500); const debouncedValue = isAddress(value) ? value : _debouncedValue; const isDebouncedValueLive = debouncedValue === value;