Skip to content

Commit eeab780

Browse files
author
vikasrohit
committed
Merge pull request #81 from appirio-tech/feature/forward-arrow-key-autocomplete
Feature/forward arrow key autocomplete
2 parents b06194f + 0e6bedf commit eeab780

File tree

3 files changed

+55
-9
lines changed

3 files changed

+55
-9
lines changed

components/SearchBar/SearchBar.jsx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class SearchBar extends Component {
5858

5959
handleSuggestionsUpdate(requestNo, data) {
6060
if (requestNo === this.state.maxRequestNo) {
61-
this.setState({loading: false, suggestions: data})
61+
this.setState({loading: false, suggestions: data, selectedSuggestionIdx: null})
6262
}
6363
}
6464

@@ -71,7 +71,8 @@ class SearchBar extends Component {
7171
searchValue: this.refs.searchValue.value,
7272
requestNo: rc,
7373
maxRequestNo: rc,
74-
loading: true
74+
loading: true,
75+
searchState: 'focused'
7576
}
7677
},
7778
function() {
@@ -93,11 +94,45 @@ class SearchBar extends Component {
9394

9495
onKeyUp(evt) {
9596
const eventKey = evt.keyCode
97+
evt.stopPropagation()
98+
evt.preventDefault()
9699
// if return is pressed
97100
if (eventKey === 13) {
98101
this.setState({ searchState: 'filled' }, function() {
99102
this.search()
100103
})
104+
} else if (eventKey === 39) { // right arrow key is pressed
105+
const suggestion = this.state.suggestions.length > 0 ? this.state.suggestions[0] : null
106+
if (suggestion) {
107+
this.refs.searchValue.value = suggestion
108+
// trigger the change event handler
109+
this.onChange()
110+
}
111+
} else if (eventKey === 38) { // up arrow key
112+
const currSelectedIdx = this.state.selectedSuggestionIdx
113+
if (currSelectedIdx) { // index is none of (undefined, null, 0)
114+
const suggestionIdx = currSelectedIdx - 1
115+
const suggestion = this.state.suggestions[suggestionIdx]
116+
this.refs.searchValue.value = suggestion
117+
this.setState({
118+
selectedSuggestionIdx : suggestionIdx,
119+
searchValue: suggestion
120+
})
121+
}
122+
} else if (eventKey === 40) { // down arrow key
123+
const currSelectedIdx = this.state.selectedSuggestionIdx
124+
// index is none of (undefined, null, 0)
125+
if (typeof currSelectedIdx === 'undefined'
126+
|| currSelectedIdx === null
127+
|| this.state.suggestions.length > currSelectedIdx + 1) {
128+
const suggestionIdx = typeof currSelectedIdx === 'number' ? currSelectedIdx + 1 : 0
129+
const suggestion = this.state.suggestions[suggestionIdx]
130+
this.refs.searchValue.value = suggestion
131+
this.setState({
132+
selectedSuggestionIdx: suggestionIdx,
133+
searchValue: suggestion
134+
})
135+
}
101136
}
102137
}
103138

@@ -140,7 +175,7 @@ class SearchBar extends Component {
140175

141176
const results = this.state.loading === true
142177
? <div className="loading-suggestions"><Loader /></div>
143-
: <SearchSuggestions recentSearch={ recentList } popularSearch={ popularList } onSuggestionSelect={ this.handleSuggestionSelect } />
178+
: <SearchSuggestions recentSearch={ recentList } searchTerm={ this.state.searchValue } popularSearch={ popularList } onSuggestionSelect={ this.handleSuggestionSelect } />
144179
return (
145180
<div className={ sbClasses }>
146181
<input className="search-bar__text" onFocus={ this.onFocus } onChange={ this.onChange } onKeyUp={ this.onKeyUp } ref="searchValue" value={this.state.searchValue} />

components/SearchSuggestions/SearchSuggestions.jsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,32 @@ class SearchSuggestions extends Component {
2323
render() {
2424
const recentList = this.props.recentSearch
2525
const popularList = this.props.popularSearch
26-
2726
const suggestionItem = (term, i) => {
2827
let labelDOM = term
2928
const searchTerm = this.props.searchTerm
29+
let exactMatch = false
3030
if (searchTerm.length > 0) {
3131
const idx = term.toLowerCase().indexOf(searchTerm.toLowerCase())
3232
if (idx !== -1) {
33+
// check if exact match
34+
exactMatch = idx === 0 && term.length === searchTerm.length
35+
// prepare DOM for the content to be rendered under StandardListItem
3336
labelDOM = (
34-
<span>
37+
<span className={ itemClasses }>
3538
{ term.substring(0, idx) }
3639
<strong>{ searchTerm }</strong>
3740
{ term.substring(idx + searchTerm.length) }
3841
</span>
3942
)
4043
}
4144
}
42-
45+
// prepares css class for li
46+
const itemClasses = classNames(
47+
{ selected : exactMatch }
48+
)
49+
// prepares and returns the DOM for each popular/recent search item
4350
return (
44-
<li key={ i } data-term={term} onClick={ this.handleClick }>
51+
<li key={ i } data-term={term} onClick={ this.handleClick } className={ itemClasses }>
4552
<StandardListItem labelText={ labelDOM } showIcon={ false } />
4653
</li>
4754
)
@@ -105,13 +112,13 @@ class SearchSuggestions extends Component {
105112
SearchSuggestions.propTypes = {
106113
onSuggestionSelect : PropTypes.func.isRequired,
107114
recentSearch : PropTypes.array,
108-
popularSearch : PropTypes.array,
115+
popularSearch : PropTypes.array,
109116
searchTerm : PropTypes.string
110117
}
111118

112119
SearchSuggestions.defaultProps = {
113120
recentSearch : [],
114-
popularSearch : [],
121+
popularSearch : [],
115122
searchTerm : ''
116123
}
117124

components/SearchSuggestions/SearchSuggestions.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
padding: 0;
6969
padding-bottom: 5px;
7070

71+
li.selected {
72+
background-color: $gray-light;
73+
}
74+
7175
.StandardListItem {
7276
align-items: initial;
7377
text-align: left;

0 commit comments

Comments
 (0)