2016-05-31 14:36:52 +00:00
|
|
|
import React from 'react'
|
2017-05-05 01:38:03 +00:00
|
|
|
import PropTypes from 'prop-types'
|
2016-07-07 18:22:02 +00:00
|
|
|
|
2018-04-30 00:55:13 +00:00
|
|
|
import frequently from '../utils/frequently'
|
|
|
|
import { getData } from '../utils'
|
2018-11-13 10:21:37 +00:00
|
|
|
import NimbleEmoji from './emoji/nimble-emoji'
|
|
|
|
import NotFound from './not-found'
|
2018-04-26 15:47:30 +00:00
|
|
|
|
2018-04-30 00:55:13 +00:00
|
|
|
export default class Category extends React.Component {
|
2017-09-29 14:46:29 +00:00
|
|
|
constructor(props) {
|
|
|
|
super(props)
|
|
|
|
|
2018-03-28 21:30:47 +00:00
|
|
|
this.data = props.data
|
2017-09-29 14:46:29 +00:00
|
|
|
this.setContainerRef = this.setContainerRef.bind(this)
|
|
|
|
this.setLabelRef = this.setLabelRef.bind(this)
|
|
|
|
}
|
|
|
|
|
2016-05-31 16:35:08 +00:00
|
|
|
componentDidMount() {
|
|
|
|
this.margin = 0
|
|
|
|
this.minMargin = 0
|
|
|
|
|
|
|
|
this.memoizeSize()
|
|
|
|
}
|
2016-05-31 14:36:52 +00:00
|
|
|
|
2016-07-08 17:56:29 +00:00
|
|
|
shouldComponentUpdate(nextProps, nextState) {
|
2017-10-07 04:02:02 +00:00
|
|
|
var {
|
|
|
|
name,
|
|
|
|
perLine,
|
|
|
|
native,
|
|
|
|
hasStickyPosition,
|
|
|
|
emojis,
|
|
|
|
emojiProps,
|
|
|
|
} = this.props,
|
|
|
|
{ skin, size, set } = emojiProps,
|
|
|
|
{
|
|
|
|
perLine: nextPerLine,
|
|
|
|
native: nextNative,
|
|
|
|
hasStickyPosition: nextHasStickyPosition,
|
|
|
|
emojis: nextEmojis,
|
|
|
|
emojiProps: nextEmojiProps,
|
|
|
|
} = nextProps,
|
|
|
|
{ skin: nextSkin, size: nextSize, set: nextSet } = nextEmojiProps,
|
|
|
|
shouldUpdate = false
|
2016-07-08 17:56:29 +00:00
|
|
|
|
|
|
|
if (name == 'Recent' && perLine != nextPerLine) {
|
|
|
|
shouldUpdate = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == 'Search') {
|
|
|
|
shouldUpdate = !(emojis == nextEmojis)
|
|
|
|
}
|
|
|
|
|
2017-10-07 04:02:02 +00:00
|
|
|
if (
|
|
|
|
skin != nextSkin ||
|
|
|
|
size != nextSize ||
|
|
|
|
native != nextNative ||
|
|
|
|
set != nextSet ||
|
|
|
|
hasStickyPosition != nextHasStickyPosition
|
|
|
|
) {
|
2016-07-08 17:56:29 +00:00
|
|
|
shouldUpdate = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return shouldUpdate
|
2016-05-31 16:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memoizeSize() {
|
2019-03-14 01:31:13 +00:00
|
|
|
if (!this.container) {
|
|
|
|
// probably this is a test environment, e.g. jest
|
|
|
|
this.top = 0
|
|
|
|
this.maxMargin = 0
|
|
|
|
return
|
|
|
|
}
|
2019-03-10 16:14:47 +00:00
|
|
|
var parent = this.container.parentElement
|
2016-05-31 16:35:08 +00:00
|
|
|
var { top, height } = this.container.getBoundingClientRect()
|
2019-03-10 16:14:47 +00:00
|
|
|
var { top: parentTop } = parent.getBoundingClientRect()
|
2016-05-31 16:35:08 +00:00
|
|
|
var { height: labelHeight } = this.label.getBoundingClientRect()
|
|
|
|
|
2019-03-10 16:14:47 +00:00
|
|
|
this.top = top - parentTop + parent.scrollTop
|
2016-07-08 21:03:41 +00:00
|
|
|
|
2016-07-08 20:28:43 +00:00
|
|
|
if (height == 0) {
|
|
|
|
this.maxMargin = 0
|
2016-06-02 15:26:48 +00:00
|
|
|
} else {
|
2016-07-08 21:03:41 +00:00
|
|
|
this.maxMargin = height - labelHeight
|
2016-06-02 15:26:48 +00:00
|
|
|
}
|
2016-05-31 16:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
handleScroll(scrollTop) {
|
|
|
|
var margin = scrollTop - this.top
|
|
|
|
margin = margin < this.minMargin ? this.minMargin : margin
|
|
|
|
margin = margin > this.maxMargin ? this.maxMargin : margin
|
|
|
|
|
|
|
|
if (margin == this.margin) return
|
2016-06-02 15:26:48 +00:00
|
|
|
|
|
|
|
if (!this.props.hasStickyPosition) {
|
|
|
|
this.label.style.top = `${margin}px`
|
|
|
|
}
|
|
|
|
|
2016-05-31 16:35:08 +00:00
|
|
|
this.margin = margin
|
2016-06-02 15:26:48 +00:00
|
|
|
return true
|
2016-05-31 14:36:52 +00:00
|
|
|
}
|
|
|
|
|
2016-07-08 21:03:41 +00:00
|
|
|
getEmojis() {
|
2017-10-07 14:26:09 +00:00
|
|
|
var { name, emojis, recent, perLine } = this.props
|
2016-05-31 14:36:52 +00:00
|
|
|
|
2016-07-07 18:22:02 +00:00
|
|
|
if (name == 'Recent') {
|
2017-05-27 17:15:17 +00:00
|
|
|
let { custom } = this.props
|
2017-10-07 14:26:09 +00:00
|
|
|
let frequentlyUsed = recent || frequently.get(perLine)
|
2016-05-31 16:35:08 +00:00
|
|
|
|
2016-07-07 18:22:02 +00:00
|
|
|
if (frequentlyUsed.length) {
|
2017-11-08 03:09:40 +00:00
|
|
|
emojis = frequentlyUsed
|
2018-03-27 18:51:26 +00:00
|
|
|
.map((id) => {
|
|
|
|
const emoji = custom.filter((e) => e.id === id)[0]
|
2017-11-08 03:09:40 +00:00
|
|
|
if (emoji) {
|
|
|
|
return emoji
|
|
|
|
}
|
|
|
|
|
|
|
|
return id
|
|
|
|
})
|
2018-03-28 21:30:47 +00:00
|
|
|
.filter((id) => !!getData(id, null, null, this.data))
|
2017-10-09 18:23:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (emojis.length === 0 && frequentlyUsed.length > 0) {
|
2017-11-08 03:09:40 +00:00
|
|
|
return null
|
2016-05-31 16:35:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-07 18:22:02 +00:00
|
|
|
if (emojis) {
|
|
|
|
emojis = emojis.slice(0)
|
2016-07-08 21:03:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return emojis
|
|
|
|
}
|
|
|
|
|
|
|
|
updateDisplay(display) {
|
|
|
|
var emojis = this.getEmojis()
|
|
|
|
|
2019-03-23 16:25:51 +00:00
|
|
|
if (!emojis || !this.container) {
|
2016-07-08 21:03:41 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.container.style.display = display
|
|
|
|
}
|
|
|
|
|
2017-09-27 19:26:50 +00:00
|
|
|
setContainerRef(c) {
|
|
|
|
this.container = c
|
|
|
|
}
|
|
|
|
|
|
|
|
setLabelRef(c) {
|
|
|
|
this.label = c
|
|
|
|
}
|
|
|
|
|
2016-07-08 21:03:41 +00:00
|
|
|
render() {
|
2018-06-21 15:56:40 +00:00
|
|
|
var {
|
|
|
|
id,
|
|
|
|
name,
|
|
|
|
hasStickyPosition,
|
|
|
|
emojiProps,
|
|
|
|
i18n,
|
|
|
|
notFound,
|
2018-07-30 21:06:23 +00:00
|
|
|
notFoundEmoji,
|
2018-06-21 15:56:40 +00:00
|
|
|
} = this.props,
|
2017-10-07 04:02:02 +00:00
|
|
|
emojis = this.getEmojis(),
|
|
|
|
labelStyles = {},
|
|
|
|
labelSpanStyles = {},
|
|
|
|
containerStyles = {}
|
2016-07-08 21:03:41 +00:00
|
|
|
|
|
|
|
if (!emojis) {
|
2016-06-02 15:26:48 +00:00
|
|
|
containerStyles = {
|
2016-07-08 21:03:41 +00:00
|
|
|
display: 'none',
|
2016-06-02 15:26:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-07 18:22:02 +00:00
|
|
|
if (!hasStickyPosition) {
|
|
|
|
labelStyles = {
|
|
|
|
height: 28,
|
|
|
|
}
|
|
|
|
|
|
|
|
labelSpanStyles = {
|
|
|
|
position: 'absolute',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-07 04:02:02 +00:00
|
|
|
return (
|
2019-03-10 04:57:30 +00:00
|
|
|
<section
|
2017-10-07 04:02:02 +00:00
|
|
|
ref={this.setContainerRef}
|
2018-07-30 20:52:15 +00:00
|
|
|
className="emoji-mart-category"
|
2019-03-10 04:57:30 +00:00
|
|
|
aria-label={i18n.categories[id]}
|
2017-10-07 04:02:02 +00:00
|
|
|
style={containerStyles}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
style={labelStyles}
|
|
|
|
data-name={name}
|
|
|
|
className="emoji-mart-category-label"
|
|
|
|
>
|
2019-03-10 04:57:30 +00:00
|
|
|
<span
|
|
|
|
style={labelSpanStyles}
|
|
|
|
ref={this.setLabelRef}
|
|
|
|
aria-hidden={true /* already labeled by the section aria-label */}
|
|
|
|
>
|
2017-12-08 17:45:31 +00:00
|
|
|
{i18n.categories[id]}
|
2017-10-07 04:02:02 +00:00
|
|
|
</span>
|
2016-06-01 15:38:11 +00:00
|
|
|
</div>
|
2017-10-07 04:02:02 +00:00
|
|
|
|
2019-03-13 03:56:50 +00:00
|
|
|
<ul className="emoji-mart-category-list">
|
2019-03-14 15:35:33 +00:00
|
|
|
{emojis &&
|
|
|
|
emojis.map((emoji) => (
|
2019-03-13 06:15:53 +00:00
|
|
|
<li key={emoji.id || emoji}>
|
2019-03-13 03:56:50 +00:00
|
|
|
{NimbleEmoji({ emoji: emoji, data: this.data, ...emojiProps })}
|
|
|
|
</li>
|
2019-03-14 15:35:33 +00:00
|
|
|
))}
|
2019-03-13 03:56:50 +00:00
|
|
|
</ul>
|
2017-10-07 04:02:02 +00:00
|
|
|
|
2019-03-16 17:26:09 +00:00
|
|
|
{emojis && !emojis.length && (
|
|
|
|
<NotFound
|
|
|
|
i18n={i18n}
|
|
|
|
notFound={notFound}
|
|
|
|
notFoundEmoji={notFoundEmoji}
|
|
|
|
data={this.data}
|
|
|
|
emojiProps={emojiProps}
|
|
|
|
/>
|
|
|
|
)}
|
2019-03-10 04:57:30 +00:00
|
|
|
</section>
|
2017-10-07 04:02:02 +00:00
|
|
|
)
|
2016-05-31 14:36:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-18 19:24:52 +00:00
|
|
|
Category.propTypes /* remove-proptypes */ = {
|
2018-04-30 00:55:13 +00:00
|
|
|
emojis: PropTypes.array,
|
|
|
|
hasStickyPosition: PropTypes.bool,
|
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
native: PropTypes.bool.isRequired,
|
|
|
|
perLine: PropTypes.number.isRequired,
|
|
|
|
emojiProps: PropTypes.object.isRequired,
|
|
|
|
recent: PropTypes.arrayOf(PropTypes.string),
|
2018-06-21 15:56:40 +00:00
|
|
|
notFound: PropTypes.func,
|
2018-07-30 21:06:23 +00:00
|
|
|
notFoundEmoji: PropTypes.string.isRequired,
|
2018-04-30 00:55:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Category.defaultProps = {
|
|
|
|
emojis: [],
|
|
|
|
hasStickyPosition: true,
|
2018-04-26 14:36:54 +00:00
|
|
|
}
|