Skip to content

Commit

Permalink
Merge pull request #305 from reservoirprotocol/ted/relay-5946-token-s…
Browse files Browse the repository at this point in the history
…election-keyboard-navigation

Token selector keyboard navigation
  • Loading branch information
ted-palmer authored Oct 21, 2024
2 parents 3f97073 + bd2fe32 commit 25c6216
Show file tree
Hide file tree
Showing 10 changed files with 709 additions and 398 deletions.
5 changes: 5 additions & 0 deletions .changeset/twenty-bananas-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@reservoir0x/relay-kit-ui': patch
---

Added keyboard navigation to token selector
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.0.7",
"@reservoir0x/relay-design-system": "workspace:^",
"@reservoir0x/relay-kit-hooks": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ const TokenSelector: FC<TokenSelectorProps> = ({
{tokenSelectorStep === TokenSelectorStep.SetCurrency ? (
<SetCurrencyStep
size={size}
inputElement={inputElement}
setInputElement={setInputElement}
tokenSearchInput={tokenSearchInput}
setTokenSearchInput={setTokenSearchInput}
Expand Down
200 changes: 121 additions & 79 deletions packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import {
Text,
Box,
Input,
ChainIcon
ChainIcon,
AccessibleList,
AccessibleListItem
} from '../../../primitives/index.js'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {
Expand Down Expand Up @@ -149,54 +151,78 @@ export const SetChainStep: FC<SetChainStepProps> = ({
>
Select Chain
</Text>
<Input
inputRef={(element) => {
setInputElement(element)
}}
placeholder="Search for a chain"
icon={
<Box css={{ color: 'gray9' }}>
<FontAwesomeIcon icon={faMagnifyingGlass} width={16} height={16} />
</Box>
}
containerCss={{ width: '100%', height: 40 }}
css={{
width: '100%',
_placeholder_parent: {
textOverflow: 'ellipsis'
<AccessibleList
onSelect={(value) => {
if (value && value !== 'input') {
const chain = filteredChains.find(
(chain) => chain.id.toString() === value
)
if (chain) {
const token = chain.isSupported
? (chain.currency as Currency)
: {
...chain.relayChain.currency,
metadata: {
logoURI: `https://assets.relay.link/icons/currencies/${chain.relayChain.currency?.id}.png`
}
}
selectToken(token, chain.id)
}
}
}}
value={chainSearchInput}
onChange={(e) =>
setChainSearchInput((e.target as HTMLInputElement).value)
}
/>

<Flex
direction={'column'}
css={{
display: isDesktop ? 'grid' : 'flex',
gridTemplateColumns: isDesktop ? 'repeat(2, minmax(0, 1fr))' : 'none',
gridColumnGap: isDesktop ? '8px' : '0',
gridAutoRows: 'min-content',
height: 350,
height: 370,
overflowY: 'auto',
pb: '2',
gap: isDesktop ? '0' : '2',
width: '100%'
width: '100%',
scrollSnapType: 'y mandatory',
scrollPaddingTop: '40px'
}}
>
{filteredChains?.map((chain) => {
const isSupported = chain.isSupported
const token = isSupported
? (chain.currency as Currency)
: {
...chain.relayChain.currency,
metadata: {
logoURI: `https://assets.relay.link/icons/currencies/${chain.relayChain.currency?.id}.png`
}
<AccessibleListItem value="input" asChild>
<Input
ref={setInputElement}
placeholder="Search for a chain"
icon={
<Box css={{ color: 'gray9' }}>
<FontAwesomeIcon
icon={faMagnifyingGlass}
width={16}
height={16}
/>
</Box>
}
containerCss={{
width: '100%',
height: 40,
scrollSnapAlign: 'start'
}}
style={{
gridColumn: isDesktop ? '1/3' : '',
marginBottom: isDesktop ? '10px' : '',
position: 'sticky',
top: 0,
zIndex: 1
}}
css={{
width: '100%',
_placeholder: {
textOverflow: 'ellipsis'
}
}}
value={chainSearchInput}
onChange={(e) =>
setChainSearchInput((e.target as HTMLInputElement).value)
}
/>
</AccessibleListItem>

{filteredChains?.map((chain) => {
const decimals = chain?.currency?.balance?.decimals ?? 18
const compactBalance = Boolean(
chain?.currency?.balance?.amount &&
Expand All @@ -205,57 +231,73 @@ export const SetChainStep: FC<SetChainStepProps> = ({
)

return (
<Button
<AccessibleListItem
key={chain.id}
color="ghost"
onClick={() => {
selectToken(token, chain.id)
}}
css={{
minHeight: 'auto',
gap: '2',
cursor: 'pointer',
px: '2',
py: '2',
transition: 'backdrop-filter 250ms linear',
_hover: {
backgroundColor: 'gray/10'
},
flexShrink: 0,
alignContent: 'center',
display: 'flex',
width: '100%'
}}
value={chain.id.toString()}
asChild
>
<ChainIcon
chainId={chain.id}
width={24}
height={24}
css={{ borderRadius: 4, overflow: 'hidden' }}
/>
<Flex direction="column" align="start">
<Text style="subtitle1">{chain.displayName}</Text>
<Button
color="ghost"
css={{
scrollSnapAlign: 'start',
minHeight: 'auto',
gap: '2',
cursor: 'pointer',
px: '2',
py: '2',
transition: 'backdrop-filter 250ms linear',
_hover: {
backgroundColor: 'gray/10'
},
flexShrink: 0,
alignContent: 'center',
display: 'flex',
width: '100%',
'--focusColor': 'colors.focus-color',
_focusVisible: {
boxShadow: 'inset 0 0 0 2px var(--focusColor)'
},
'&[data-state="on"]': {
boxShadow: 'inset 0 0 0 2px var(--focusColor)'
},
_active: {
boxShadow: 'inset 0 0 0 2px var(--focusColor)'
},
_focusWithin: {
boxShadow: 'inset 0 0 0 2px var(--focusColor)'
}
}}
>
<ChainIcon
chainId={chain.id}
width={24}
height={24}
css={{ borderRadius: 4, overflow: 'hidden' }}
/>
<Flex direction="column" align="start">
<Text style="subtitle1">{chain.displayName}</Text>

{type === 'token' ? (
<Text style="subtitle3" color="subtle">
{truncateAddress(chain?.currency?.address)}
{type === 'token' ? (
<Text style="subtitle3" color="subtle">
{truncateAddress(chain?.currency?.address)}
</Text>
) : null}
</Flex>
{chain?.currency?.balance?.amount ? (
<Text css={{ ml: 'auto' }} style="subtitle3" color="subtle">
{formatBN(
BigInt(chain?.currency?.balance?.amount),
5,
decimals,
compactBalance
)}
</Text>
) : null}
</Flex>
{chain?.currency?.balance?.amount ? (
<Text css={{ ml: 'auto' }} style="subtitle3" color="subtle">
{formatBN(
BigInt(chain?.currency?.balance?.amount),
5,
decimals,
compactBalance
)}
</Text>
) : null}
</Button>
</Button>
</AccessibleListItem>
)
})}
</Flex>
</AccessibleList>
</>
)
}
Loading

0 comments on commit 25c6216

Please sign in to comment.