1
- import React , { ChangeEvent , KeyboardEvent , useMemo , useState } from 'react' ;
2
- import ReactDOM from 'react-dom' ;
3
1
import classNames from 'classnames' ;
4
- import { useDropdown } from '../../src' ;
2
+ import React , { ChangeEvent , KeyboardEvent , useMemo , useState } from 'react' ;
3
+ import { useDropdown } from '../../src' ;
5
4
import './MultiSelect.css' ;
6
5
7
6
export type Item = {
@@ -12,62 +11,63 @@ export type Item = {
12
11
type Props = {
13
12
onSelect : ( items : Item [ ] ) => void ;
14
13
values ?: Item [ ] ;
15
- }
14
+ } ;
16
15
17
16
const items : Item [ ] = [
18
17
{
19
18
name : 'NewYork' ,
20
- value : 'NewYork'
19
+ value : 'NewYork' ,
21
20
} ,
22
21
{
23
22
name : 'Moscow' ,
24
- value : 'Moscow'
23
+ value : 'Moscow' ,
25
24
} ,
26
25
{
27
26
name : 'London' ,
28
- value : 'London'
27
+ value : 'London' ,
29
28
} ,
30
29
{
31
30
name : 'Amsterdam' ,
32
- value : 'Amsterdam'
31
+ value : 'Amsterdam' ,
33
32
} ,
34
33
{
35
34
name : 'Tokyo' ,
36
- value : 'Tokyo'
35
+ value : 'Tokyo' ,
37
36
} ,
38
37
{
39
38
name : 'Toronto' ,
40
- value : 'Toronto'
39
+ value : 'Toronto' ,
41
40
} ,
42
41
{
43
42
name : 'Cape Town' ,
44
- value : 'Cape Town'
43
+ value : 'Cape Town' ,
45
44
} ,
46
45
{
47
46
name : 'Rio de Janeiro' ,
48
- value : 'Rio de Janeiro'
47
+ value : 'Rio de Janeiro' ,
49
48
} ,
50
49
] ;
51
50
52
-
53
-
54
- export const Dropdown : React . FC < Props > = ( { onSelect, values} ) => {
51
+ export const Dropdown : React . FC < Props > = ( { onSelect, values } ) => {
55
52
const [ inputValue , setInputValue ] = useState < string > ( '' ) ;
56
53
const [ selectedOptions , setSelected ] = useState < Item [ ] > ( values ) ;
54
+ const [ isFocused , setFocused ] = useState < Boolean > ( false ) ;
57
55
58
56
const handleSelect = ( item : Item ) => {
59
- if ( selectedOptions . some ( el => el . value === item . value ) ) {
60
- return ;
57
+ let newOptions = [ ] ;
58
+ if ( selectedOptions . some ( ( el ) => el . value === item . value ) ) {
59
+ newOptions = selectedOptions . filter ( ( el ) => el . value !== item . value ) ;
60
+ } else {
61
+ newOptions = [ ...selectedOptions , item ] ;
61
62
}
62
63
63
- const newArr = [ ...selectedOptions , item ] ;
64
- setSelected ( newArr ) ;
65
- onSelect ( newArr ) ;
66
- }
64
+ setSelected ( newOptions ) ;
65
+ onSelect ( newOptions ) ;
66
+ } ;
67
67
68
68
const options = useMemo ( ( ) => {
69
- return items . filter ( item => item . name . includes ( inputValue ) ) ;
70
- } , [ inputValue ] )
69
+ return items . filter ( ( item ) => item . name . toLowerCase ( ) . includes ( inputValue . toLowerCase ( ) ) ) ;
70
+ } , [ inputValue ] ) ;
71
71
72
72
const {
73
73
isOpen,
@@ -77,7 +77,7 @@ export const Dropdown: React.FC<Props> = ({onSelect, values}) => {
77
77
getMenuProps,
78
78
getItemProps,
79
79
setOpen,
80
- } = useDropdown < Item > ( { items : options , onSelect : handleSelect } )
80
+ } = useDropdown < Item > ( { items : options , onSelect : handleSelect } ) ;
81
81
82
82
const handleChange = ( event : ChangeEvent < HTMLInputElement > ) => {
83
83
setOpen ( true ) ;
@@ -91,61 +91,80 @@ export const Dropdown: React.FC<Props> = ({onSelect, values}) => {
91
91
setOpen ( true ) ;
92
92
break ;
93
93
}
94
- }
95
-
96
- const handleBlur = ( ) => {
97
- setInputValue ( '' ) ;
98
- }
94
+ } ;
99
95
100
96
const handleCloseClick = ( item : Item ) => ( event ) => {
101
97
event . stopPropagation ( ) ;
102
- const newArr = selectedOptions . filter ( el => el . value !== item . value ) ;
98
+ const newArr = selectedOptions . filter ( ( el ) => el . value !== item . value ) ;
103
99
setSelected ( newArr ) ;
104
100
onSelect ( newArr ) ;
105
- }
106
-
107
- return < div className = 'wrapper' { ...getWrapperProps ( ) } onKeyDown = { handleKeyDown } onBlur = { handleBlur } >
108
-
109
- { selectedOptions . length === 0 ? null :
110
- selectedOptions . map ( ( item : Item ) => {
111
- return (
112
- < div className = 'multivalue' key = { item . value } >
113
- < span className = 'multivalue-name' > { item . name } </ span >
114
- < button type = 'button' className = 'remove' onClick = { handleCloseClick ( item ) } aria-label = { `Remove value ${ item . name } ` } > </ button >
115
- </ div > )
116
- } )
117
- }
101
+ } ;
118
102
119
- < input
120
- className = 'input'
121
- type = "text" id = "input" { ...getInputProps ( ) }
122
- placeholder = 'Select city'
123
- value = { inputValue }
124
- onChange = { handleChange }
125
- autoComplete = 'off'
126
- />
127
-
128
- { isOpen &&
129
- < ul className = 'menu' { ...getMenuProps ( ) as any } >
130
- { options . length === 0 ?
131
- < li > No data</ li >
132
- : options . map (
133
- ( item : Item , index ) =>
134
- < li
135
- key = { item . value }
136
- className = {
137
- classNames ( 'item' , {
138
- 'active' : highlightedIndex === index ,
139
- 'selected' : selectedOptions . some ( el => el . value === item . value ) ,
140
- } )
141
- }
142
- { ...getItemProps ( item , index ) }
143
- >
144
- { item . name }
145
- </ li >
146
- )
147
- }
148
- </ ul >
149
- }
150
- </ div >
151
- }
103
+ const handleBlur = ( ) => {
104
+ setInputValue ( '' ) ;
105
+ setFocused ( false ) ;
106
+ } ;
107
+
108
+ const handleFocus = ( ) => {
109
+ setFocused ( true ) ;
110
+ } ;
111
+
112
+ return (
113
+ < div
114
+ className = "wrapper"
115
+ { ...getWrapperProps ( ) }
116
+ onKeyDown = { handleKeyDown }
117
+ onFocus = { handleFocus }
118
+ onBlur = { handleBlur }
119
+ >
120
+ { selectedOptions . length === 0
121
+ ? null
122
+ : selectedOptions . map ( ( item : Item ) => {
123
+ return (
124
+ < div className = "multivalue" key = { item . value } >
125
+ < span className = "multivalue-name" > { item . name } </ span >
126
+ < button
127
+ type = "button"
128
+ className = "remove"
129
+ onClick = { handleCloseClick ( item ) }
130
+ tabIndex = { isFocused ? 0 : - 1 }
131
+ aria-label = { `Remove value ${ item . name } ` }
132
+ > </ button >
133
+ </ div >
134
+ ) ;
135
+ } ) }
136
+
137
+ < input
138
+ className = "input"
139
+ type = "text"
140
+ id = "input"
141
+ { ...getInputProps ( ) }
142
+ placeholder = "Select city"
143
+ value = { inputValue }
144
+ onChange = { handleChange }
145
+ autoComplete = "off"
146
+ />
147
+
148
+ { isOpen && (
149
+ < ul className = "menu" { ...( getMenuProps ( ) as any ) } >
150
+ { options . length === 0 ? (
151
+ < li > No data</ li >
152
+ ) : (
153
+ options . map ( ( item : Item , index ) => (
154
+ < li
155
+ key = { item . value }
156
+ className = { classNames ( 'item' , {
157
+ active : highlightedIndex === index ,
158
+ selected : selectedOptions . some ( ( el ) => el . value === item . value ) ,
159
+ } ) }
160
+ { ...getItemProps ( item , index ) }
161
+ >
162
+ { item . name }
163
+ </ li >
164
+ ) )
165
+ ) }
166
+ </ ul >
167
+ ) }
168
+ </ div >
169
+ ) ;
170
+ } ;
0 commit comments