@@ -22,41 +22,46 @@ const defaultFilter = (term, item) => {
22
22
class SLDSLookup extends React . Component {
23
23
constructor ( props ) {
24
24
super ( props ) ;
25
- this . props . items . map ( ( item , index ) => {
26
- return item . id = 'item-' + index ;
27
- } )
25
+
26
+ //Dynamically assign ids to list items to reference for focusing and selecting items
27
+ this . props . items . map ( ( item , index ) => { return item . id = 'item-' + index ; } )
28
28
29
29
this . state = {
30
30
searchTerm : '' ,
31
31
isOpen :false ,
32
- activeItem :null ,
32
+ currentFocus :null ,
33
+ focusIndex :null ,
33
34
selectedIndex : null ,
34
- activeIndex : null ,
35
+ listLength : this . props . items . length
35
36
} ;
36
37
}
37
38
38
39
//=================================================
39
- // Set Active Descendant (on key down/up, set currently focused/hovered item in list)
40
+ // Using down/up keys, set Focus on list item and assign it to aria-activedescendant attribute in input.
41
+ // Need to keep track of filtered list length to be able to increment/decrement the focus index so it's contained to the number of available list items.
40
42
increaseIndex ( ) {
41
- this . setState ( {
42
- activeIndex : this . state . activeIndex <= this . props . items . length ? this . state . activeIndex + 1 : 0
43
- } )
43
+ let items = this . state . listLength - 1 ;
44
+ this . setState ( { focusIndex : this . state . focusIndex < items ? this . state . focusIndex + 1 : 0 } )
44
45
}
45
46
46
47
decreaseIndex ( ) {
47
- this . setState ( {
48
- activeIndex : this . state . activeIndex > 0 ? this . state . activeIndex - 1 : this . props . items . length
49
- } )
48
+ let items = this . state . listLength - 1 ;
49
+ this . setState ( { focusIndex : this . state . focusIndex > 0 ? this . state . focusIndex - 1 : items } )
50
50
}
51
51
52
- setActiveDescendant ( id ) {
53
- this . setState ( { activeItem :id } ) ;
52
+ setFocus ( id ) {
53
+ this . setState ( { currentFocus :id } ) ;
54
+ }
55
+
56
+ getListLength ( qty ) {
57
+ if ( qty !== this . state . listLength ) {
58
+ this . setState ( { listLength :qty } ) ;
59
+ }
54
60
}
55
61
56
62
//=================================================
57
63
// Select menu item (onClick or on key enter/space)
58
64
selectItem ( itemId ) {
59
- //console.log('selectItem fired');
60
65
let index = itemId . replace ( 'item-' , '' ) ;
61
66
this . setState ( {
62
67
selectedIndex : index ,
@@ -76,7 +81,7 @@ class SLDSLookup extends React.Component {
76
81
handleClose ( ) {
77
82
this . setState ( {
78
83
isOpen :false ,
79
- activeIndex :null
84
+ focusIndex :null
80
85
} )
81
86
}
82
87
@@ -103,25 +108,25 @@ class SLDSLookup extends React.Component {
103
108
event . keyCode === KEYS . ESCAPE ? this . handleClose ( ) : this . handleClick ( ) ;
104
109
105
110
//If user hits tab key, move aria activedescendant to first menu item
106
- if ( event . keyCode === KEYS . TAB && this . state . activeIndex === null ) {
107
- this . setState ( { activeIndex : 0 } ) ;
111
+ if ( event . keyCode === KEYS . TAB && this . state . focusIndex === null ) {
112
+ this . setState ( { focusIndex : 0 } ) ;
108
113
EventUtil . trapImmediate ( event ) ;
109
114
}
110
115
//If user hits down key, advance aria activedescendant to next item
111
- else if ( event . keyCode === KEYS . DOWN && this . state . activeIndex !== null ) {
116
+ else if ( event . keyCode === KEYS . DOWN && this . state . focusIndex !== null ) {
112
117
EventUtil . trapImmediate ( event ) ;
113
118
this . increaseIndex ( ) ;
114
119
}
115
120
//If user hits up key, advance aria activedescendant to previous item
116
- else if ( event . keyCode === KEYS . UP && this . state . activeIndex !== null ) {
121
+ else if ( event . keyCode === KEYS . UP && this . state . focusIndex !== null ) {
117
122
EventUtil . trapImmediate ( event ) ;
118
123
this . decreaseIndex ( ) ;
119
124
}
120
125
121
126
//If user hits enter/space key, select current activedescendant item
122
- else if ( ( event . keyCode === KEYS . ENTER || event . keyCode === KEYS . SPACE ) && this . state . activeIndex !== null ) {
127
+ else if ( ( event . keyCode === KEYS . ENTER || event . keyCode === KEYS . SPACE ) && this . state . focusIndex !== null ) {
123
128
EventUtil . trapImmediate ( event ) ;
124
- this . selectItem ( this . state . activeItem ) ;
129
+ this . selectItem ( this . state . currentFocus ) ;
125
130
}
126
131
}
127
132
}
@@ -136,8 +141,10 @@ class SLDSLookup extends React.Component {
136
141
onSelect = { this . selectItem . bind ( this ) }
137
142
label = { this . props . label }
138
143
items = { this . props . items }
139
- setActiveDescendant = { this . setActiveDescendant . bind ( this ) }
140
- activeIndex = { this . state . activeIndex } /> ;
144
+ setFocus = { this . setFocus . bind ( this ) }
145
+ getListLength = { this . getListLength . bind ( this ) }
146
+ listLength = { this . state . listLength }
147
+ focusIndex = { this . state . focusIndex } /> ;
141
148
} else {
142
149
return null ;
143
150
}
@@ -162,10 +169,10 @@ class SLDSLookup extends React.Component {
162
169
163
170
render ( ) {
164
171
let inputClasses = this . state . selectedIndex === null ? 'slds-input' :'slds-input slds-hide' ;
165
- let compClasses = this . state . selectedIndex === null ? "slds-lookup ignore-react-onclickoutside" :"slds-lookup ignore-react-onclickoutside slds-has-selection" ;
172
+ let componentClasses = this . state . selectedIndex === null ? "slds-lookup ignore-react-onclickoutside" :"slds-lookup ignore-react-onclickoutside slds-has-selection" ;
166
173
167
174
return (
168
- < div className = { compClasses } data-select = "single" data-scope = "single" data-typeahead = "true" >
175
+ < div className = { componentClasses } data-select = "single" data-scope = "single" data-typeahead = "true" >
169
176
< section className = "slds-form-element" >
170
177
< label className = "slds-form-element__label" forHTML = "lookup" > { this . props . label } </ label >
171
178
@@ -179,7 +186,7 @@ class SLDSLookup extends React.Component {
179
186
aria-label = "lookup"
180
187
aria-haspopup = "true"
181
188
aria-autocomplete = "list"
182
- aria-activedescendant = { this . state . activeItem ? this . state . activeItem :"" }
189
+ aria-activedescendant = { this . state . currentFocus ? this . state . currentFocus :"" }
183
190
aria-expanded = { this . state . isOpen }
184
191
role = "combobox"
185
192
onChange = { this . handleChange . bind ( this ) }
@@ -197,11 +204,18 @@ class SLDSLookup extends React.Component {
197
204
}
198
205
}
199
206
207
+
208
+ SLDSLookup . propTypes = {
209
+ items : React . PropTypes . array ,
210
+ label : React . PropTypes . string ,
211
+ } ;
212
+
200
213
SLDSLookup . defaultProps = {
201
214
filterWith : defaultFilter ,
202
215
onItemSelect : function ( item ) {
203
- //console.log('onItemSelect should be defined');
216
+ //console.log('onItemSelect should be defined');
204
217
}
205
218
} ;
219
+
206
220
module . exports = SLDSLookup ;
207
221
0 commit comments