Skip to content

Commit e8f9816

Browse files
authored
Focus Opcode-Search on Alt+K (#278)
1 parent 080c358 commit e8f9816

2 files changed

Lines changed: 80 additions & 49 deletions

File tree

components/Reference/Filters.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useMemo, useEffect } from 'react'
1+
import { useState, useMemo, useEffect, useRef } from 'react'
22

33
import debounce from 'lodash.debounce'
44
import { useRouter } from 'next/router'
@@ -33,6 +33,8 @@ const Filters = ({ onSetFilter, isPrecompiled = false }: Props) => {
3333
[isPrecompiled],
3434
)
3535

36+
const inputRef = useRef<HTMLInputElement>(null)
37+
3638
const handleKeywordChange = debounce(
3739
(value: string) => onSetFilter(searchFilter.value, value),
3840
debounceTimeout,
@@ -45,6 +47,13 @@ const Filters = ({ onSetFilter, isPrecompiled = false }: Props) => {
4547
setSearchFilter(option)
4648
}
4749

50+
const handleAltK = (event: KeyboardEvent) => {
51+
if (event.altKey && event.key.toLowerCase() === 'k') {
52+
inputRef.current?.focus()
53+
inputRef.current?.value && inputRef.current.select()
54+
}
55+
}
56+
4857
// Change filter and search opcode according to query param
4958
useEffect(() => {
5059
const query = router.query
@@ -56,6 +65,11 @@ const Filters = ({ onSetFilter, isPrecompiled = false }: Props) => {
5665
handleKeywordChange(query.name as string)
5766
router.push(router)
5867
}
68+
69+
// Register and clean up Alt+K event listener
70+
window.addEventListener('keydown', handleAltK)
71+
return () => window.removeEventListener('keydown', handleAltK)
72+
5973
// eslint-disable-next-line react-hooks/exhaustive-deps
6074
}, [router.isReady])
6175

@@ -78,6 +92,7 @@ const Filters = ({ onSetFilter, isPrecompiled = false }: Props) => {
7892
</div>
7993

8094
<Input
95+
ref={inputRef}
8196
searchable
8297
value={searchKeyword}
8398
onChange={(e) => {

components/ui/Input.tsx

Lines changed: 64 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,80 @@
1-
import React, { useState } from 'react'
1+
import React, { useState, ForwardedRef, forwardRef } from 'react'
22

33
import cn from 'classnames'
44

55
import { Icon } from './Icon'
66

77
type Props = {
88
searchable?: boolean
9+
ref?: ForwardedRef<HTMLInputElement>
910
className?: string
1011
} & React.ComponentPropsWithoutRef<'input'>
1112

12-
export const Input: React.FC<Props> = ({
13-
searchable = false,
14-
onFocus,
15-
onBlur,
16-
className,
17-
...rest
18-
}) => {
19-
const [isFocused, setIsFocused] = useState(false)
13+
export const Input: React.FC<Props> = forwardRef(
14+
(
15+
{ searchable = false, onFocus, onBlur, className, ...rest },
16+
ref: ForwardedRef<HTMLInputElement>,
17+
) => {
18+
const [isFocused, setIsFocused] = useState(false)
19+
const [isInputEmpty, setIsInputEmpty] = useState(true)
2020

21-
const handleFocus = (e: any) => {
22-
setIsFocused(true)
23-
if (onFocus) {
24-
onFocus(e)
21+
const handleFocus = (e: any) => {
22+
setIsFocused(true)
23+
if (onFocus) {
24+
onFocus(e)
25+
}
2526
}
26-
}
2727

28-
const handleBlur = (e: any) => {
29-
setIsFocused(false)
30-
if (onBlur && e) {
31-
onBlur(e)
28+
const handleBlur = (e: any) => {
29+
setIsFocused(false)
30+
if (onBlur && e) {
31+
onBlur(e)
32+
}
3233
}
33-
}
3434

35-
return (
36-
<div
37-
className={cn(
38-
'flex items-center rounded px-3 py-2',
39-
{
40-
shadow: isFocused,
41-
},
42-
className,
43-
)}
44-
>
45-
<input
46-
onFocus={handleFocus}
47-
onBlur={handleBlur}
48-
className="w-full outline-none bg-transparent dark:placeholder-black-400 text-sm"
49-
{...rest}
50-
/>
51-
{searchable && (
52-
<Icon
53-
name="search-line"
54-
className={cn(
55-
'ml-2',
56-
isFocused
57-
? 'text-gray-400 dark:text-gray-300'
58-
: 'text-gray-300 dark:text-gray-400',
59-
)}
35+
const handleInput = (e: any) => {
36+
if (e.target.value === '') {
37+
setIsInputEmpty(true)
38+
} else {
39+
setIsInputEmpty(false)
40+
}
41+
}
42+
43+
return (
44+
<div
45+
className={cn(
46+
'flex items-center rounded px-3 py-2 text-sm relative',
47+
{
48+
shadow: isFocused,
49+
},
50+
className,
51+
)}
52+
>
53+
<input
54+
ref={ref}
55+
onFocus={handleFocus}
56+
onBlur={handleBlur}
57+
onInput={handleInput}
58+
className="w-full outline-none bg-transparent dark:placeholder-black-400"
59+
{...rest}
6060
/>
61-
)}
62-
</div>
63-
)
64-
}
61+
{searchable && (
62+
<>
63+
{isInputEmpty && (
64+
<span className="text-black-400 absolute right-8">Alt+K</span>
65+
)}
66+
<Icon
67+
name="search-line"
68+
className={cn(
69+
'ml-2',
70+
isFocused
71+
? 'text-gray-400 dark:text-gray-300'
72+
: 'text-gray-300 dark:text-gray-400',
73+
)}
74+
/>
75+
</>
76+
)}
77+
</div>
78+
)
79+
},
80+
)

0 commit comments

Comments
 (0)