UNPKG

emoji-mart

Version:

Customizable Slack-like emoji picker for React

247 lines (213 loc) 6.45 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } import React from 'react'; import PropTypes from 'prop-types'; import frequently from '../utils/frequently'; import { getData } from '../utils'; import NimbleEmoji from './emoji/nimble-emoji'; import NotFound from './not-found'; export default class Category extends React.Component { constructor(props) { super(props); this.data = props.data; this.setContainerRef = this.setContainerRef.bind(this); this.setLabelRef = this.setLabelRef.bind(this); } componentDidMount() { this.margin = 0; this.minMargin = 0; this.memoizeSize(); } shouldComponentUpdate(nextProps, nextState) { 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; if (name == 'Recent' && perLine != nextPerLine) { shouldUpdate = true; } if (name == 'Search') { shouldUpdate = !(emojis == nextEmojis); } if (skin != nextSkin || size != nextSize || native != nextNative || set != nextSet || hasStickyPosition != nextHasStickyPosition) { shouldUpdate = true; } return shouldUpdate; } memoizeSize() { if (!this.container) { // probably this is a test environment, e.g. jest this.top = 0; this.maxMargin = 0; return; } var parent = this.container.parentElement; var { top, height } = this.container.getBoundingClientRect(); var { top: parentTop } = parent.getBoundingClientRect(); var { height: labelHeight } = this.label.getBoundingClientRect(); this.top = top - parentTop + parent.scrollTop; if (height == 0) { this.maxMargin = 0; } else { this.maxMargin = height - labelHeight; } } 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; if (!this.props.hasStickyPosition) { this.label.style.top = `${margin}px`; } this.margin = margin; return true; } getEmojis() { var { name, emojis, recent, perLine } = this.props; if (name == 'Recent') { let { custom } = this.props; let frequentlyUsed = recent || frequently.get(perLine); if (frequentlyUsed.length) { emojis = frequentlyUsed.map(id => { const emoji = custom.filter(e => e.id === id)[0]; if (emoji) { return emoji; } return id; }).filter(id => !!getData(id, null, null, this.data)); } if (emojis.length === 0 && frequentlyUsed.length > 0) { return null; } } if (emojis) { emojis = emojis.slice(0); } return emojis; } updateDisplay(display) { var emojis = this.getEmojis(); if (!emojis || !this.container) { return; } this.container.style.display = display; } setContainerRef(c) { this.container = c; } setLabelRef(c) { this.label = c; } render() { var { id, name, hasStickyPosition, emojiProps, i18n, notFound, notFoundEmoji } = this.props, emojis = this.getEmojis(), labelStyles = {}, labelSpanStyles = {}, containerStyles = {}; if (!emojis) { containerStyles = { display: 'none' }; } if (!hasStickyPosition) { labelStyles = { height: 28 }; labelSpanStyles = { position: 'absolute' }; } const label = i18n.categories[id] || name; return React.createElement("section", { ref: this.setContainerRef, className: "emoji-mart-category", "aria-label": label, style: containerStyles }, React.createElement("div", { style: labelStyles, "data-name": name, className: "emoji-mart-category-label" }, React.createElement("span", { style: labelSpanStyles, ref: this.setLabelRef, "aria-hidden": true /* already labeled by the section aria-label */ }, label)), React.createElement("ul", { className: "emoji-mart-category-list" }, emojis && emojis.map(emoji => React.createElement("li", { key: emoji.short_names && emoji.short_names.join('_') || emoji }, NimbleEmoji(_objectSpread({ emoji: emoji, data: this.data }, emojiProps))))), emojis && !emojis.length && React.createElement(NotFound, { i18n: i18n, notFound: notFound, notFoundEmoji: notFoundEmoji, data: this.data, emojiProps: emojiProps })); } } Category.propTypes /* remove-proptypes */ = { 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), notFound: PropTypes.func, notFoundEmoji: PropTypes.string.isRequired }; Category.defaultProps = { emojis: [], hasStickyPosition: true };