Prettier 💄

release
Etienne Lemay 2017-10-07 00:02:02 -04:00
parent 9ff4c8855c
commit 3021758115
25 changed files with 660 additions and 481 deletions

View File

@ -51,6 +51,7 @@
"karma-jasmine": "^1.1.0", "karma-jasmine": "^1.1.0",
"karma-webpack": "^2.0.4", "karma-webpack": "^2.0.4",
"mkdirp": "0.5.1", "mkdirp": "0.5.1",
"prettier": "1.7.4",
"prop-types": "^15.6.0", "prop-types": "^15.6.0",
"react": "^16.0.0", "react": "^16.0.0",
"react-dom": "^16.0.0", "react-dom": "^16.0.0",
@ -75,7 +76,8 @@
"test": "NODE_ENV=test karma start && size-limit", "test": "NODE_ENV=test karma start && size-limit",
"prepublish": "npm run build", "prepublish": "npm run build",
"storybook": "start-storybook -p 6006", "storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook" "build-storybook": "build-storybook",
"prettier": "prettier --no-semi --single-quote --trailing-comma es5 --write \"src/**/*.js\""
}, },
"size-limit": [ "size-limit": [
{ {

View File

@ -7,18 +7,18 @@ export default class Anchors extends React.PureComponent {
constructor(props) { constructor(props) {
super(props) super(props)
const {categories} = props const { categories } = props
const defaultCategory = categories.filter(category => category.first)[0] const defaultCategory = categories.filter(category => category.first)[0]
this.state = { this.state = {
selected: defaultCategory.name selected: defaultCategory.name,
} }
this.handleClick = this.handleClick.bind(this) this.handleClick = this.handleClick.bind(this)
} }
handleClick (e) { handleClick(e) {
var index = e.currentTarget.getAttribute('data-index') var index = e.currentTarget.getAttribute('data-index')
var { categories, onAnchorClick } = this.props var { categories, onAnchorClick } = this.props
@ -27,32 +27,39 @@ export default class Anchors extends React.PureComponent {
render() { render() {
var { categories, onAnchorClick, color, i18n } = this.props, var { categories, onAnchorClick, color, i18n } = this.props,
{ selected } = this.state { selected } = this.state
return <div className='emoji-mart-anchors'> return (
{categories.map((category, i) => { <div className="emoji-mart-anchors">
var { name, anchor } = category, {categories.map((category, i) => {
var { name, anchor } = category,
isSelected = name == selected isSelected = name == selected
if (anchor === false) { if (anchor === false) {
return null return null
} }
return ( return (
<span <span
key={name} key={name}
title={i18n.categories[name.toLowerCase()]} title={i18n.categories[name.toLowerCase()]}
data-index={i} data-index={i}
onClick={this.handleClick} onClick={this.handleClick}
className={`emoji-mart-anchor ${isSelected ? 'emoji-mart-anchor-selected' : ''}`} className={`emoji-mart-anchor ${isSelected
style={{ color: isSelected ? color : null }} ? 'emoji-mart-anchor-selected'
> : ''}`}
<div dangerouslySetInnerHTML={{ __html: SVGs[name] }}></div> style={{ color: isSelected ? color : null }}
<span className='emoji-mart-anchor-bar' style={{ backgroundColor: color }}></span> >
</span> <div dangerouslySetInnerHTML={{ __html: SVGs[name] }} />
) <span
})} className="emoji-mart-anchor-bar"
</div> style={{ backgroundColor: color }}
/>
</span>
)
})}
</div>
)
} }
} }
@ -63,5 +70,5 @@ Anchors.propTypes = {
Anchors.defaultProps = { Anchors.defaultProps = {
categories: [], categories: [],
onAnchorClick: (() => {}), onAnchorClick: () => {},
} }

View File

@ -22,11 +22,24 @@ export default class Category extends React.Component {
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
var { name, perLine, native, hasStickyPosition, emojis, emojiProps } = this.props, var {
{ skin, size, set } = emojiProps, name,
{ perLine: nextPerLine, native: nextNative, hasStickyPosition: nextHasStickyPosition, emojis: nextEmojis, emojiProps: nextEmojiProps } = nextProps, perLine,
{ skin: nextSkin, size: nextSize, set: nextSet } = nextEmojiProps, native,
shouldUpdate = false 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) { if (name == 'Recent' && perLine != nextPerLine) {
shouldUpdate = true shouldUpdate = true
@ -36,7 +49,13 @@ export default class Category extends React.Component {
shouldUpdate = !(emojis == nextEmojis) shouldUpdate = !(emojis == nextEmojis)
} }
if (skin != nextSkin || size != nextSize || native != nextNative || set != nextSet || hasStickyPosition != nextHasStickyPosition) { if (
skin != nextSkin ||
size != nextSize ||
native != nextNative ||
set != nextSet ||
hasStickyPosition != nextHasStickyPosition
) {
shouldUpdate = true shouldUpdate = true
} }
@ -81,7 +100,7 @@ export default class Category extends React.Component {
let frequentlyUsed = frequently.get(perLine) let frequentlyUsed = frequently.get(perLine)
if (frequentlyUsed.length) { if (frequentlyUsed.length) {
emojis = frequentlyUsed.map((id) => { emojis = frequentlyUsed.map(id => {
const emoji = custom.filter(e => e.id === id)[0] const emoji = custom.filter(e => e.id === id)[0]
if (emoji) { if (emoji) {
return emoji return emoji
@ -119,10 +138,10 @@ export default class Category extends React.Component {
render() { render() {
var { name, hasStickyPosition, emojiProps, i18n } = this.props, var { name, hasStickyPosition, emojiProps, i18n } = this.props,
emojis = this.getEmojis(), emojis = this.getEmojis(),
labelStyles = {}, labelStyles = {},
labelSpanStyles = {}, labelSpanStyles = {},
containerStyles = {} containerStyles = {}
if (!emojis) { if (!emojis) {
containerStyles = { containerStyles = {
@ -140,34 +159,45 @@ export default class Category extends React.Component {
} }
} }
return <div ref={this.setContainerRef} className={`emoji-mart-category ${emojis && !emojis.length ? 'emoji-mart-no-results' : ''}`} style={containerStyles}> return (
<div style={labelStyles} data-name={name} className='emoji-mart-category-label'> <div
<span style={labelSpanStyles} ref={this.setLabelRef}>{i18n.categories[name.toLowerCase()]}</span> ref={this.setContainerRef}
</div> className={`emoji-mart-category ${emojis && !emojis.length
? 'emoji-mart-no-results'
{emojis && emojis.map((emoji) => : ''}`}
Emoji({ emoji: emoji, ...emojiProps }) style={containerStyles}
)} >
<div
{emojis && !emojis.length && style={labelStyles}
<div> data-name={name}
<div> className="emoji-mart-category-label"
{Emoji({ >
...emojiProps, <span style={labelSpanStyles} ref={this.setLabelRef}>
size: 38, {i18n.categories[name.toLowerCase()]}
emoji: 'sleuth_or_spy', </span>
onOver: null,
onLeave: null,
onClick: null,
})}
</div>
<div className='emoji-mart-no-results-label'>
{i18n.notfound}
</div>
</div> </div>
}
</div> {emojis && emojis.map(emoji => Emoji({ emoji: emoji, ...emojiProps }))}
{emojis &&
!emojis.length && (
<div>
<div>
{Emoji({
...emojiProps,
size: 38,
emoji: 'sleuth_or_spy',
onOver: null,
onLeave: null,
onClick: null,
})}
</div>
<div className="emoji-mart-no-results-label">{i18n.notfound}</div>
</div>
)}
</div>
)
} }
} }

View File

@ -6,48 +6,54 @@ import { getData, getSanitizedData, unifiedToNative } from '../utils'
const SHEET_COLUMNS = 49 const SHEET_COLUMNS = 49
const _getPosition = (props) => { const _getPosition = props => {
var { sheet_x, sheet_y } = _getData(props), var { sheet_x, sheet_y } = _getData(props),
multiply = 100 / (SHEET_COLUMNS - 1) multiply = 100 / (SHEET_COLUMNS - 1)
return `${multiply * sheet_x}% ${multiply * sheet_y}%` return `${multiply * sheet_x}% ${multiply * sheet_y}%`
} }
const _getData = (props) => { const _getData = props => {
var { emoji, skin, set } = props var { emoji, skin, set } = props
return getData(emoji, skin, set) return getData(emoji, skin, set)
} }
const _getSanitizedData = (props) => { const _getSanitizedData = props => {
var { emoji, skin, set } = props var { emoji, skin, set } = props
return getSanitizedData(emoji, skin, set) return getSanitizedData(emoji, skin, set)
} }
const _handleClick = (e, props) => { const _handleClick = (e, props) => {
if (!props.onClick) { return } if (!props.onClick) {
return
}
var { onClick } = props, var { onClick } = props,
emoji = _getSanitizedData(props) emoji = _getSanitizedData(props)
onClick(emoji, e) onClick(emoji, e)
} }
const _handleOver = (e, props) => { const _handleOver = (e, props) => {
if (!props.onOver) { return } if (!props.onOver) {
return
}
var { onOver } = props, var { onOver } = props,
emoji = _getSanitizedData(props) emoji = _getSanitizedData(props)
onOver(emoji, e) onOver(emoji, e)
} }
const _handleLeave = (e, props) => { const _handleLeave = (e, props) => {
if (!props.onLeave) { return } if (!props.onLeave) {
return
}
var { onLeave } = props, var { onLeave } = props,
emoji = _getSanitizedData(props) emoji = _getSanitizedData(props)
onLeave(emoji, e) onLeave(emoji, e)
} }
const Emoji = (props) => { const Emoji = props => {
for (let k in Emoji.defaultProps) { for (let k in Emoji.defaultProps) {
if (props[k] == undefined && Emoji.defaultProps[k] != undefined) { if (props[k] == undefined && Emoji.defaultProps[k] != undefined) {
props[k] = Emoji.defaultProps[k] props[k] = Emoji.defaultProps[k]
@ -55,10 +61,10 @@ const Emoji = (props) => {
} }
var { unified, custom, short_names, imageUrl } = _getData(props), var { unified, custom, short_names, imageUrl } = _getData(props),
style = {}, style = {},
children = props.children, children = props.children,
className = 'emoji-mart-emoji', className = 'emoji-mart-emoji',
title = null title = null
if (!unified && !custom) { if (!unified && !custom) {
return null return null
@ -98,21 +104,27 @@ const Emoji = (props) => {
width: props.size, width: props.size,
height: props.size, height: props.size,
display: 'inline-block', display: 'inline-block',
backgroundImage: `url(${props.backgroundImageFn(props.set, props.sheetSize)})`, backgroundImage: `url(${props.backgroundImageFn(
props.set,
props.sheetSize
)})`,
backgroundSize: `${100 * SHEET_COLUMNS}%`, backgroundSize: `${100 * SHEET_COLUMNS}%`,
backgroundPosition: _getPosition(props), backgroundPosition: _getPosition(props),
} }
} }
return <span return (
key={props.emoji.id || props.emoji} <span
onClick={(e) => _handleClick(e, props)} key={props.emoji.id || props.emoji}
onMouseEnter={(e) => _handleOver(e, props)} onClick={e => _handleClick(e, props)}
onMouseLeave={(e) => _handleLeave(e, props)} onMouseEnter={e => _handleOver(e, props)}
title={title} onMouseLeave={e => _handleLeave(e, props)}
className={className}> title={title}
<span style={style}>{children}</span> className={className}
</span> >
<span style={style}>{children}</span>
</span>
)
} }
Emoji.propTypes = { Emoji.propTypes = {
@ -125,12 +137,16 @@ Emoji.propTypes = {
tooltip: PropTypes.bool, tooltip: PropTypes.bool,
skin: PropTypes.oneOf([1, 2, 3, 4, 5, 6]), skin: PropTypes.oneOf([1, 2, 3, 4, 5, 6]),
sheetSize: PropTypes.oneOf([16, 20, 32, 64]), sheetSize: PropTypes.oneOf([16, 20, 32, 64]),
set: PropTypes.oneOf(['apple', 'google', 'twitter', 'emojione', 'messenger', 'facebook']), set: PropTypes.oneOf([
'apple',
'google',
'twitter',
'emojione',
'messenger',
'facebook',
]),
size: PropTypes.number.isRequired, size: PropTypes.number.isRequired,
emoji: PropTypes.oneOfType([ emoji: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
PropTypes.string,
PropTypes.object,
]).isRequired,
} }
Emoji.defaultProps = { Emoji.defaultProps = {
@ -140,10 +156,11 @@ Emoji.defaultProps = {
native: false, native: false,
forceSize: false, forceSize: false,
tooltip: false, tooltip: false,
backgroundImageFn: ((set, sheetSize) => `https://unpkg.com/emoji-datasource-${set}@${EMOJI_DATASOURCE_VERSION}/img/${set}/sheets/${sheetSize}.png`), backgroundImageFn: (set, sheetSize) =>
onOver: (() => {}), `https://unpkg.com/emoji-datasource-${set}@${EMOJI_DATASOURCE_VERSION}/img/${set}/sheets/${sheetSize}.png`,
onLeave: (() => {}), onOver: () => {},
onClick: (() => {}), onLeave: () => {},
onClick: () => {},
} }
export default Emoji export default Emoji

View File

@ -73,16 +73,28 @@ export default class Picker extends React.PureComponent {
}) })
} }
for (let categoryIndex = 0; categoryIndex < allCategories.length; categoryIndex++) { for (
let categoryIndex = 0;
categoryIndex < allCategories.length;
categoryIndex++
) {
const category = allCategories[categoryIndex] const category = allCategories[categoryIndex]
let isIncluded = props.include && props.include.length ? props.include.indexOf(category.name.toLowerCase()) > -1 : true let isIncluded =
let isExcluded = props.exclude && props.exclude.length ? props.exclude.indexOf(category.name.toLowerCase()) > -1 : false props.include && props.include.length
if (!isIncluded || isExcluded) { continue } ? props.include.indexOf(category.name.toLowerCase()) > -1
: true
let isExcluded =
props.exclude && props.exclude.length
? props.exclude.indexOf(category.name.toLowerCase()) > -1
: false
if (!isIncluded || isExcluded) {
continue
}
if (props.emojisToShowFilter) { if (props.emojisToShowFilter) {
let newEmojis = [] let newEmojis = []
const {emojis} = category const { emojis } = category
for (let emojiIndex = 0; emojiIndex < emojis.length; emojiIndex++) { for (let emojiIndex = 0; emojiIndex < emojis.length; emojiIndex++) {
const emoji = emojis[emojiIndex] const emoji = emojis[emojiIndex]
if (props.emojisToShowFilter(data.emojis[emoji] || emoji)) { if (props.emojisToShowFilter(data.emojis[emoji] || emoji)) {
@ -103,8 +115,14 @@ export default class Picker extends React.PureComponent {
} }
} }
let includeRecent = props.include && props.include.length ? props.include.indexOf('recent') > -1 : true let includeRecent =
let excludeRecent = props.exclude && props.exclude.length ? props.exclude.indexOf('recent') > -1 : false props.include && props.include.length
? props.include.indexOf('recent') > -1
: true
let excludeRecent =
props.exclude && props.exclude.length
? props.exclude.indexOf('recent') > -1
: false
if (includeRecent && !excludeRecent) { if (includeRecent && !excludeRecent) {
this.hideRecent = false this.hideRecent = false
this.categories.unshift(RECENT_CATEGORY) this.categories.unshift(RECENT_CATEGORY)
@ -116,18 +134,18 @@ export default class Picker extends React.PureComponent {
this.categories.unshift(SEARCH_CATEGORY) this.categories.unshift(SEARCH_CATEGORY)
this.setAnchorsRef = this.setAnchorsRef.bind(this) this.setAnchorsRef = this.setAnchorsRef.bind(this)
this.handleAnchorClick = this.handleAnchorClick.bind(this) this.handleAnchorClick = this.handleAnchorClick.bind(this)
this.setSearchRef = this.setSearchRef.bind(this) this.setSearchRef = this.setSearchRef.bind(this)
this.handleSearch = this.handleSearch.bind(this) this.handleSearch = this.handleSearch.bind(this)
this.setScrollRef = this.setScrollRef.bind(this) this.setScrollRef = this.setScrollRef.bind(this)
this.handleScroll = this.handleScroll.bind(this) this.handleScroll = this.handleScroll.bind(this)
this.handleScrollPaint = this.handleScrollPaint.bind(this) this.handleScrollPaint = this.handleScrollPaint.bind(this)
this.handleEmojiOver = this.handleEmojiOver.bind(this) this.handleEmojiOver = this.handleEmojiOver.bind(this)
this.handleEmojiLeave = this.handleEmojiLeave.bind(this) this.handleEmojiLeave = this.handleEmojiLeave.bind(this)
this.handleEmojiClick = this.handleEmojiClick.bind(this) this.handleEmojiClick = this.handleEmojiClick.bind(this)
this.setPreviewRef = this.setPreviewRef.bind(this) this.setPreviewRef = this.setPreviewRef.bind(this)
this.handleSkinChange = this.handleSkinChange.bind(this) this.handleSkinChange = this.handleSkinChange.bind(this)
} }
componentWillReceiveProps(props) { componentWillReceiveProps(props) {
@ -162,20 +180,26 @@ export default class Picker extends React.PureComponent {
const prefixes = ['', '-webkit-', '-ms-', '-moz-', '-o-'] const prefixes = ['', '-webkit-', '-ms-', '-moz-', '-o-']
prefixes.forEach(prefix => stickyTestElement.style.position = `${prefix}sticky`) prefixes.forEach(
prefix => (stickyTestElement.style.position = `${prefix}sticky`)
)
this.hasStickyPosition = !!stickyTestElement.style.position.length this.hasStickyPosition = !!stickyTestElement.style.position.length
} }
handleEmojiOver(emoji) { handleEmojiOver(emoji) {
var { preview } = this var { preview } = this
if (!preview) { return } if (!preview) {
return
}
// Use Array.prototype.find() when it is more widely supported. // Use Array.prototype.find() when it is more widely supported.
const emojiData = CUSTOM_CATEGORY.emojis.filter(customEmoji => customEmoji.id === emoji.id)[0] const emojiData = CUSTOM_CATEGORY.emojis.filter(
customEmoji => customEmoji.id === emoji.id
)[0]
for (let key in emojiData) { for (let key in emojiData) {
if (emojiData.hasOwnProperty(key)) { if (emojiData.hasOwnProperty(key)) {
emoji[key] = emojiData[key] emoji[key] = emojiData[key]
} }
} }
@ -185,7 +209,9 @@ export default class Picker extends React.PureComponent {
handleEmojiLeave(emoji) { handleEmojiLeave(emoji) {
var { preview } = this var { preview } = this
if (!preview) { return } if (!preview) {
return
}
this.leaveTimeout = setTimeout(() => { this.leaveTimeout = setTimeout(() => {
preview.setState({ emoji: null }) preview.setState({ emoji: null })
@ -236,14 +262,14 @@ export default class Picker extends React.PureComponent {
activeCategory = SEARCH_CATEGORY activeCategory = SEARCH_CATEGORY
} else { } else {
var target = this.scroll, var target = this.scroll,
scrollTop = target.scrollTop, scrollTop = target.scrollTop,
scrollingDown = scrollTop > (this.scrollTop || 0), scrollingDown = scrollTop > (this.scrollTop || 0),
minTop = 0 minTop = 0
for (let i = 0, l = this.categories.length; i < l; i++) { for (let i = 0, l = this.categories.length; i < l; i++) {
let ii = scrollingDown ? (this.categories.length - 1 - i) : i, let ii = scrollingDown ? this.categories.length - 1 - i : i,
category = this.categories[ii], category = this.categories[ii],
component = this.categoryRefs[`category-${ii}`] component = this.categoryRefs[`category-${ii}`]
if (component) { if (component) {
let active = component.handleScroll(scrollTop) let active = component.handleScroll(scrollTop)
@ -261,7 +287,9 @@ export default class Picker extends React.PureComponent {
} }
if (scrollTop < minTop) { if (scrollTop < minTop) {
activeCategory = this.categories.filter(category => !(category.anchor === false))[0] activeCategory = this.categories.filter(
category => !(category.anchor === false)
)[0]
} else if (scrollTop + this.clientHeight >= this.scrollHeight) { } else if (scrollTop + this.clientHeight >= this.scrollHeight) {
activeCategory = this.categories[this.categories.length - 1] activeCategory = this.categories[this.categories.length - 1]
} }
@ -269,7 +297,7 @@ export default class Picker extends React.PureComponent {
if (activeCategory) { if (activeCategory) {
let { anchors } = this, let { anchors } = this,
{ name: categoryName } = activeCategory { name: categoryName } = activeCategory
if (anchors.state.selected != categoryName) { if (anchors.state.selected != categoryName) {
anchors.setState({ selected: categoryName }) anchors.setState({ selected: categoryName })
@ -298,8 +326,8 @@ export default class Picker extends React.PureComponent {
handleAnchorClick(category, i) { handleAnchorClick(category, i) {
var component = this.categoryRefs[`category-${i}`], var component = this.categoryRefs[`category-${i}`],
{ scroll, anchors } = this, { scroll, anchors } = this,
scrollToComponent = null scrollToComponent = null
scrollToComponent = () => { scrollToComponent = () => {
if (component) { if (component) {
@ -346,7 +374,9 @@ export default class Picker extends React.PureComponent {
} }
getCategories() { getCategories() {
return this.state.firstRender ? this.categories.slice(0, 3) : this.categories return this.state.firstRender
? this.categories.slice(0, 3)
: this.categories
} }
setAnchorsRef(c) { setAnchorsRef(c) {
@ -374,81 +404,110 @@ export default class Picker extends React.PureComponent {
} }
render() { render() {
var { perLine, emojiSize, set, sheetSize, style, title, emoji, color, native, backgroundImageFn, emojisToShowFilter, showPreview, emojiTooltip, include, exclude, autoFocus } = this.props, var {
{ skin } = this.state, perLine,
width = (perLine * (emojiSize + 12)) + 12 + 2 + measureScrollbar() emojiSize,
set,
sheetSize,
style,
title,
emoji,
color,
native,
backgroundImageFn,
emojisToShowFilter,
showPreview,
emojiTooltip,
include,
exclude,
autoFocus,
} = this.props,
{ skin } = this.state,
width = perLine * (emojiSize + 12) + 12 + 2 + measureScrollbar()
return <div style={{width: width, ...style}} className='emoji-mart'> return (
<div className='emoji-mart-bar'> <div style={{ width: width, ...style }} className="emoji-mart">
<Anchors <div className="emoji-mart-bar">
ref={this.setAnchorsRef} <Anchors
i18n={this.i18n} ref={this.setAnchorsRef}
color={color}
categories={this.categories}
onAnchorClick={this.handleAnchorClick}
/>
</div>
<Search
ref={this.setSearchRef}
onSearch={this.handleSearch}
i18n={this.i18n}
emojisToShowFilter={emojisToShowFilter}
include={include}
exclude={exclude}
custom={CUSTOM_CATEGORY.emojis}
autoFocus={autoFocus}
/>
<div ref={this.setScrollRef} className='emoji-mart-scroll' onScroll={this.handleScroll}>
{this.getCategories().map((category, i) => {
return <Category
ref={this.setCategoryRef.bind(this, `category-${i}`)}
key={category.name}
name={category.name}
emojis={category.emojis}
perLine={perLine}
native={native}
hasStickyPosition={this.hasStickyPosition}
i18n={this.i18n} i18n={this.i18n}
custom={category.name == 'Recent' ? CUSTOM_CATEGORY.emojis : undefined} color={color}
emojiProps={{ categories={this.categories}
native: native, onAnchorClick={this.handleAnchorClick}
skin: skin,
size: emojiSize,
set: set,
sheetSize: sheetSize,
forceSize: native,
tooltip: emojiTooltip,
backgroundImageFn: backgroundImageFn,
onOver: this.handleEmojiOver,
onLeave: this.handleEmojiLeave,
onClick: this.handleEmojiClick,
}}
/> />
})} </div>
</div>
{showPreview && <div className='emoji-mart-bar'> <Search
<Preview ref={this.setSearchRef}
ref={this.setPreviewRef} onSearch={this.handleSearch}
title={title} i18n={this.i18n}
emoji={emoji} emojisToShowFilter={emojisToShowFilter}
emojiProps={{ include={include}
native: native, exclude={exclude}
size: 38, custom={CUSTOM_CATEGORY.emojis}
skin: skin, autoFocus={autoFocus}
set: set,
sheetSize: sheetSize,
backgroundImageFn: backgroundImageFn,
}}
skinsProps={{
skin: skin,
onChange: this.handleSkinChange
}}
/> />
</div>}
</div> <div
ref={this.setScrollRef}
className="emoji-mart-scroll"
onScroll={this.handleScroll}
>
{this.getCategories().map((category, i) => {
return (
<Category
ref={this.setCategoryRef.bind(this, `category-${i}`)}
key={category.name}
name={category.name}
emojis={category.emojis}
perLine={perLine}
native={native}
hasStickyPosition={this.hasStickyPosition}
i18n={this.i18n}
custom={
category.name == 'Recent' ? CUSTOM_CATEGORY.emojis : undefined
}
emojiProps={{
native: native,
skin: skin,
size: emojiSize,
set: set,
sheetSize: sheetSize,
forceSize: native,
tooltip: emojiTooltip,
backgroundImageFn: backgroundImageFn,
onOver: this.handleEmojiOver,
onLeave: this.handleEmojiLeave,
onClick: this.handleEmojiClick,
}}
/>
)
})}
</div>
{showPreview && (
<div className="emoji-mart-bar">
<Preview
ref={this.setPreviewRef}
title={title}
emoji={emoji}
emojiProps={{
native: native,
size: 38,
skin: skin,
set: set,
sheetSize: sheetSize,
backgroundImageFn: backgroundImageFn,
}}
skinsProps={{
skin: skin,
onChange: this.handleSkinChange,
}}
/>
</div>
)}
</div>
)
} }
} }
@ -472,17 +531,19 @@ Picker.propTypes = {
include: PropTypes.arrayOf(PropTypes.string), include: PropTypes.arrayOf(PropTypes.string),
exclude: PropTypes.arrayOf(PropTypes.string), exclude: PropTypes.arrayOf(PropTypes.string),
autoFocus: PropTypes.bool, autoFocus: PropTypes.bool,
custom: PropTypes.arrayOf(PropTypes.shape({ custom: PropTypes.arrayOf(
name: PropTypes.string.isRequired, PropTypes.shape({
short_names: PropTypes.arrayOf(PropTypes.string).isRequired, name: PropTypes.string.isRequired,
emoticons: PropTypes.arrayOf(PropTypes.string), short_names: PropTypes.arrayOf(PropTypes.string).isRequired,
keywords: PropTypes.arrayOf(PropTypes.string), emoticons: PropTypes.arrayOf(PropTypes.string),
imageUrl: PropTypes.string.isRequired, keywords: PropTypes.arrayOf(PropTypes.string),
})), imageUrl: PropTypes.string.isRequired,
})
),
} }
Picker.defaultProps = { Picker.defaultProps = {
onClick: (() => {}), onClick: () => {},
emojiSize: 24, emojiSize: 24,
perLine: 9, perLine: 9,
i18n: {}, i18n: {},

View File

@ -1,42 +1,37 @@
import React from 'react'; import React from 'react'
import TestUtils from 'react-dom/test-utils'; import TestUtils from 'react-dom/test-utils'
import Picker from './picker'; import Picker from './picker'
const { const { click } = TestUtils.Simulate
click
} = TestUtils.Simulate;
const { const {
renderIntoDocument, renderIntoDocument,
scryRenderedComponentsWithType, scryRenderedComponentsWithType,
findRenderedComponentWithType, findRenderedComponentWithType,
} = TestUtils; } = TestUtils
describe('Picker', () => { describe('Picker', () => {
let subject; let subject
it('works', () => { it('works', () => {
subject = render(); subject = render()
expect(subject).toBeDefined(); expect(subject).toBeDefined()
}); })
describe('categories', () => { describe('categories', () => {
it('shows 10 by default', () => { it('shows 10 by default', () => {
subject = render(); subject = render()
expect(subject.categories.length).toEqual(10); expect(subject.categories.length).toEqual(10)
}); })
it('will not show some based upon our filter', () => { it('will not show some based upon our filter', () => {
subject = render({emojisToShowFilter: (unified) => false}); subject = render({ emojisToShowFilter: unified => false })
expect(subject.categories.length).toEqual(2); expect(subject.categories.length).toEqual(2)
}); })
}); })
function render(props = {}) { function render(props = {}) {
const defaultProps = { const defaultProps = {}
}; return renderIntoDocument(<Picker {...defaultProps} {...props} />)
return renderIntoDocument(
<Picker {...defaultProps} {...props} />
);
} }
}); })

View File

@ -12,13 +12,13 @@ export default class Preview extends React.PureComponent {
render() { render() {
var { emoji } = this.state, var { emoji } = this.state,
{ emojiProps, skinsProps, title, emoji: idleEmoji } = this.props { emojiProps, skinsProps, title, emoji: idleEmoji } = this.props
if (emoji) { if (emoji) {
var emojiData = getData(emoji), var emojiData = getData(emoji),
{ emoticons = [] } = emojiData, { emoticons = [] } = emojiData,
knownEmoticons = [], knownEmoticons = [],
listedEmoticons = [] listedEmoticons = []
emoticons.forEach(emoticon => { emoticons.forEach(emoticon => {
if (knownEmoticons.indexOf(emoticon.toLowerCase()) >= 0) { if (knownEmoticons.indexOf(emoticon.toLowerCase()) >= 0) {
@ -29,43 +29,49 @@ export default class Preview extends React.PureComponent {
listedEmoticons.push(emoticon) listedEmoticons.push(emoticon)
}) })
return <div className='emoji-mart-preview'> return (
<div className='emoji-mart-preview-emoji'> <div className="emoji-mart-preview">
{Emoji({ key: emoji.id, emoji: emoji, ...emojiProps })} <div className="emoji-mart-preview-emoji">
</div> {Emoji({ key: emoji.id, emoji: emoji, ...emojiProps })}
</div>
<div className='emoji-mart-preview-data'> <div className="emoji-mart-preview-data">
<div className='emoji-mart-preview-name'>{emoji.name}</div> <div className="emoji-mart-preview-name">{emoji.name}</div>
<div className='emoji-mart-preview-shortnames'> <div className="emoji-mart-preview-shortnames">
{emojiData.short_names.map((short_name) => {emojiData.short_names.map(short_name => (
<span key={short_name} className='emoji-mart-preview-shortname'>:{short_name}:</span> <span key={short_name} className="emoji-mart-preview-shortname">
)} :{short_name}:
</div> </span>
<div className='emoji-mart-preview-emoticons'> ))}
{listedEmoticons.map((emoticon) => </div>
<span key={emoticon} className='emoji-mart-preview-emoticon'>{emoticon}</span> <div className="emoji-mart-preview-emoticons">
)} {listedEmoticons.map(emoticon => (
<span key={emoticon} className="emoji-mart-preview-emoticon">
{emoticon}
</span>
))}
</div>
</div> </div>
</div> </div>
</div> )
} else { } else {
return <div className='emoji-mart-preview'> return (
<div className='emoji-mart-preview-emoji'> <div className="emoji-mart-preview">
{idleEmoji && idleEmoji.length && Emoji({ emoji: idleEmoji, ...emojiProps })} <div className="emoji-mart-preview-emoji">
</div> {idleEmoji &&
idleEmoji.length &&
Emoji({ emoji: idleEmoji, ...emojiProps })}
</div>
<div className='emoji-mart-preview-data'> <div className="emoji-mart-preview-data">
<span className='emoji-mart-title-label'> <span className="emoji-mart-title-label">{title}</span>
{title} </div>
</span>
</div>
<div className='emoji-mart-preview-skins'> <div className="emoji-mart-preview-skins">
<Skins <Skins {...skinsProps} />
{...skinsProps} </div>
/>
</div> </div>
</div> )
} }
} }
} }

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import emojiIndex from '../utils/emoji-index' import emojiIndex from '../utils/emoji-index'
export default class Search extends React.PureComponent { export default class Search extends React.PureComponent {
constructor (props) { constructor(props) {
super(props) super(props)
this.setRef = this.setRef.bind(this) this.setRef = this.setRef.bind(this)
@ -13,13 +13,15 @@ export default class Search extends React.PureComponent {
handleChange() { handleChange() {
var value = this.input.value var value = this.input.value
this.props.onSearch(emojiIndex.search(value, { this.props.onSearch(
emojisToShowFilter: this.props.emojisToShowFilter, emojiIndex.search(value, {
maxResults: this.props.maxResults, emojisToShowFilter: this.props.emojisToShowFilter,
include: this.props.include, maxResults: this.props.maxResults,
exclude: this.props.exclude, include: this.props.include,
custom: this.props.custom, exclude: this.props.exclude,
})) custom: this.props.custom,
})
)
} }
setRef(c) { setRef(c) {
@ -33,15 +35,17 @@ export default class Search extends React.PureComponent {
render() { render() {
var { i18n, autoFocus } = this.props var { i18n, autoFocus } = this.props
return <div className='emoji-mart-search'> return (
<input <div className="emoji-mart-search">
ref={this.setRef} <input
type='text' ref={this.setRef}
onChange={this.handleChange} type="text"
placeholder={i18n.search} onChange={this.handleChange}
autoFocus={autoFocus} placeholder={i18n.search}
/> autoFocus={autoFocus}
</div> />
</div>
)
} }
} }
@ -53,7 +57,7 @@ Search.propTypes = {
} }
Search.defaultProps = { Search.defaultProps = {
onSearch: (() => {}), onSearch: () => {},
maxResults: 75, maxResults: 75,
emojisToShowFilter: null, emojisToShowFilter: null,
autoFocus: false, autoFocus: false,

View File

@ -39,21 +39,30 @@ export default class Skins extends React.PureComponent {
skinToneNodes.push( skinToneNodes.push(
<span <span
key={`skin-tone-${skinTone}`} key={`skin-tone-${skinTone}`}
className={`emoji-mart-skin-swatch ${selected ? 'emoji-mart-skin-swatch-selected' : ''}`} className={`emoji-mart-skin-swatch ${selected
? 'emoji-mart-skin-swatch-selected'
: ''}`}
> >
<span <span
onClick={this.handleClick} onClick={this.handleClick}
data-skin={skinTone} data-skin={skinTone}
className={`emoji-mart-skin emoji-mart-skin-tone-${skinTone}`} /> className={`emoji-mart-skin emoji-mart-skin-tone-${skinTone}`}
/>
</span> </span>
) )
} }
return <div> return (
<div className={`emoji-mart-skin-swatches ${opened ? 'emoji-mart-skin-swatches-opened' : ''}`}> <div>
{skinToneNodes} <div
className={`emoji-mart-skin-swatches ${opened
? 'emoji-mart-skin-swatches-opened'
: ''}`}
>
{skinToneNodes}
</div>
</div> </div>
</div> )
} }
} }
@ -63,5 +72,5 @@ Skins.propTypes = {
} }
Skins.defaultProps = { Skins.defaultProps = {
onChange: (() => {}), onChange: () => {},
} }

View File

@ -1,7 +1,7 @@
import buildSearch from '../utils/build-search' import buildSearch from '../utils/build-search'
import data from './data' import data from './data'
function uncompress (list) { function uncompress(list) {
for (var short_name in list) { for (var short_name in list) {
var datum = list[short_name] var datum = list[short_name]
@ -19,7 +19,7 @@ function uncompress (list) {
short_names: datum.short_names, short_names: datum.short_names,
name: datum.name, name: datum.name,
keywords: datum.keywords, keywords: datum.keywords,
emoticons: datum.emoticons emoticons: datum.emoticons,
}) })
} }
} }

View File

@ -3,17 +3,17 @@ const _Object = Object
export default (function createClass() { export default (function createClass() {
function defineProperties(target, props) { function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) { for (var i = 0; i < props.length; i++) {
var descriptor = props[i]; var descriptor = props[i]
descriptor.enumerable = descriptor.enumerable || false; descriptor.enumerable = descriptor.enumerable || false
descriptor.configurable = true; descriptor.configurable = true
if ("value" in descriptor) descriptor.writable = true; if ('value' in descriptor) descriptor.writable = true
_Object.defineProperty(target, descriptor.key, descriptor); _Object.defineProperty(target, descriptor.key, descriptor)
} }
} }
return function (Constructor, protoProps, staticProps) { return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps); if (protoProps) defineProperties(Constructor.prototype, protoProps)
if (staticProps) defineProperties(Constructor, staticProps); if (staticProps) defineProperties(Constructor, staticProps)
return Constructor; return Constructor
}; }
}()); })()

View File

@ -1,15 +1,16 @@
const _Object = Object const _Object = Object
export default _Object.assign || function (target) { export default _Object.assign ||
for (var i = 1; i < arguments.length; i++) { function(target) {
var source = arguments[i]; for (var i = 1; i < arguments.length; i++) {
var source = arguments[i]
for (var key in source) { for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) { if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key]; target[key] = source[key]
}
} }
} }
}
return target; return target
}; }

View File

@ -1,8 +1,11 @@
const _Object = Object const _Object = Object
export default function inherits(subClass, superClass) { export default function inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) { if (typeof superClass !== 'function' && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); throw new TypeError(
'Super expression must either be null or a function, not ' +
typeof superClass
)
} }
subClass.prototype = _Object.create(superClass && superClass.prototype, { subClass.prototype = _Object.create(superClass && superClass.prototype, {
@ -10,10 +13,12 @@ export default function inherits(subClass, superClass) {
value: subClass, value: subClass,
enumerable: false, enumerable: false,
writable: true, writable: true,
configurable: true configurable: true,
} },
}); })
if (superClass) { if (superClass) {
_Object.setPrototypeOf ? _Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; _Object.setPrototypeOf
? _Object.setPrototypeOf(subClass, superClass)
: (subClass.__proto__ = superClass)
} }
}; }

View File

@ -1,11 +1,12 @@
const _Object = Object const _Object = Object
export default _Object.getPrototypeOf || function (O) { export default _Object.getPrototypeOf ||
O = Object(O) function(O) {
O = Object(O)
if (typeof O.constructor === 'function' && O instanceof O.constructor) { if (typeof O.constructor === 'function' && O instanceof O.constructor) {
return O.constructor.prototype return O.constructor.prototype
}
return O instanceof Object ? Object.prototype : null
} }
return O instanceof Object ? Object.prototype : null
};

View File

@ -1,7 +1,11 @@
export default function possibleConstructorReturn(self, call) { export default function possibleConstructorReturn(self, call) {
if (!self) { if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); throw new ReferenceError(
"this hasn't been initialised - super() hasn't been called"
)
} }
return call && (typeof call === "object" || typeof call === "function") ? call : self; return call && (typeof call === 'object' || typeof call === 'function')
}; ? call
: self
}

View File

@ -1,39 +1,42 @@
const _String = String const _String = String
export default _String.fromCodePoint || function stringFromCodePoint() { export default _String.fromCodePoint ||
var MAX_SIZE = 0x4000; function stringFromCodePoint() {
var codeUnits = []; var MAX_SIZE = 0x4000
var highSurrogate; var codeUnits = []
var lowSurrogate; var highSurrogate
var index = -1; var lowSurrogate
var length = arguments.length; var index = -1
if (!length) { var length = arguments.length
return ''; if (!length) {
return ''
}
var result = ''
while (++index < length) {
var codePoint = Number(arguments[index])
if (
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint < 0 || // not a valid Unicode code point
codePoint > 0x10ffff || // not a valid Unicode code point
Math.floor(codePoint) != codePoint // not an integer
) {
throw RangeError('Invalid code point: ' + codePoint)
}
if (codePoint <= 0xffff) {
// BMP code point
codeUnits.push(codePoint)
} else {
// Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000
highSurrogate = (codePoint >> 10) + 0xd800
lowSurrogate = codePoint % 0x400 + 0xdc00
codeUnits.push(highSurrogate, lowSurrogate)
}
if (index + 1 === length || codeUnits.length > MAX_SIZE) {
result += String.fromCharCode.apply(null, codeUnits)
codeUnits.length = 0
}
}
return result
} }
var result = '';
while (++index < length) {
var codePoint = Number(arguments[index]);
if (
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint < 0 || // not a valid Unicode code point
codePoint > 0x10FFFF || // not a valid Unicode code point
Math.floor(codePoint) != codePoint // not an integer
) {
throw RangeError('Invalid code point: ' + codePoint);
}
if (codePoint <= 0xFFFF) { // BMP code point
codeUnits.push(codePoint);
} else { // Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000;
highSurrogate = (codePoint >> 10) + 0xD800;
lowSurrogate = (codePoint % 0x400) + 0xDC00;
codeUnits.push(highSurrogate, lowSurrogate);
}
if (index + 1 === length || codeUnits.length > MAX_SIZE) {
result += String.fromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
}
}
return result;
};

View File

@ -6,8 +6,8 @@ export default data => {
return return
} }
(Array.isArray(strings) ? strings : [strings]).forEach((string) => { ;(Array.isArray(strings) ? strings : [strings]).forEach(string => {
(split ? string.split(/[-|_|\s]+/) : [string]).forEach((s) => { ;(split ? string.split(/[-|_|\s]+/) : [string]).forEach(s => {
s = s.toLowerCase() s = s.toLowerCase()
if (search.indexOf(s) == -1) { if (search.indexOf(s) == -1) {

View File

@ -8,8 +8,8 @@ var emoticonsList = {}
for (let emoji in data.emojis) { for (let emoji in data.emojis) {
let emojiData = data.emojis[emoji], let emojiData = data.emojis[emoji],
{ short_names, emoticons } = emojiData, { short_names, emoticons } = emojiData,
id = short_names[0] id = short_names[0]
if (emoticons) { if (emoticons) {
emoticons.forEach(emoticon => { emoticons.forEach(emoticon => {
@ -26,7 +26,7 @@ for (let emoji in data.emojis) {
} }
function addCustomToPool(custom, pool) { function addCustomToPool(custom, pool) {
custom.forEach((emoji) => { custom.forEach(emoji => {
let emojiId = emoji.id || emoji.short_names[0] let emojiId = emoji.id || emoji.short_names[0]
if (emojiId && !pool[emojiId]) { if (emojiId && !pool[emojiId]) {
@ -36,7 +36,10 @@ function addCustomToPool(custom, pool) {
}) })
} }
function search(value, { emojisToShowFilter, maxResults, include, exclude, custom = [] } = {}) { function search(
value,
{ emojisToShowFilter, maxResults, include, exclude, custom = [] } = {}
) {
addCustomToPool(custom, originalPool) addCustomToPool(custom, originalPool)
maxResults || (maxResults = 75) maxResults || (maxResults = 75)
@ -44,7 +47,7 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
exclude || (exclude = []) exclude || (exclude = [])
var results = null, var results = null,
pool = originalPool pool = originalPool
if (value.length) { if (value.length) {
if (value == '-' || value == '-1') { if (value == '-' || value == '-1') {
@ -52,7 +55,7 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
} }
var values = value.toLowerCase().split(/[\s|,|\-|_]+/), var values = value.toLowerCase().split(/[\s|,|\-|_]+/),
allResults = [] allResults = []
if (values.length > 2) { if (values.length > 2) {
values = [values[0], values[1]] values = [values[0], values[1]]
@ -62,72 +65,84 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
pool = {} pool = {}
data.categories.forEach(category => { data.categories.forEach(category => {
let isIncluded = include && include.length ? include.indexOf(category.name.toLowerCase()) > -1 : true let isIncluded =
let isExcluded = exclude && exclude.length ? exclude.indexOf(category.name.toLowerCase()) > -1 : false include && include.length
? include.indexOf(category.name.toLowerCase()) > -1
: true
let isExcluded =
exclude && exclude.length
? exclude.indexOf(category.name.toLowerCase()) > -1
: false
if (!isIncluded || isExcluded) { if (!isIncluded || isExcluded) {
return return
} }
category.emojis.forEach(emojiId => pool[emojiId] = data.emojis[emojiId]) category.emojis.forEach(
emojiId => (pool[emojiId] = data.emojis[emojiId])
)
}) })
if (custom.length) { if (custom.length) {
let customIsIncluded = include && include.length ? include.indexOf('custom') > -1 : true let customIsIncluded =
let customIsExcluded = exclude && exclude.length ? exclude.indexOf('custom') > -1 : false include && include.length ? include.indexOf('custom') > -1 : true
let customIsExcluded =
exclude && exclude.length ? exclude.indexOf('custom') > -1 : false
if (customIsIncluded && !customIsExcluded) { if (customIsIncluded && !customIsExcluded) {
addCustomToPool(custom, pool) addCustomToPool(custom, pool)
} }
} }
} }
allResults = values.map((value) => { allResults = values
var aPool = pool, .map(value => {
var aPool = pool,
aIndex = index, aIndex = index,
length = 0 length = 0
for (let charIndex = 0; charIndex < value.length; charIndex++) { for (let charIndex = 0; charIndex < value.length; charIndex++) {
const char = value[charIndex] const char = value[charIndex]
length++ length++
aIndex[char] || (aIndex[char] = {}) aIndex[char] || (aIndex[char] = {})
aIndex = aIndex[char] aIndex = aIndex[char]
if (!aIndex.results) { if (!aIndex.results) {
let scores = {} let scores = {}
aIndex.results = [] aIndex.results = []
aIndex.pool = {} aIndex.pool = {}
for (let id in aPool) { for (let id in aPool) {
let emoji = aPool[id], let emoji = aPool[id],
{ search } = emoji, { search } = emoji,
sub = value.substr(0, length), sub = value.substr(0, length),
subIndex = search.indexOf(sub) subIndex = search.indexOf(sub)
if (subIndex != -1) { if (subIndex != -1) {
let score = subIndex + 1 let score = subIndex + 1
if (sub == id) score = 0 if (sub == id) score = 0
aIndex.results.push(emojisList[id]) aIndex.results.push(emojisList[id])
aIndex.pool[id] = emoji aIndex.pool[id] = emoji
scores[id] = score scores[id] = score
}
} }
}
aIndex.results.sort((a, b) => { aIndex.results.sort((a, b) => {
var aScore = scores[a.id], var aScore = scores[a.id],
bScore = scores[b.id] bScore = scores[b.id]
return aScore - bScore return aScore - bScore
}) })
}
aPool = aIndex.pool
} }
aPool = aIndex.pool return aIndex.results
} })
.filter(a => a)
return aIndex.results
}).filter(a => a)
if (allResults.length > 1) { if (allResults.length > 1) {
results = intersect.apply(null, allResults) results = intersect.apply(null, allResults)
@ -140,7 +155,9 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
if (results) { if (results) {
if (emojisToShowFilter) { if (emojisToShowFilter) {
results = results.filter((result) => emojisToShowFilter(data.emojis[result.id].unified)) results = results.filter(result =>
emojisToShowFilter(data.emojis[result.id].unified)
)
} }
if (results && results.length > maxResults) { if (results && results.length > maxResults) {

View File

@ -1,36 +1,42 @@
import emojiIndex from './emoji-index'; import emojiIndex from './emoji-index'
describe('#emojiIndex', () => { describe('#emojiIndex', () => {
describe('search', function() { describe('search', function() {
it('should work', () => { it('should work', () => {
expect(emojiIndex.search('pineapple')).toEqual([{ expect(emojiIndex.search('pineapple')).toEqual([
id: 'pineapple', {
name: 'Pineapple', id: 'pineapple',
colons: ':pineapple:', name: 'Pineapple',
emoticons: [ ], colons: ':pineapple:',
unified: '1f34d', emoticons: [],
skin: null, unified: '1f34d',
native: '🍍' skin: null,
}]); native: '🍍',
}); },
])
})
it('should filter only emojis we care about, exclude pineapple', () => { it('should filter only emojis we care about, exclude pineapple', () => {
let emojisToShowFilter = (unified) => unified !== '1F34D'; let emojisToShowFilter = unified => unified !== '1F34D'
expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id)) expect(
.not.toContain('pineapple'); emojiIndex.search('apple', { emojisToShowFilter }).map(obj => obj.id)
}); ).not.toContain('pineapple')
})
it('can include/exclude categories', () => { it('can include/exclude categories', () => {
expect(emojiIndex.search('flag', { include: ['people'] })) expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([])
.toEqual([])
}) })
it('can search for thinking_face', () => { it('can search for thinking_face', () => {
expect(emojiIndex.search('thinking_fac').map(x => x.id)).toEqual(['thinking_face']) expect(emojiIndex.search('thinking_fac').map(x => x.id)).toEqual([
'thinking_face',
])
}) })
it('can search for woman-facepalming', () => { it('can search for woman-facepalming', () => {
expect(emojiIndex.search('woman-facep').map(x => x.id)).toEqual(['woman-facepalming']); expect(emojiIndex.search('woman-facep').map(x => x.id)).toEqual([
'woman-facepalming',
])
}) })
}); })
}); })

View File

@ -52,11 +52,13 @@ function get(perLine) {
for (let key in frequently) { for (let key in frequently) {
if (frequently.hasOwnProperty(key)) { if (frequently.hasOwnProperty(key)) {
frequentlyKeys.push(key); frequentlyKeys.push(key)
} }
} }
const sorted = frequentlyKeys.sort((a, b) => frequently[a] - frequently[b]).reverse() const sorted = frequentlyKeys
.sort((a, b) => frequently[a] - frequently[b])
.reverse()
const sliced = sorted.slice(0, quantity) const sliced = sorted.slice(0, quantity)
const last = store.get('last') const last = store.get('last')

View File

@ -5,22 +5,28 @@ import stringFromCodePoint from '../polyfills/stringFromCodePoint'
const _JSON = JSON const _JSON = JSON
const COLONS_REGEX = /^(?:\:([^\:]+)\:)(?:\:skin-tone-(\d)\:)?$/ const COLONS_REGEX = /^(?:\:([^\:]+)\:)(?:\:skin-tone-(\d)\:)?$/
const SKINS = [ const SKINS = ['1F3FA', '1F3FB', '1F3FC', '1F3FD', '1F3FE', '1F3FF']
'1F3FA', '1F3FB', '1F3FC',
'1F3FD', '1F3FE', '1F3FF',
]
function unifiedToNative(unified) { function unifiedToNative(unified) {
var unicodes = unified.split('-'), var unicodes = unified.split('-'),
codePoints = unicodes.map((u) => `0x${u}`) codePoints = unicodes.map(u => `0x${u}`)
return stringFromCodePoint.apply(null, codePoints) return stringFromCodePoint.apply(null, codePoints)
} }
function sanitize(emoji) { function sanitize(emoji) {
var { name, short_names, skin_tone, skin_variations, emoticons, unified, custom, imageUrl } = emoji, var {
id = emoji.id || short_names[0], name,
colons = `:${id}:` short_names,
skin_tone,
skin_variations,
emoticons,
unified,
custom,
imageUrl,
} = emoji,
id = emoji.id || short_names[0],
colons = `:${id}:`
if (custom) { if (custom) {
return { return {
@ -29,7 +35,7 @@ function sanitize(emoji) {
colons, colons,
emoticons, emoticons,
custom, custom,
imageUrl imageUrl,
} }
} }
@ -100,7 +106,7 @@ function getData(emoji, skin, set) {
emojiData = JSON.parse(_JSON.stringify(emojiData)) emojiData = JSON.parse(_JSON.stringify(emojiData))
var skinKey = SKINS[skin - 1], var skinKey = SKINS[skin - 1],
variationData = emojiData.skin_variations[skinKey] variationData = emojiData.skin_variations[skinKey]
if (!variationData.variations && emojiData.variations) { if (!variationData.variations && emojiData.variations) {
delete emojiData.variations delete emojiData.variations
@ -145,7 +151,7 @@ function deepMerge(a, b) {
for (let key in a) { for (let key in a) {
let originalValue = a[key], let originalValue = a[key],
value = originalValue value = originalValue
if (b.hasOwnProperty(key)) { if (b.hasOwnProperty(key)) {
value = b[key] value = b[key]
@ -185,5 +191,5 @@ export {
intersect, intersect,
deepMerge, deepMerge,
unifiedToNative, unifiedToNative,
measureScrollbar measureScrollbar,
} }

View File

@ -2,8 +2,8 @@ var NAMESPACE = 'emoji-mart'
const _JSON = JSON const _JSON = JSON
var isLocalStorageSupported = typeof window !== 'undefined' && var isLocalStorageSupported =
'localStorage' in window typeof window !== 'undefined' && 'localStorage' in window
function update(state) { function update(state) {
for (let key in state) { for (let key in state) {
@ -16,8 +16,7 @@ function set(key, value) {
if (!isLocalStorageSupported) return if (!isLocalStorageSupported) return
try { try {
window.localStorage[`${NAMESPACE}.${key}`] = _JSON.stringify(value) window.localStorage[`${NAMESPACE}.${key}`] = _JSON.stringify(value)
} catch (e) { } catch (e) {}
}
} }
function get(key) { function get(key) {

View File

@ -7,28 +7,33 @@
var isWindowAvailable = typeof window !== 'undefined' var isWindowAvailable = typeof window !== 'undefined'
isWindowAvailable && (function() { isWindowAvailable &&
var lastTime = 0; (function() {
var vendors = ['ms', 'moz', 'webkit', 'o']; var lastTime = 0
var vendors = ['ms', 'moz', 'webkit', 'o']
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.requestAnimationFrame =
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] window[vendors[x] + 'RequestAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame']; window.cancelAnimationFrame =
window[vendors[x] + 'CancelAnimationFrame'] ||
window[vendors[x] + 'CancelRequestAnimationFrame']
} }
if (!window.requestAnimationFrame) if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) { window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime(); var currTime = new Date().getTime()
var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var timeToCall = Math.max(0, 16 - (currTime - lastTime))
var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); var id = window.setTimeout(function() {
callback(currTime + timeToCall)
}, timeToCall)
lastTime = currTime + timeToCall; lastTime = currTime + timeToCall
return id; return id
}; }
if (!window.cancelAnimationFrame) if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) { window.cancelAnimationFrame = function(id) {
clearTimeout(id); clearTimeout(id)
}; }
}()); })()

View File

@ -1,10 +1,11 @@
var path = require('path') var path = require('path')
var pack = require('../package.json') var pack = require('../package.json')
var webpack = require('webpack') var webpack = require('webpack')
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; var BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
.BundleAnalyzerPlugin
var PROD = process.env.NODE_ENV === 'production'; var PROD = process.env.NODE_ENV === 'production'
var TEST = process.env.NODE_ENV === 'test'; var TEST = process.env.NODE_ENV === 'test'
var config = { var config = {
entry: path.resolve('src/index.js'), entry: path.resolve('src/index.js'),
@ -22,28 +23,22 @@ var config = {
{ {
test: /\.js$/, test: /\.js$/,
use: 'babel-loader', use: 'babel-loader',
include: [ include: [path.resolve('src'), path.resolve('data')],
path.resolve('src'),
path.resolve('node_modules/measure-scrollbar'),
path.resolve('data'),
],
}, },
{ {
test: /\.svg$/, test: /\.svg$/,
use: [ use: [
{ {
loader: 'babel-loader' loader: 'babel-loader',
}, },
{ {
loader: 'svg-jsx-loader', loader: 'svg-jsx-loader',
options: { options: {
es6: true es6: true,
} },
}, },
], ],
include: [ include: [path.resolve('src/svgs')],
path.resolve('src/svgs'),
],
}, },
], ],
}, },
@ -64,7 +59,7 @@ var config = {
if (!TEST) { if (!TEST) {
config.externals = config.externals.concat([ config.externals = config.externals.concat([
{ {
'react': { react: {
root: 'React', root: 'React',
commonjs2: 'react', commonjs2: 'react',
commonjs: 'react', commonjs: 'react',

View File

@ -4751,6 +4751,10 @@ preserve@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
prettier@1.7.4:
version "1.7.4"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.7.4.tgz#5e8624ae9363c80f95ec644584ecdf55d74f93fa"
private@^0.1.6, private@^0.1.7, private@~0.1.5: private@^0.1.6, private@^0.1.7, private@~0.1.5:
version "0.1.7" version "0.1.7"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"