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

195 lines
4.6 KiB
JavaScript
Raw Normal View History

2016-06-02 15:26:48 +00:00
import '../utils/raf-polyfill'
2016-05-31 14:36:52 +00:00
import React from 'react'
import data from '../../data'
2016-06-02 17:21:31 +00:00
import {Anchors, Category, Preview, Search} from '.'
2016-06-02 15:26:48 +00:00
const DEFAULT_CATEGORIES = [
{ name: 'Recent', emojis: null }
].concat(data.categories)
2016-05-31 14:36:52 +00:00
export default class Picker extends React.Component {
2016-05-31 18:39:30 +00:00
constructor(props) {
super(props)
this.testStickyPosition()
this.state = {
2016-06-02 15:26:48 +00:00
categories: DEFAULT_CATEGORIES,
2016-06-09 00:22:06 +00:00
skin: props.skin,
2016-05-31 18:39:30 +00:00
}
}
2016-06-09 00:22:06 +00:00
componentWillReceiveProps(props) {
this.setState({ skin: props.skin })
}
2016-05-31 18:39:30 +00:00
componentDidUpdate() {
this.handleScroll()
}
testStickyPosition() {
2016-05-31 16:35:08 +00:00
var stickyTestElement = document.createElement('div')
for (let prefix of ['', '-webkit-', '-ms-', '-moz-', '-o-']) {
stickyTestElement.style.position = `${prefix}sticky`
}
this.hasStickyPosition = !!stickyTestElement.style.position.length
}
2016-05-31 14:36:52 +00:00
handleEmojiOver(emoji) {
var { preview } = this.refs
preview.setState({ emoji: emoji })
clearTimeout(this.leaveTimeout)
}
handleEmojiLeave(emoji) {
this.leaveTimeout = setTimeout(() => {
var { preview } = this.refs
preview.setState({ emoji: null })
}, 16)
2016-05-31 14:36:52 +00:00
}
2016-05-31 16:35:08 +00:00
handleScroll() {
2016-06-02 15:26:48 +00:00
if (!this.waitingForPaint) {
this.waitingForPaint = true
window.requestAnimationFrame(this.handleScrollPaint.bind(this))
}
}
handleScrollPaint() {
this.waitingForPaint = false
2016-05-31 16:35:08 +00:00
var target = this.refs.scroll,
2016-06-02 15:26:48 +00:00
scrollTop = target.scrollTop,
2016-06-02 18:58:19 +00:00
scrollingDown = scrollTop > (this.scrollTop || 0),
activeCategory = null,
{ categories } = this.state
2016-05-31 16:35:08 +00:00
2016-06-02 18:58:19 +00:00
for (let i = 0, l = categories.length; i < l; i++) {
let ii = scrollingDown ? (categories.length - 1 - i) : i,
category = categories[ii],
component = this.refs[`category-${ii}`]
2016-06-02 15:26:48 +00:00
if (component) {
let active = component.handleScroll(scrollTop)
if (active && !activeCategory) {
activeCategory = category
2016-05-31 16:35:08 +00:00
}
2016-06-02 15:26:48 +00:00
}
}
if (activeCategory) {
let { anchors } = this.refs,
{ name: categoryName } = activeCategory
if (anchors.state.selected != categoryName) {
anchors.setState({ selected: categoryName })
}
2016-05-31 16:35:08 +00:00
}
2016-06-02 15:26:48 +00:00
this.scrollTop = scrollTop
2016-05-31 16:35:08 +00:00
}
2016-05-31 18:39:30 +00:00
handleSearch(emojis) {
if (emojis == null) {
2016-06-02 15:26:48 +00:00
this.setState({ categories: DEFAULT_CATEGORIES })
2016-05-31 18:39:30 +00:00
} else {
this.setState({ categories: [{
name: 'Search Results',
emojis: emojis,
}]})
}
}
2016-06-02 18:58:19 +00:00
handleAnchorClick(category, i) {
var component = this.refs[`category-${i}`],
{ scroll, anchors } = this.refs
if (component) {
let { top } = component
if (i == 0) {
top = 0
} else {
top += 1
}
scroll.scrollTop = top
}
}
2016-06-09 00:22:06 +00:00
handleSkinChange(skin) {
this.setState({ skin: skin })
}
2016-05-31 14:36:52 +00:00
render() {
2016-06-09 00:22:06 +00:00
var { perLine, emojiSize, sheetURL } = this.props,
{ skin } = this.state,
2016-05-31 18:48:15 +00:00
width = (perLine * (emojiSize + 12)) + 12 + 2
2016-05-31 14:36:52 +00:00
2016-05-31 18:48:15 +00:00
return <div style={{width: width}} className='emoji-picker'>
2016-05-31 14:36:52 +00:00
<div className='emoji-picker-bar'>
2016-06-02 15:26:48 +00:00
<Anchors
ref='anchors'
categories={DEFAULT_CATEGORIES}
2016-06-02 18:58:19 +00:00
onAnchorClick={this.handleAnchorClick.bind(this)}
2016-06-02 15:26:48 +00:00
/>
2016-05-31 14:36:52 +00:00
</div>
2016-05-31 16:35:08 +00:00
<div ref="scroll" className='emoji-picker-scroll' onScroll={this.handleScroll.bind(this)}>
2016-05-31 18:39:30 +00:00
<Search
onSearch={this.handleSearch.bind(this)}
2016-05-31 14:36:52 +00:00
/>
2016-05-31 18:39:30 +00:00
{this.state.categories.map((category, i) => {
2016-05-31 14:36:52 +00:00
return <Category
2016-05-31 16:35:08 +00:00
ref={`category-${i}`}
2016-05-31 14:36:52 +00:00
key={category.name}
name={category.name}
emojis={category.emojis}
2016-05-31 16:35:08 +00:00
hasStickyPosition={this.hasStickyPosition}
2016-05-31 14:36:52 +00:00
emojiProps={{
2016-05-31 23:36:50 +00:00
skin: skin,
2016-05-31 14:36:52 +00:00
size: emojiSize,
sheetURL: sheetURL,
onOver: this.handleEmojiOver.bind(this),
onLeave: this.handleEmojiLeave.bind(this),
2016-05-31 14:36:52 +00:00
onClick: this.props.onClick,
}}
/>
})}
</div>
2016-06-01 19:25:45 +00:00
<div className='emoji-picker-bar'>
2016-05-31 14:36:52 +00:00
<Preview
ref='preview'
emojiProps={{
size: 38,
sheetURL: sheetURL,
}}
2016-06-09 00:22:06 +00:00
skinsProps={{
skin: skin,
onChange: this.handleSkinChange.bind(this)
}}
2016-05-31 14:36:52 +00:00
/>
</div>
</div>
}
}
Picker.propTypes = {
onClick: React.PropTypes.func,
2016-05-31 23:36:50 +00:00
skin: React.PropTypes.number,
2016-05-31 14:36:52 +00:00
perLine: React.PropTypes.number,
emojiSize: React.PropTypes.number,
sheetURL: React.PropTypes.string.isRequired,
}
Picker.defaultProps = {
onClick: (() => {}),
2016-05-31 21:23:51 +00:00
emojiSize: 24,
2016-05-31 14:36:52 +00:00
perLine: 9,
2016-05-31 23:36:50 +00:00
skin: 1,
2016-05-31 14:36:52 +00:00
}