1
- import React , {
2
- useState ,
3
- ReactNode ,
4
- useCallback ,
5
- useMemo ,
6
- useRef ,
7
- SelectHTMLAttributes ,
8
- } from "react" ;
1
+ import React , { useState , useRef } from "react" ;
9
2
import { useClickAway } from "react-use" ;
10
- import { SelectContext } from "./select-context " ;
3
+ import { Option } from "./option " ;
11
4
import * as S from "./select.styled" ;
12
5
13
- type SelectProps = SelectHTMLAttributes < HTMLSelectElement > & {
14
- children : ReactNode | ReactNode [ ] ;
6
+ type Option = {
7
+ value : unknown ;
8
+ label : React . ReactNode ;
9
+ } ;
10
+
11
+ type SelectProps = Omit < React . HTMLAttributes < HTMLDivElement > , "onChange" > & {
12
+ options : Option [ ] ;
13
+ value : unknown ;
14
+ onChange : ( value : unknown ) => void ;
15
15
errorMessage ?: string ;
16
16
defaultValue ?: string ;
17
17
placeholder ?: string ;
@@ -23,6 +23,9 @@ type SelectProps = SelectHTMLAttributes<HTMLSelectElement> & {
23
23
} ;
24
24
25
25
export function Select ( {
26
+ options,
27
+ value,
28
+ onChange,
26
29
placeholder = "Choose an option" ,
27
30
defaultValue = "" ,
28
31
iconSrc = "" ,
@@ -31,10 +34,8 @@ export function Select({
31
34
hint = "" ,
32
35
errorMessage = "" ,
33
36
width = "" ,
34
- children,
35
37
...props
36
38
} : SelectProps ) {
37
- const [ selectedOption , setSelectedOption ] = useState ( defaultValue || "" ) ;
38
39
const [ showDropdown , setShowDropdown ] = useState ( false ) ;
39
40
const ref = useRef ( null ) ;
40
41
@@ -43,55 +44,59 @@ export function Select({
43
44
setShowDropdown ( false ) ;
44
45
} ) ;
45
46
46
- const showDropdownHandler = useCallback (
47
- ( ) => setShowDropdown ( ( prevShowDropdown ) => ! prevShowDropdown ) ,
48
- [ ]
49
- ) ;
47
+ const showDropdownHandler = ( ) =>
48
+ setShowDropdown ( ( prevShowDropdown ) => ! prevShowDropdown ) ;
50
49
51
- const updateSelectedOption = useCallback ( ( option : string ) => {
52
- setSelectedOption ( option ) ;
50
+ const onClickOption = ( newValue : unknown ) => {
51
+ onChange ( newValue ) ;
53
52
setShowDropdown ( false ) ;
54
- } , [ ] ) ;
53
+ } ;
55
54
56
- const value = useMemo (
57
- ( ) => ( { selectedOption, changeSelectedOption : updateSelectedOption } ) ,
58
- [ selectedOption , updateSelectedOption ]
55
+ const selectedOption = options . find (
56
+ ( option ) => option . value === ( value || defaultValue )
59
57
) ;
60
58
61
59
return (
62
- < SelectContext . Provider value = { value } >
63
- < S . Container ref = { ref } width = { width } { ...props } >
64
- { label && < S . Label > { label } </ S . Label > }
60
+ < S . Container ref = { ref } width = { width } { ...props } >
61
+ { label && < S . Label > { label } </ S . Label > }
65
62
66
- < S . SelectedOption
67
- onClick = { showDropdownHandler }
68
- selectedOption = { selectedOption }
69
- disabled = { disabled }
70
- errorMessage = { errorMessage }
71
- aria-expanded = { showDropdown }
72
- width = { width }
73
- >
74
- < S . LeftContainer >
75
- { iconSrc && < S . OptionalIcon src = { iconSrc } /> }
76
- { selectedOption || placeholder }
77
- </ S . LeftContainer >
63
+ < S . SelectedOption
64
+ onClick = { showDropdownHandler }
65
+ selectedOption = { selectedOption }
66
+ disabled = { disabled }
67
+ errorMessage = { errorMessage }
68
+ aria-expanded = { showDropdown }
69
+ width = { width }
70
+ >
71
+ < S . LeftContainer >
72
+ { iconSrc && < S . OptionalIcon src = { iconSrc } /> }
73
+ { selectedOption ?. label || placeholder }
74
+ </ S . LeftContainer >
78
75
79
- < S . SelectArrowIcon
80
- src = "/icons/chevron-down.svg"
81
- showDropdown = { showDropdown }
82
- />
83
- </ S . SelectedOption >
76
+ < S . SelectArrowIcon
77
+ src = "/icons/chevron-down.svg"
78
+ showDropdown = { showDropdown }
79
+ />
80
+ </ S . SelectedOption >
84
81
85
- { hint && ! showDropdown && ! errorMessage && < S . Hint > { hint } </ S . Hint > }
82
+ { hint && ! showDropdown && ! errorMessage && < S . Hint > { hint } </ S . Hint > }
86
83
87
- { errorMessage && ! showDropdown && ! disabled && (
88
- < S . ErrorMessage > { errorMessage } </ S . ErrorMessage >
89
- ) }
84
+ { errorMessage && ! showDropdown && ! disabled && (
85
+ < S . ErrorMessage > { errorMessage } </ S . ErrorMessage >
86
+ ) }
90
87
91
- < S . List showDropdown = { showDropdown } role = "listbox" tabIndex = { - 1 } >
92
- { children }
93
- </ S . List >
94
- </ S . Container >
95
- </ SelectContext . Provider >
88
+ < S . List showDropdown = { showDropdown } role = "listbox" tabIndex = { - 1 } >
89
+ { options . map ( ( option ) => (
90
+ < Option
91
+ key = { String ( option . value ) }
92
+ value = { option . value }
93
+ isSelected = { value === option . value }
94
+ onClick = { onClickOption }
95
+ >
96
+ { option . label }
97
+ </ Option >
98
+ ) ) }
99
+ </ S . List >
100
+ </ S . Container >
96
101
) ;
97
102
}
0 commit comments