Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-wombats-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@relayprotocol/relay-kit-ui': patch
---

Add same chain selector
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type ChainFilterSidebarProps = {
value: ChainFilterValue
isOpen: boolean
onSelect: (value: ChainFilterValue) => void
sameChainOption?: RelayChain
onAnalyticEvent?: (eventName: string, data?: any) => void
onInputRef?: (element: HTMLInputElement | null) => void
tokenSearchInputRef?: HTMLInputElement | null
Expand All @@ -57,6 +58,7 @@ export const ChainFilterSidebar: FC<ChainFilterSidebarProps> = ({
value,
isOpen,
onSelect,
sameChainOption,
onAnalyticEvent,
onInputRef,
tokenSearchInputRef,
Expand All @@ -74,6 +76,8 @@ export const ChainFilterSidebar: FC<ChainFilterSidebarProps> = ({
() => groupChains(options, popularChainIds, starredChainIds),
[options, popularChainIds, starredChainIds, isOpen]
)
const isSameChainSelected =
sameChainOption !== undefined && value.id === sameChainOption.id

const filteredChains = useMemo(() => {
if (chainSearchInput.trim() === '') {
Expand Down Expand Up @@ -120,20 +124,24 @@ export const ChainFilterSidebar: FC<ChainFilterSidebarProps> = ({
onSelect={(selectedValue) => {
if (selectedValue === 'input') return
if (selectedValue) {
const isSameChainSelection = selectedValue === 'same-chain'
const chain =
selectedValue === 'all-chains'
? { id: undefined, name: 'All Chains' }
: isSameChainSelection
? sameChainOption
: options.find(
(chain) => chain.id?.toString() === selectedValue
)
if (chain) {
onSelect(chain)
const fromStarredList =
!isSameChainSelection &&
chain.id !== undefined &&
starredChains.some((c) => c.id === chain.id)

onAnalyticEvent?.(EventNames.CURRENCY_STEP_CHAIN_FILTER, {
chain: chain.name,
chain: isSameChainSelection ? 'Same Chain' : chain.name,
chain_id: chain.id,
search_term: chainSearchInput,
context,
Expand Down Expand Up @@ -207,6 +215,51 @@ export const ChainFilterSidebar: FC<ChainFilterSidebarProps> = ({
key="all-chains"
onAnalyticEvent={onAnalyticEvent}
/>
{sameChainOption && (
<AccessibleListItem value="same-chain" asChild>
<Button
color="ghost"
size="none"
onClick={(e) => {
if (e.detail > 0) {
tokenSearchInputRef?.focus()
}
}}
ref={isSameChainSelected ? activeChainRef : null}
css={{
p: '2',
display: 'flex',
alignItems: 'center',
gap: '2',
position: 'relative',
...(isSameChainSelected && {
backgroundColor: 'gray6'
}),
transition: 'backdrop-filter 250ms linear',
_hover: {
backgroundColor:
isSameChainSelected
? 'gray6'
: 'gray/10'
},
'--focusColor': 'colors.focus-color',
_focus: {
boxShadow: 'inset 0 0 0 2px var(--focusColor)'
}
}}
>
<ChainIcon
chainId={sameChainOption.id}
square
width={24}
height={24}
/>
<Text style="subtitle1" ellipsify>
Same Chain
</Text>
</Button>
</AccessibleListItem>
)}
</>
)}

Expand Down Expand Up @@ -235,7 +288,9 @@ export const ChainFilterSidebar: FC<ChainFilterSidebarProps> = ({
</Flex>
{starredChains.map((chain) => {
const tag = 'tags' in chain ? chain.tags?.[0] : undefined
const active = value.id === chain.id
const active =
value.id === chain.id &&
!(isSameChainSelected && chain.id === sameChainOption?.id)
return chain.id ? (
<ChainFilterRow
chain={chain}
Expand Down Expand Up @@ -263,7 +318,9 @@ export const ChainFilterSidebar: FC<ChainFilterSidebarProps> = ({
</Text>
{alphabeticalChains.map((chain) => {
const tag = 'tags' in chain ? chain.tags?.[0] : undefined
const active = value.id === chain.id
const active =
value.id === chain.id &&
!(isSameChainSelected && chain.id === sameChainOption?.id)
return chain.id ? (
<ChainFilterRow
chain={chain}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import Tooltip from '../../../components/primitives/Tooltip.js'
type MobileChainSelectorProps = {
options: (RelayChain | { id: undefined; name: string })[]
value: ChainFilterValue
sameChainOption?: RelayChain
onSelect: (value: ChainFilterValue) => void
onBack: () => void
onClose: () => void
Expand All @@ -60,6 +61,7 @@ const fuseSearchOptions = {
export const MobileChainSelector: FC<MobileChainSelectorProps> = ({
options,
value,
sameChainOption,
onSelect,
onBack,
onClose,
Expand Down Expand Up @@ -96,26 +98,9 @@ export const MobileChainSelector: FC<MobileChainSelectorProps> = ({
const handleChainSelect = useCallback(
(chain: ChainFilterValue) => {
onSelect(chain)
const fromStarredList =
chain.id !== undefined && starredChains.some((c) => c.id === chain.id)

onAnalyticEvent?.(EventNames.CURRENCY_STEP_CHAIN_FILTER, {
chain: chain.name,
chain_id: chain.id,
search_term: chainSearchInput,
context,
from_starred_list: fromStarredList
})
onBack() // Go back to token view after selection
},
[
onSelect,
onAnalyticEvent,
chainSearchInput,
context,
starredChains,
onBack
]
[onSelect, onBack]
)

return (
Expand Down Expand Up @@ -203,13 +188,28 @@ export const MobileChainSelector: FC<MobileChainSelectorProps> = ({
<AccessibleList
onSelect={(selectedValue) => {
if (selectedValue) {
const isSameChainSelection = selectedValue === 'same-chain'
const chain =
selectedValue === 'all-chains'
? { id: undefined, name: 'All Chains' }
: isSameChainSelection
? sameChainOption
: options.find(
(chain) => chain.id?.toString() === selectedValue
)
if (chain) {
const fromStarredList =
!isSameChainSelection &&
chain.id !== undefined &&
starredChains.some((c) => c.id === chain.id)

onAnalyticEvent?.(EventNames.CURRENCY_STEP_CHAIN_FILTER, {
chain: isSameChainSelection ? 'Same Chain' : chain.name,
chain_id: chain.id,
search_term: chainSearchInput,
context,
from_starred_list: fromStarredList
})
handleChainSelect(chain)
}
}
Expand Down Expand Up @@ -248,6 +248,35 @@ export const MobileChainSelector: FC<MobileChainSelectorProps> = ({
onAnalyticEvent={onAnalyticEvent}
/>
)}
{sameChainOption && (
<AccessibleListItem value="same-chain" asChild>
<Button
color="ghost"
size="none"
css={{
py: '3',
px: '2',
display: 'flex',
alignItems: 'center',
gap: '2',
width: '100%',
height: '56px',
borderRadius: '12px',
_hover: {
backgroundColor: 'gray3'
}
}}
>
<ChainIcon
chainId={sameChainOption.id}
square
width={24}
height={24}
/>
<Text style="subtitle1">Same Chain</Text>
</Button>
</AccessibleListItem>
)}

{starredChains.length > 0 && (
<>
Expand Down
16 changes: 16 additions & 0 deletions packages/ui/src/components/common/TokenSelector/TokenSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export type TokenSelectorProps = {
trigger: ReactNode
chainIdsFilter?: number[]
lockedChainIds?: number[]
sameChainId?: number
context: 'from' | 'to'
address?: Address | string
isValidAddress?: boolean
Expand All @@ -74,6 +75,7 @@ const TokenSelector: FC<TokenSelectorProps> = ({
trigger,
chainIdsFilter,
lockedChainIds,
sameChainId,
context,
address,
isValidAddress,
Expand Down Expand Up @@ -177,6 +179,18 @@ const TokenSelector: FC<TokenSelectorProps> = ({
configuredChainIds.includes(chain.id)
)

const sameChainOption = useMemo(() => {
if (
context !== 'to' ||
sameChainId === undefined ||
isReceivingDepositAddress
) {
return undefined
}

return chainFilterOptions?.find((chain) => chain.id === sameChainId)
}, [context, sameChainId, isReceivingDepositAddress, chainFilterOptions])

const allChains = useMemo(
() => [
...(isReceivingDepositAddress
Expand Down Expand Up @@ -540,6 +554,7 @@ const TokenSelector: FC<TokenSelectorProps> = ({
<MobileChainSelector
options={allChains}
value={chainFilter}
sameChainOption={sameChainOption}
onSelect={(chain) => {
setChainFilter(chain)
setMobileView('tokens')
Expand Down Expand Up @@ -573,6 +588,7 @@ const TokenSelector: FC<TokenSelectorProps> = ({
value={chainFilter}
isOpen={open}
onSelect={setChainFilter}
sameChainOption={sameChainOption}
onAnalyticEvent={onAnalyticEvent}
onInputRef={setChainSearchInputElement}
tokenSearchInputRef={tokenSearchInputElement}
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/components/widgets/SwapWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,7 @@ const SwapWidget: FC<SwapWidgetProps> = ({
address={recipient}
isValidAddress={isValidToAddress}
token={toToken}
sameChainId={fromToken?.chainId}
fromChainWalletVMSupported={
fromChainWalletVMSupported
}
Expand Down