2016-05-31 18:39:30 +00:00
|
|
|
import React from 'react'
|
2017-05-05 01:38:03 +00:00
|
|
|
import PropTypes from 'prop-types'
|
2018-04-26 15:47:30 +00:00
|
|
|
|
2018-06-27 19:03:44 +00:00
|
|
|
import { search as icons } from '../svgs'
|
2018-04-30 00:55:13 +00:00
|
|
|
import NimbleEmojiIndex from '../utils/emoji-index/nimble-emoji-index'
|
2019-03-10 16:40:59 +00:00
|
|
|
import { throttleIdleTask } from '../utils/index'
|
2016-05-31 18:39:30 +00:00
|
|
|
|
2019-03-09 21:03:00 +00:00
|
|
|
let id = 0
|
|
|
|
|
2018-04-30 00:55:13 +00:00
|
|
|
export default class Search extends React.PureComponent {
|
2017-10-07 04:02:02 +00:00
|
|
|
constructor(props) {
|
2017-09-29 14:46:29 +00:00
|
|
|
super(props)
|
2018-06-27 19:03:44 +00:00
|
|
|
this.state = {
|
|
|
|
icon: icons.search,
|
|
|
|
isSearching: false,
|
2019-03-10 16:54:12 +00:00
|
|
|
id: ++id,
|
2018-06-27 19:03:44 +00:00
|
|
|
}
|
2017-09-29 14:46:29 +00:00
|
|
|
|
2018-03-28 21:30:47 +00:00
|
|
|
this.data = props.data
|
|
|
|
this.emojiIndex = new NimbleEmojiIndex(this.data)
|
2017-09-29 14:46:29 +00:00
|
|
|
this.setRef = this.setRef.bind(this)
|
2018-06-27 19:03:44 +00:00
|
|
|
this.clear = this.clear.bind(this)
|
|
|
|
this.handleKeyUp = this.handleKeyUp.bind(this)
|
2019-03-10 16:40:59 +00:00
|
|
|
|
|
|
|
// throttle keyboard input so that typing isn't delayed
|
|
|
|
this.handleChange = throttleIdleTask(this.handleChange.bind(this))
|
2017-09-29 14:46:29 +00:00
|
|
|
}
|
|
|
|
|
2019-03-10 18:19:41 +00:00
|
|
|
componentDidMount() {
|
|
|
|
// in some cases (e.g. preact) the input may already be pre-populated
|
2019-03-14 01:31:13 +00:00
|
|
|
// this.input is undefined in Jest tests
|
|
|
|
if (this.input && this.input.value) {
|
2019-03-10 18:19:41 +00:00
|
|
|
this.search(this.input.value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-27 19:03:44 +00:00
|
|
|
search(value) {
|
|
|
|
if (value == '')
|
|
|
|
this.setState({
|
|
|
|
icon: icons.search,
|
|
|
|
isSearching: false,
|
|
|
|
})
|
|
|
|
else
|
|
|
|
this.setState({
|
|
|
|
icon: icons.delete,
|
|
|
|
isSearching: true,
|
|
|
|
})
|
2016-05-31 18:39:30 +00:00
|
|
|
|
2017-10-07 04:02:02 +00:00
|
|
|
this.props.onSearch(
|
2018-03-28 21:30:47 +00:00
|
|
|
this.emojiIndex.search(value, {
|
2017-10-07 04:02:02 +00:00
|
|
|
emojisToShowFilter: this.props.emojisToShowFilter,
|
|
|
|
maxResults: this.props.maxResults,
|
|
|
|
include: this.props.include,
|
|
|
|
exclude: this.props.exclude,
|
|
|
|
custom: this.props.custom,
|
2018-03-27 18:51:26 +00:00
|
|
|
}),
|
2017-10-07 04:02:02 +00:00
|
|
|
)
|
2016-05-31 18:39:30 +00:00
|
|
|
}
|
|
|
|
|
2016-07-08 20:28:43 +00:00
|
|
|
clear() {
|
2018-06-27 19:03:44 +00:00
|
|
|
if (this.input.value == '') return
|
2017-09-27 19:26:50 +00:00
|
|
|
this.input.value = ''
|
2019-03-10 17:35:07 +00:00
|
|
|
this.input.focus()
|
2018-06-27 19:03:44 +00:00
|
|
|
this.search('')
|
|
|
|
}
|
|
|
|
|
|
|
|
handleChange() {
|
2020-03-18 16:14:38 +00:00
|
|
|
if (this.input) {
|
|
|
|
this.search(this.input.value)
|
|
|
|
}
|
2018-06-27 19:03:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
handleKeyUp(e) {
|
|
|
|
if (e.keyCode === 13) {
|
|
|
|
this.clear()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setRef(c) {
|
|
|
|
this.input = c
|
2016-07-08 20:28:43 +00:00
|
|
|
}
|
|
|
|
|
2016-05-31 18:39:30 +00:00
|
|
|
render() {
|
2019-12-21 17:07:17 +00:00
|
|
|
const { i18n, autoFocus } = this.props
|
2019-03-10 17:35:07 +00:00
|
|
|
const { icon, isSearching, id } = this.state
|
2019-03-09 21:35:48 +00:00
|
|
|
const inputId = `emoji-mart-search-${id}`
|
2016-10-27 03:22:59 +00:00
|
|
|
|
2017-10-07 04:02:02 +00:00
|
|
|
return (
|
2019-03-12 16:36:28 +00:00
|
|
|
<section className="emoji-mart-search" aria-label={i18n.search}>
|
2017-10-07 04:02:02 +00:00
|
|
|
<input
|
2019-03-09 21:03:00 +00:00
|
|
|
id={inputId}
|
2017-10-07 04:02:02 +00:00
|
|
|
ref={this.setRef}
|
2019-03-09 21:03:00 +00:00
|
|
|
type="search"
|
2017-10-07 04:02:02 +00:00
|
|
|
onChange={this.handleChange}
|
|
|
|
placeholder={i18n.search}
|
|
|
|
autoFocus={autoFocus}
|
|
|
|
/>
|
2019-03-09 21:03:00 +00:00
|
|
|
{/*
|
2019-03-16 17:26:09 +00:00
|
|
|
* Use a <label> in addition to the placeholder for accessibility, but place it off-screen
|
|
|
|
* http://www.maxability.co.in/2016/01/placeholder-attribute-and-why-it-is-not-accessible/
|
|
|
|
*/}
|
2019-03-10 16:54:12 +00:00
|
|
|
<label className="emoji-mart-sr-only" htmlFor={inputId}>
|
|
|
|
{i18n.search}
|
|
|
|
</label>
|
2018-06-27 19:03:44 +00:00
|
|
|
<button
|
|
|
|
className="emoji-mart-search-icon"
|
2019-03-10 17:35:07 +00:00
|
|
|
onClick={this.clear}
|
2018-06-27 19:03:44 +00:00
|
|
|
onKeyUp={this.handleKeyUp}
|
2019-03-09 21:03:00 +00:00
|
|
|
aria-label={i18n.clear}
|
2019-03-10 17:35:07 +00:00
|
|
|
disabled={!isSearching}
|
2018-07-31 19:01:34 +00:00
|
|
|
>
|
|
|
|
{icon()}
|
|
|
|
</button>
|
2019-03-12 16:36:28 +00:00
|
|
|
</section>
|
2017-10-07 04:02:02 +00:00
|
|
|
)
|
2016-05-31 18:39:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-18 19:24:52 +00:00
|
|
|
Search.propTypes /* remove-proptypes */ = {
|
2018-04-30 00:55:13 +00:00
|
|
|
onSearch: PropTypes.func,
|
|
|
|
maxResults: PropTypes.number,
|
|
|
|
emojisToShowFilter: PropTypes.func,
|
|
|
|
autoFocus: PropTypes.bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
Search.defaultProps = {
|
|
|
|
onSearch: () => {},
|
|
|
|
maxResults: 75,
|
|
|
|
emojisToShowFilter: null,
|
|
|
|
autoFocus: false,
|
2018-04-26 14:36:54 +00:00
|
|
|
}
|