Skip to content

Commit

Permalink
feat(search): implement onSearchTyping and add searchResults props
Browse files Browse the repository at this point in the history
The `onSearchTyping` prop was never fully implemented, and the new
`searchResults` prop makes displaying search results relative to the search
bar much easier. The `onSearch` behavior still needs to be added though.
  • Loading branch information
skipjack committed Oct 17, 2017
1 parent 8bfccbe commit 636ae07
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 5 deletions.
9 changes: 9 additions & 0 deletions src/banner/banner-search-style.css
@@ -1,5 +1,6 @@
.banner-search {
flex: 0 0 auto;
position: relative;
display: flex;
justify-content: flex-end;
}
Expand Down Expand Up @@ -55,3 +56,11 @@
.banner-search--active .banner-search__clear {
display: block;
}

.banner-search__results {
position: absolute;
top: 100%;
right: 0;
width: 100%;
margin-top: 5px;
}
89 changes: 85 additions & 4 deletions src/banner/banner-search.jsx
Expand Up @@ -11,15 +11,25 @@ export default class BannerSearch extends React.Component {
clear: PropTypes.node.isRequired,
search: PropTypes.node.isRequired
}),
onToggle: PropTypes.func.isRequired
searchResults: PropTypes.node,
onToggle: PropTypes.func.isRequired,
onSearch: PropTypes.func,
onSearchTyping: PropTypes.func
}

static defaultProps = {
placeholder: 'Search this site...'
}

state = {
input: '',
showResults: false
}

_resultsContainer = null

render() {
let { blockName, active, placeholder } = this.props,
let { blockName, active, placeholder, searchResults } = this.props,
activeMod = active ? `${blockName}--active` : ''

return (
Expand All @@ -28,7 +38,10 @@ export default class BannerSearch extends React.Component {
ref={ ref => this._input = ref }
className={ `${blockName}__input` }
type="text"
placeholder={ placeholder } />
placeholder={ placeholder }
value={ this.state.input }
onChange={ this._changeInput }
onFocus={ this._onFocus } />

<button
className={ `${blockName}__icon ${blockName}__clear` }
Expand All @@ -41,13 +54,81 @@ export default class BannerSearch extends React.Component {
onClick={ this.props.onToggle }>
{ this.props.icons.search }
</button>

{ searchResults && this.state.showResults ? (
<div
ref={ ref => this._resultsContainer = ref }
className={ `${blockName}__results` }>
{ searchResults }
</div>
) : null }
</div>
)
}

componentDidMount() {
window.addEventListener(
'click',
this._onDocumentClick
)
}

componentDidUpdate(prevProps, prevState) {
if ( !prevProps.active && this.props.active ) {
this._input.focus()
setTimeout(() => this._input && this._input.focus(), 150)
}
}

componentWillUnmount() {
window.removeEventListener(
'click',
this._onDocumentClick
)
}

/**
* Update the current search input and trigger the handler
*
* @param {object} e - React synthetic event
*/
_changeInput = e => {
let { onSearchTyping } = this.props,
{ value } = e.target

this.setState({
input: e.target.value
}, () => {
if ( onSearchTyping ) onSearchTyping(value)
})
}

/**
* Handle input focus to show search results
*
* @param {object} e - React synthetic event
*/
_onFocus = e => {
this.setState({
showResults: true
})
}

/**
* Handle document clicks to hide results when appropriate
*
* @param {object} e - Native click event
*/
_onDocumentClick = e => {
let { blockName } = this.props,
container = this._resultsContainer

if (
container && !container.contains(e.target) &&
!Array.from(e.target.classList).includes(`${blockName}__input`)
) {
this.setState({
showResults: false
})
}
}
}
6 changes: 5 additions & 1 deletion src/banner/banner.jsx
Expand Up @@ -27,6 +27,7 @@ export default class Banner extends React.Component {
PropTypes.object
),
search: PropTypes.bool.isRequired,
searchResults: PropTypes.node,
onMenuClick: PropTypes.func,
onSearch: PropTypes.func,
onSearchTyping: PropTypes.func
Expand Down Expand Up @@ -79,7 +80,10 @@ export default class Banner extends React.Component {
icons={ this.props.icons }
blockName={ `${blockName}-search` }
active={ this.state.searching }
onToggle={ this._toggleSearch } />
searchResults={ this.props.searchResults }
onToggle={ this._toggleSearch }
onSearch={ this.props.onSearch }
onSearchTyping={ this.props.onSearchTyping } />
) : null }
</section>

Expand Down

0 comments on commit 636ae07

Please sign in to comment.