@@ -3,15 +3,15 @@ import { useClickAway } from "react-use";
3
3
import { Option } from "./option" ;
4
4
import * as S from "./select.styled" ;
5
5
6
- type Option = {
7
- value : unknown ;
6
+ type Option < T > = {
7
+ value : T ;
8
8
label : React . ReactNode ;
9
9
} ;
10
10
11
- type SelectProps = Omit < React . HTMLAttributes < HTMLDivElement > , "onChange" > & {
12
- options : Option [ ] ;
11
+ type SelectProps < T > = Omit < React . HTMLAttributes < HTMLDivElement > , "onChange" > & {
12
+ options : Option < T > [ ] ;
13
13
value : unknown ;
14
- onChange : ( value : unknown ) => void ;
14
+ onChange : ( value : T ) => void ;
15
15
errorMessage ?: string ;
16
16
defaultValue ?: string ;
17
17
placeholder ?: string ;
@@ -22,7 +22,7 @@ type SelectProps = Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> & {
22
22
hint ?: string ;
23
23
} ;
24
24
25
- export function Select ( {
25
+ export function Select < T > ( {
26
26
options,
27
27
value,
28
28
onChange,
@@ -35,7 +35,7 @@ export function Select({
35
35
errorMessage = "" ,
36
36
width = "" ,
37
37
...props
38
- } : SelectProps ) {
38
+ } : SelectProps < T > ) {
39
39
const [ showDropdown , setShowDropdown ] = useState ( false ) ;
40
40
const ref = useRef ( null ) ;
41
41
@@ -44,14 +44,34 @@ export function Select({
44
44
setShowDropdown ( false ) ;
45
45
} ) ;
46
46
47
- const showDropdownHandler = ( ) =>
47
+ const toggleDropdown = ( ) =>
48
48
setShowDropdown ( ( prevShowDropdown ) => ! prevShowDropdown ) ;
49
49
50
- const onClickOption = ( newValue : unknown ) => {
50
+ const onKeyDown = ( event : React . KeyboardEvent < HTMLDivElement > ) => {
51
+ if ( event . code === "Space" || event . code === "ArrowDown" ) {
52
+ event . preventDefault ( ) ;
53
+ toggleDropdown ( ) ;
54
+ }
55
+ if ( event . code === "Escape" ) {
56
+ setShowDropdown ( false ) ;
57
+ }
58
+ } ;
59
+
60
+ const onClickOption = ( newValue : T ) => {
51
61
onChange ( newValue ) ;
52
62
setShowDropdown ( false ) ;
53
63
} ;
54
64
65
+ const onKeyDownOption = ( event : React . KeyboardEvent , value : T ) => {
66
+ if ( event . code === "Space" ) {
67
+ event . preventDefault ( ) ;
68
+ onClickOption ( value ) ;
69
+ }
70
+ if ( event . code === "Escape" ) {
71
+ setShowDropdown ( false ) ;
72
+ }
73
+ } ;
74
+
55
75
const selectedOption = options . find (
56
76
( option ) => option . value === ( value || defaultValue )
57
77
) ;
@@ -61,12 +81,13 @@ export function Select({
61
81
{ label && < S . Label > { label } </ S . Label > }
62
82
63
83
< S . SelectedOption
64
- onClick = { showDropdownHandler }
65
- selectedOption = { selectedOption }
84
+ onClick = { toggleDropdown }
85
+ hasValue = { ! ! selectedOption }
86
+ hasError = { ! ! errorMessage }
66
87
disabled = { disabled }
67
- errorMessage = { errorMessage }
68
88
aria-expanded = { showDropdown }
69
89
width = { width }
90
+ onKeyDown = { onKeyDown }
70
91
>
71
92
< S . LeftContainer >
72
93
{ iconSrc && < S . OptionalIcon src = { iconSrc } /> }
@@ -92,6 +113,7 @@ export function Select({
92
113
value = { option . value }
93
114
isSelected = { value === option . value }
94
115
onClick = { onClickOption }
116
+ onKeyDown = { onKeyDownOption }
95
117
>
96
118
{ option . label }
97
119
</ Option >
0 commit comments