@@ -22,41 +22,46 @@ const defaultFilter = (term, item) => {
2222class SLDSLookup extends React . Component {
2323 constructor ( props ) {
2424 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 ; } )
2828
2929 this . state = {
3030 searchTerm : '' ,
3131 isOpen :false ,
32- activeItem :null ,
32+ currentFocus :null ,
33+ focusIndex :null ,
3334 selectedIndex : null ,
34- activeIndex : null ,
35+ listLength : this . props . items . length
3536 } ;
3637 }
3738
3839 //=================================================
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.
4042 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 } )
4445 }
4546
4647 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 } )
5050 }
5151
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+ }
5460 }
5561
5662 //=================================================
5763 // Select menu item (onClick or on key enter/space)
5864 selectItem ( itemId ) {
59- //console.log('selectItem fired');
6065 let index = itemId . replace ( 'item-' , '' ) ;
6166 this . setState ( {
6267 selectedIndex : index ,
@@ -76,7 +81,7 @@ class SLDSLookup extends React.Component {
7681 handleClose ( ) {
7782 this . setState ( {
7883 isOpen :false ,
79- activeIndex :null
84+ focusIndex :null
8085 } )
8186 }
8287
@@ -103,25 +108,25 @@ class SLDSLookup extends React.Component {
103108 event . keyCode === KEYS . ESCAPE ? this . handleClose ( ) : this . handleClick ( ) ;
104109
105110 //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 } ) ;
108113 EventUtil . trapImmediate ( event ) ;
109114 }
110115 //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 ) {
112117 EventUtil . trapImmediate ( event ) ;
113118 this . increaseIndex ( ) ;
114119 }
115120 //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 ) {
117122 EventUtil . trapImmediate ( event ) ;
118123 this . decreaseIndex ( ) ;
119124 }
120125
121126 //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 ) {
123128 EventUtil . trapImmediate ( event ) ;
124- this . selectItem ( this . state . activeItem ) ;
129+ this . selectItem ( this . state . currentFocus ) ;
125130 }
126131 }
127132 }
@@ -136,8 +141,10 @@ class SLDSLookup extends React.Component {
136141 onSelect = { this . selectItem . bind ( this ) }
137142 label = { this . props . label }
138143 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 } /> ;
141148 } else {
142149 return null ;
143150 }
@@ -162,10 +169,10 @@ class SLDSLookup extends React.Component {
162169
163170 render ( ) {
164171 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" ;
166173
167174 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" >
169176 < section className = "slds-form-element" >
170177 < label className = "slds-form-element__label" forHTML = "lookup" > { this . props . label } </ label >
171178
@@ -179,7 +186,7 @@ class SLDSLookup extends React.Component {
179186 aria-label = "lookup"
180187 aria-haspopup = "true"
181188 aria-autocomplete = "list"
182- aria-activedescendant = { this . state . activeItem ? this . state . activeItem :"" }
189+ aria-activedescendant = { this . state . currentFocus ? this . state . currentFocus :"" }
183190 aria-expanded = { this . state . isOpen }
184191 role = "combobox"
185192 onChange = { this . handleChange . bind ( this ) }
@@ -197,11 +204,18 @@ class SLDSLookup extends React.Component {
197204 }
198205}
199206
207+
208+ SLDSLookup . propTypes = {
209+ items : React . PropTypes . array ,
210+ label : React . PropTypes . string ,
211+ } ;
212+
200213SLDSLookup . defaultProps = {
201214 filterWith : defaultFilter ,
202215 onItemSelect : function ( item ) {
203- //console.log('onItemSelect should be defined');
216+ //console.log('onItemSelect should be defined');
204217 }
205218} ;
219+
206220module . exports = SLDSLookup ;
207221
0 commit comments