@@ -13,6 +13,8 @@ import { useMedia } from 'react-use'
1313import { useAllPairsInUniswap , useAllTokensInUniswap } from '../../contexts/GlobalData'
1414import { OVERVIEW_TOKEN_BLACKLIST , OVERVIEW_PAIR_BLACKLIST } from '../../constants'
1515
16+ import { useKeyPress } from '../../hooks'
17+
1618const Wrapper = styled . div `
1719 display: flex;
1820 position: relative;
@@ -68,7 +70,7 @@ const Menu = styled.div`
6870 width: 100%;
6971 top: 50px;
7072 max-height: 540px;
71- overflow: scroll;
73+ overflow-y : scroll;
7274 left: 0;
7375 padding-bottom: 20px;
7476 background: white;
@@ -89,6 +91,10 @@ const MenuItem = styled(Row)`
8991 cursor: pointer;
9092 background-color: #f7f8fa;
9193 }
94+ :focus {
95+ background-color: #f7f8fa;
96+ outline: black auto 1px;
97+ }
9298`
9399
94100const Heading = styled ( Row ) `
@@ -119,7 +125,13 @@ export const Search = ({ small = false }) => {
119125 const allPairs = useAllPairsInUniswap ( )
120126 const allPairData = useAllPairData ( )
121127
122- const [ showMenu , toggleMenu ] = useState ( false )
128+ const [ cursor , setCursor ] = useState ( null )
129+ const downKeyPressed = useKeyPress ( 'ArrowDown' )
130+ const escapeKeyPressed = useKeyPress ( 'Escape' )
131+ const tabKeyPressed = useKeyPress ( 'Tab' )
132+ const upKeyPressed = useKeyPress ( 'ArrowUp' )
133+
134+ const [ showMenu , setShowMenu ] = useState ( false )
123135 const [ value , setValue ] = useState ( '' )
124136 const [ , toggleShadow ] = useState ( false )
125137 const [ , toggleBottomShadow ] = useState ( false )
@@ -134,9 +146,9 @@ export const Search = ({ small = false }) => {
134146
135147 useEffect ( ( ) => {
136148 if ( value !== '' ) {
137- toggleMenu ( true )
149+ setShowMenu ( true )
138150 } else {
139- toggleMenu ( false )
151+ setShowMenu ( false )
140152 }
141153 } , [ value ] )
142154
@@ -278,10 +290,50 @@ export const Search = ({ small = false }) => {
278290 setPairsShown ( Math . min ( Object . keys ( filteredPairList ) . length , 3 ) )
279291 } , [ filteredPairList ] )
280292
293+ useEffect ( ( ) => {
294+ if ( pairsShown + tokensShown === 0 ) {
295+ setCursor ( undefined )
296+ } else if ( showMenu && downKeyPressed && cursor === undefined ) {
297+ setCursor ( 0 )
298+ } else if ( showMenu && downKeyPressed && cursor < pairsShown + tokensShown ) {
299+ setCursor ( cursor + 1 )
300+ }
301+ } , [ showMenu , downKeyPressed , pairsShown , tokensShown , cursor ] )
302+
303+ useEffect ( ( ) => {
304+ if ( pairsShown + tokensShown === 0 ) {
305+ setCursor ( undefined )
306+ } else if ( showMenu && upKeyPressed && cursor === undefined ) {
307+ setCursor ( pairsShown + tokensShown - 1 )
308+ } else if ( showMenu && upKeyPressed && cursor === 0 ) {
309+ setCursor ( pairsShown + tokensShown - 1 )
310+ } else if ( showMenu && upKeyPressed && cursor > 0 ) {
311+ setCursor ( cursor - 1 )
312+ }
313+ } , [ cursor , pairsShown , showMenu , tokensShown , upKeyPressed ] )
314+
315+ useEffect ( ( ) => {
316+ setCursor ( undefined )
317+ } , [ tabKeyPressed ] )
318+
319+ useEffect ( ( ) => {
320+ setCursor ( undefined )
321+ setShowMenu ( false )
322+ } , [ escapeKeyPressed ] )
323+
324+ useEffect ( ( ) => {
325+ const canUseCursor = Boolean (
326+ Number . isInteger ( cursor ) && menuRef . current && menuRef . current . querySelectorAll ( 'a' ) [ cursor ]
327+ )
328+ if ( canUseCursor ) {
329+ menuRef . current . querySelectorAll ( 'a' ) [ cursor ] . focus ( )
330+ }
331+ } , [ cursor ] )
332+
281333 function onDismiss ( ) {
282334 setPairsShown ( 3 )
283335 setTokensShown ( 3 )
284- toggleMenu ( false )
336+ setShowMenu ( false )
285337 setValue ( '' )
286338 }
287339
@@ -296,7 +348,7 @@ export const Search = ({ small = false }) => {
296348 ) {
297349 setPairsShown ( 3 )
298350 setTokensShown ( 3 )
299- toggleMenu ( false )
351+ setShowMenu ( false )
300352 }
301353 }
302354
@@ -338,7 +390,7 @@ export const Search = ({ small = false }) => {
338390 setValue ( e . target . value )
339391 } }
340392 onFocus = { ( ) => {
341- toggleMenu ( true )
393+ setShowMenu ( true )
342394 } }
343395 />
344396 </ Wrapper >
@@ -350,68 +402,51 @@ export const Search = ({ small = false }) => {
350402 < Heading >
351403 < Gray > Pairs</ Gray >
352404 </ Heading >
353- < div >
354- { filteredPairList && Object . keys ( filteredPairList ) . length === 0 && < MenuItem > No results</ MenuItem > }
355- { filteredPairList &&
356- filteredPairList . slice ( 0 , pairsShown ) . map ( pair => {
357- if ( pair ?. token0 ?. id === '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' ) {
358- pair . token0 . name = 'ETH (Wrapped)'
359- pair . token0 . symbol = 'ETH'
360- }
361- if ( pair ?. token1 . id === '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' ) {
362- pair . token1 . name = 'ETH (Wrapped)'
363- pair . token1 . symbol = 'ETH'
364- }
365- return (
366- < BasicLink to = { '/pair/' + pair . id } key = { pair . id } onClick = { onDismiss } >
367- < MenuItem >
368- < DoubleTokenLogo a0 = { pair ?. token0 ?. id } a1 = { pair ?. token1 ?. id } margin = { true } />
369- < span style = { { marginLeft : '10px' } } > { pair . token0 . symbol + '-' + pair . token1 . symbol } Pair</ span >
370- </ MenuItem >
371- </ BasicLink >
372- )
373- } ) }
374- < Heading
375- hide = { ! ( Object . keys ( filteredPairList ) . length > 3 && Object . keys ( filteredPairList ) . length >= pairsShown ) }
376- >
377- < Blue
378- onClick = { ( ) => {
379- setPairsShown ( pairsShown + 5 )
380- } }
381- >
382- See more...
383- </ Blue >
384- </ Heading >
385- </ div >
405+ { Object . keys ( filteredPairList ) . length === 0 && < MenuItem > No results</ MenuItem > }
406+ { filteredPairList . slice ( 0 , pairsShown ) . map ( pair => {
407+ if ( pair ?. token0 ?. id === '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' ) {
408+ pair . token0 . name = 'ETH (Wrapped)'
409+ pair . token0 . symbol = 'ETH'
410+ }
411+ if ( pair ?. token1 . id === '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' ) {
412+ pair . token1 . name = 'ETH (Wrapped)'
413+ pair . token1 . symbol = 'ETH'
414+ }
415+ return (
416+ < BasicLink to = { '/pair/' + pair . id } key = { pair . id } onClick = { onDismiss } >
417+ < MenuItem >
418+ < DoubleTokenLogo a0 = { pair ?. token0 ?. id } a1 = { pair ?. token1 ?. id } margin = { true } />
419+ < span style = { { marginLeft : '10px' } } > { pair . token0 . symbol + '-' + pair . token1 . symbol } Pair</ span >
420+ </ MenuItem >
421+ </ BasicLink >
422+ )
423+ } ) }
424+ < Heading
425+ hide = { ! ( Object . keys ( filteredPairList ) . length > 3 && Object . keys ( filteredPairList ) . length >= pairsShown ) }
426+ >
427+ < Blue onClick = { ( ) => setPairsShown ( pairsShown + 5 ) } > See more...</ Blue >
428+ </ Heading >
386429 < Heading >
387430 < Gray > Tokens</ Gray >
388431 </ Heading >
389- < div >
390- { Object . keys ( filteredTokenList ) . length === 0 && < MenuItem > No results</ MenuItem > }
391- { filteredTokenList . slice ( 0 , tokensShown ) . map ( token => {
392- return (
393- < BasicLink to = { '/token/' + token . id } key = { token . id } onClick = { onDismiss } >
394- < MenuItem >
395- < TokenLogo address = { token . id } style = { { marginRight : '10px' } } />
396- < span > { token . name } </ span >
397- < span > ({ token . symbol } )</ span >
398- </ MenuItem >
399- </ BasicLink >
400- )
401- } ) }
402-
403- < Heading
404- hide = { ! ( Object . keys ( filteredTokenList ) . length > 3 && Object . keys ( filteredTokenList ) . length >= tokensShown ) }
405- >
406- < Blue
407- onClick = { ( ) => {
408- setTokensShown ( tokensShown + 5 )
409- } }
410- >
411- See more...
412- </ Blue >
413- </ Heading >
414- </ div >
432+ { Object . keys ( filteredTokenList ) . length === 0 && < MenuItem > No results</ MenuItem > }
433+ { filteredTokenList . slice ( 0 , tokensShown ) . map ( token => {
434+ return (
435+ < BasicLink to = { '/token/' + token . id } key = { token . id } onClick = { onDismiss } >
436+ < MenuItem >
437+ < TokenLogo address = { token . id } style = { { marginRight : '10px' } } />
438+ < span > { token . name } </ span >
439+ < span > ({ token . symbol } )</ span >
440+ </ MenuItem >
441+ </ BasicLink >
442+ )
443+ } ) }
444+
445+ < Heading
446+ hide = { ! ( Object . keys ( filteredTokenList ) . length > 3 && Object . keys ( filteredTokenList ) . length >= tokensShown ) }
447+ >
448+ < Blue onClick = { ( ) => setTokensShown ( tokensShown + 5 ) } > See more...</ Blue >
449+ </ Heading >
415450 </ Menu >
416451 </ div >
417452 )
0 commit comments