emoji-mart-lazyload/src/components/search.js

132 lines
3.1 KiB
JavaScript
Raw Normal View History

2016-05-31 18:39:30 +00:00
import React from 'react'
import PropTypes from 'prop-types'
2018-04-26 15:47:30 +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'
import { throttleIdleTask } from '../utils/index'
2016-05-31 18:39:30 +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) {
super(props)
this.state = {
icon: icons.search,
isSearching: false,
2019-03-10 16:54:12 +00:00
id: ++id,
}
this.data = props.data
this.emojiIndex = new NimbleEmojiIndex(this.data)
this.setRef = this.setRef.bind(this)
this.clear = this.clear.bind(this)
this.handleKeyUp = this.handleKeyUp.bind(this)
// throttle keyboard input so that typing isn't delayed
this.handleChange = throttleIdleTask(this.handleChange.bind(this))
}
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) {
this.search(this.input.value)
}
}
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(
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
}
clear() {
if (this.input.value == '') return
this.input.value = ''
2019-03-10 17:35:07 +00:00
this.input.focus()
this.search('')
}
handleChange() {
2020-03-18 16:14:38 +00:00
if (this.input) {
this.search(this.input.value)
}
}
handleKeyUp(e) {
if (e.keyCode === 13) {
this.clear()
}
}
setRef(c) {
this.input = c
}
2016-05-31 18:39:30 +00:00
render() {
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 (
<section className="emoji-mart-search" aria-label={i18n.search}>
2017-10-07 04:02:02 +00:00
<input
id={inputId}
2017-10-07 04:02:02 +00:00
ref={this.setRef}
type="search"
2017-10-07 04:02:02 +00:00
onChange={this.handleChange}
placeholder={i18n.search}
autoFocus={autoFocus}
/>
{/*
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>
<button
className="emoji-mart-search-icon"
2019-03-10 17:35:07 +00:00
onClick={this.clear}
onKeyUp={this.handleKeyUp}
aria-label={i18n.clear}
2019-03-10 17:35:07 +00:00
disabled={!isSearching}
>
{icon()}
</button>
</section>
2017-10-07 04:02:02 +00:00
)
2016-05-31 18:39:30 +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
}