Add custom emoji lazyload
parent
fe28ab637b
commit
7edf171664
|
@ -137,7 +137,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoji-mart-category .emoji-mart-emoji:hover:before {
|
.emoji-mart-category .emoji-mart-emoji:hover:before {
|
||||||
z-index: 0;
|
z-index: -1;
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0; left: 0;
|
top: 0; left: 0;
|
||||||
|
|
177
package.json
177
package.json
|
@ -1,88 +1,89 @@
|
||||||
{
|
{
|
||||||
"name": "emoji-mart",
|
"name": "emoji-mart-lazyload",
|
||||||
"version": "3.0.1",
|
"version": "3.0.1h",
|
||||||
"description": "Customizable Slack-like emoji picker for React",
|
"description": "Customizable Slack-like emoji picker for React",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist-es/index.js",
|
"module": "dist-es/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@github.com:missive/emoji-mart.git"
|
"url": "git@github.com:mashirozx/emoji-mart.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"emoji",
|
"emoji",
|
||||||
"picker"
|
"picker"
|
||||||
],
|
],
|
||||||
"author": "Etienne Lemay",
|
"author": "Etienne Lemay",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/missive/emoji-mart/issues"
|
"url": "https://github.com/mashirozx/emoji-mart/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/missive/emoji-mart",
|
"homepage": "https://github.com/mashirozx/emoji-mart",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.0.0",
|
"@babel/runtime": "^7.0.0",
|
||||||
"prop-types": "^15.6.0"
|
"intersection-observer": "^0.12.0",
|
||||||
},
|
"prop-types": "^15.6.0"
|
||||||
"peerDependencies": {
|
},
|
||||||
"react": "^0.14.0 || ^15.0.0-0 || ^16.0.0 || ^17.0.0"
|
"peerDependencies": {
|
||||||
},
|
"react": "^0.14.0 || ^15.0.0-0 || ^16.0.0 || ^17.0.0"
|
||||||
"devDependencies": {
|
},
|
||||||
"@babel/cli": "^7.0.0",
|
"devDependencies": {
|
||||||
"@babel/core": "^7.0.0",
|
"@babel/cli": "^7.0.0",
|
||||||
"@babel/plugin-transform-runtime": "^7.7.6",
|
"@babel/core": "^7.0.0",
|
||||||
"@babel/preset-env": "^7.0.0",
|
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||||
"@babel/preset-react": "7.0.0",
|
"@babel/preset-env": "^7.0.0",
|
||||||
"@storybook/addon-actions": "^3.2.11",
|
"@babel/preset-react": "7.0.0",
|
||||||
"@storybook/addon-knobs": "^3.2.10",
|
"@storybook/addon-actions": "^3.2.11",
|
||||||
"@storybook/addon-links": "^3.2.10",
|
"@storybook/addon-knobs": "^3.2.10",
|
||||||
"@storybook/addon-options": "3.2.10",
|
"@storybook/addon-links": "^3.2.10",
|
||||||
"@storybook/react": "^3.2.11",
|
"@storybook/addon-options": "3.2.10",
|
||||||
"babel-jest": "^24.9.0",
|
"@storybook/react": "^3.2.11",
|
||||||
"babel-loader": "^8.0.0",
|
"babel-jest": "^24.9.0",
|
||||||
"babel-plugin-transform-define": "^2.0.0",
|
"babel-loader": "^8.0.0",
|
||||||
"emoji-datasource": "5.0.1",
|
"babel-plugin-transform-define": "^2.0.0",
|
||||||
"emojilib": "^2.2.1",
|
"emoji-datasource": "5.0.1",
|
||||||
"enzyme": "^3.9.0",
|
"emojilib": "^2.2.1",
|
||||||
"enzyme-adapter-react-16": "^1.11.2",
|
"enzyme": "^3.9.0",
|
||||||
"inflection": "1.10.0",
|
"enzyme-adapter-react-16": "^1.11.2",
|
||||||
"jest": "^24.9.0",
|
"inflection": "1.10.0",
|
||||||
"mkdirp": "0.5.1",
|
"jest": "^24.9.0",
|
||||||
"prettier": "^1.16.4",
|
"mkdirp": "0.5.1",
|
||||||
"react": "^16.0.0",
|
"prettier": "^1.16.4",
|
||||||
"react-dom": "^16.0.0",
|
"react": "^16.0.0",
|
||||||
"react-test-renderer": "^16.8.4",
|
"react-dom": "^16.0.0",
|
||||||
"rimraf": "2.5.2",
|
"react-test-renderer": "^16.8.4",
|
||||||
"size-limit": "^0.11.4",
|
"rimraf": "2.5.2",
|
||||||
"webpack": "^3.6.0"
|
"size-limit": "^0.11.4",
|
||||||
},
|
"webpack": "^3.6.0"
|
||||||
"scripts": {
|
},
|
||||||
"clean": "rm -rf dist/ dist-es/ dist-modern/",
|
"scripts": {
|
||||||
"build:data": "node scripts/build-data",
|
"clean": "rm -rf dist/ dist-es/ dist-modern/",
|
||||||
"build:dist": "npm run build:cjs && npm run build:es && npm run build:modern",
|
"build:data": "node scripts/build-data",
|
||||||
"build:cjs": "BABEL_ENV=legacy-cjs babel src --out-dir dist --ignore '**/__tests__/*'",
|
"build:dist": "npm run build:cjs && npm run build:es && npm run build:modern",
|
||||||
"build:es": "BABEL_ENV=legacy-es babel src --out-dir dist-es --ignore '**/__tests__/*'",
|
"build:cjs": "BABEL_ENV=legacy-cjs babel src --out-dir dist --ignore '**/__tests__/*'",
|
||||||
"build:modern": "BABEL_ENV=modern babel src --out-dir dist-modern --ignore '**/__tests__/*'",
|
"build:es": "BABEL_ENV=legacy-es babel src --out-dir dist-es --ignore '**/__tests__/*'",
|
||||||
"build:docs": "cp css/emoji-mart.css docs && webpack --config ./docs/webpack.config.js",
|
"build:modern": "BABEL_ENV=modern babel src --out-dir dist-modern --ignore '**/__tests__/*'",
|
||||||
"build": "npm run clean && npm run build:dist",
|
"build:docs": "cp css/emoji-mart.css docs && webpack --config ./docs/webpack.config.js",
|
||||||
"watch": "BABEL_ENV=legacy-cjs babel src --watch --out-dir dist --ignore '**/__tests__/*'",
|
"build": "npm run clean && npm run build:dist",
|
||||||
"start": "npm run watch",
|
"watch": "BABEL_ENV=legacy-cjs babel src --watch --out-dir dist --ignore '**/__tests__/*'",
|
||||||
"react:clean": "rimraf node_modules/{react,react-dom,react-addons-test-utils}",
|
"start": "npm run watch",
|
||||||
"react:14": "npm run react:clean && npm i react@^0.14 react-dom@^0.14 react-addons-test-utils@^0.14 --save-dev",
|
"react:clean": "rimraf node_modules/{react,react-dom,react-addons-test-utils}",
|
||||||
"react:15": "npm run react:clean && npm i react@^15 react-dom@^15 react-addons-test-utils@^15 --save-dev",
|
"react:14": "npm run react:clean && npm i react@^0.14 react-dom@^0.14 react-addons-test-utils@^0.14 --save-dev",
|
||||||
"test": "npm run clean && jest",
|
"react:15": "npm run react:clean && npm i react@^15 react-dom@^15 react-addons-test-utils@^15 --save-dev",
|
||||||
"test:size": "size-limit",
|
"test": "npm run clean && jest",
|
||||||
"test:ssr": "node test/ssr.js",
|
"test:size": "size-limit",
|
||||||
"prepublishOnly": "npm run build",
|
"test:ssr": "node test/ssr.js",
|
||||||
"storybook": "start-storybook -p 6006",
|
"prepublishOnly": "npm run build",
|
||||||
"build-storybook": "build-storybook",
|
"storybook": "start-storybook -p 6006",
|
||||||
"prettier": "prettier --write \"{src,scripts,test,stories}/**/*.js\"",
|
"build-storybook": "build-storybook",
|
||||||
"prettier:check": "prettier --check \"{src,scripts,test,stories}/**/*.js\"",
|
"prettier": "prettier --write \"{src,scripts,test,stories}/**/*.js\"",
|
||||||
"prepare": "npm run build:dist"
|
"prettier:check": "prettier --check \"{src,scripts,test,stories}/**/*.js\"",
|
||||||
},
|
"prepare": "npm run build:dist"
|
||||||
"size-limit": [
|
},
|
||||||
{
|
"size-limit": [
|
||||||
"path": "dist-es/index.js",
|
{
|
||||||
"limit": "82 KB"
|
"path": "dist-es/index.js",
|
||||||
}
|
"limit": "82 KB"
|
||||||
]
|
}
|
||||||
}
|
]
|
||||||
|
}
|
||||||
|
|
|
@ -1,248 +1,287 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import frequently from '../utils/frequently'
|
import frequently from '../utils/frequently'
|
||||||
import { getData } from '../utils'
|
import { getData } from '../utils'
|
||||||
import NimbleEmoji from './emoji/nimble-emoji'
|
import NimbleEmoji from './emoji/nimble-emoji'
|
||||||
import NotFound from './not-found'
|
import NotFound from './not-found'
|
||||||
|
import 'intersection-observer'
|
||||||
export default class Category extends React.Component {
|
|
||||||
constructor(props) {
|
export default class Category extends React.Component {
|
||||||
super(props)
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
this.data = props.data
|
|
||||||
this.setContainerRef = this.setContainerRef.bind(this)
|
this.data = props.data
|
||||||
this.setLabelRef = this.setLabelRef.bind(this)
|
this.setContainerRef = this.setContainerRef.bind(this)
|
||||||
}
|
this.setLabelRef = this.setLabelRef.bind(this)
|
||||||
|
|
||||||
componentDidMount() {
|
this.imageObserver = new window.IntersectionObserver((entries, observer) => {
|
||||||
this.margin = 0
|
entries.forEach((entry) => {
|
||||||
this.minMargin = 0
|
if (entry.isIntersecting) {
|
||||||
|
const image = entry.target;
|
||||||
this.memoizeSize()
|
image.src = image.dataset.src;
|
||||||
}
|
image.classList.remove("lazy");
|
||||||
|
this.imageObserver.unobserve(image);
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
}
|
||||||
var {
|
});
|
||||||
name,
|
});
|
||||||
perLine,
|
}
|
||||||
native,
|
|
||||||
hasStickyPosition,
|
componentDidMount() {
|
||||||
emojis,
|
this.margin = 0
|
||||||
emojiProps,
|
this.minMargin = 0
|
||||||
} = this.props,
|
|
||||||
{ skin, size, set } = emojiProps,
|
this.memoizeSize()
|
||||||
{
|
|
||||||
perLine: nextPerLine,
|
this.lazyloadImages = []
|
||||||
native: nextNative,
|
this.lazyload()
|
||||||
hasStickyPosition: nextHasStickyPosition,
|
}
|
||||||
emojis: nextEmojis,
|
|
||||||
emojiProps: nextEmojiProps,
|
componentDidUpdate() {
|
||||||
} = nextProps,
|
this.lazyload()
|
||||||
{ skin: nextSkin, size: nextSize, set: nextSet } = nextEmojiProps,
|
}
|
||||||
shouldUpdate = false
|
|
||||||
|
componentWillUnmount() {
|
||||||
if (name == 'Recent' && perLine != nextPerLine) {
|
this.removeLazyloadObserver()
|
||||||
shouldUpdate = true
|
}
|
||||||
}
|
|
||||||
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
if (name == 'Search') {
|
var {
|
||||||
shouldUpdate = !(emojis == nextEmojis)
|
name,
|
||||||
}
|
perLine,
|
||||||
|
native,
|
||||||
if (
|
hasStickyPosition,
|
||||||
skin != nextSkin ||
|
emojis,
|
||||||
size != nextSize ||
|
emojiProps,
|
||||||
native != nextNative ||
|
} = this.props,
|
||||||
set != nextSet ||
|
{ skin, size, set } = emojiProps,
|
||||||
hasStickyPosition != nextHasStickyPosition
|
{
|
||||||
) {
|
perLine: nextPerLine,
|
||||||
shouldUpdate = true
|
native: nextNative,
|
||||||
}
|
hasStickyPosition: nextHasStickyPosition,
|
||||||
|
emojis: nextEmojis,
|
||||||
return shouldUpdate
|
emojiProps: nextEmojiProps,
|
||||||
}
|
} = nextProps,
|
||||||
|
{ skin: nextSkin, size: nextSize, set: nextSet } = nextEmojiProps,
|
||||||
memoizeSize() {
|
shouldUpdate = false
|
||||||
if (!this.container) {
|
|
||||||
// probably this is a test environment, e.g. jest
|
if (name == 'Recent' && perLine != nextPerLine) {
|
||||||
this.top = 0
|
shouldUpdate = true
|
||||||
this.maxMargin = 0
|
}
|
||||||
return
|
|
||||||
}
|
if (name == 'Search') {
|
||||||
var parent = this.container.parentElement
|
// shouldUpdate = !(emojis == nextEmojis)
|
||||||
var { top, height } = this.container.getBoundingClientRect()
|
shouldUpdate = true
|
||||||
var { top: parentTop } = parent.getBoundingClientRect()
|
}
|
||||||
var { height: labelHeight } = this.label.getBoundingClientRect()
|
|
||||||
|
if (
|
||||||
this.top = top - parentTop + parent.scrollTop
|
skin != nextSkin ||
|
||||||
|
size != nextSize ||
|
||||||
if (height == 0) {
|
native != nextNative ||
|
||||||
this.maxMargin = 0
|
set != nextSet ||
|
||||||
} else {
|
hasStickyPosition != nextHasStickyPosition
|
||||||
this.maxMargin = height - labelHeight
|
) {
|
||||||
}
|
shouldUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
handleScroll(scrollTop) {
|
return shouldUpdate
|
||||||
var margin = scrollTop - this.top
|
}
|
||||||
margin = margin < this.minMargin ? this.minMargin : margin
|
|
||||||
margin = margin > this.maxMargin ? this.maxMargin : margin
|
memoizeSize() {
|
||||||
|
if (!this.container) {
|
||||||
if (margin == this.margin) return
|
// probably this is a test environment, e.g. jest
|
||||||
|
this.top = 0
|
||||||
if (!this.props.hasStickyPosition) {
|
this.maxMargin = 0
|
||||||
this.label.style.top = `${margin}px`
|
return
|
||||||
}
|
}
|
||||||
|
var parent = this.container.parentElement
|
||||||
this.margin = margin
|
var { top, height } = this.container.getBoundingClientRect()
|
||||||
return true
|
var { top: parentTop } = parent.getBoundingClientRect()
|
||||||
}
|
var { height: labelHeight } = this.label.getBoundingClientRect()
|
||||||
|
|
||||||
getEmojis() {
|
this.top = top - parentTop + parent.scrollTop
|
||||||
var { name, emojis, recent, perLine } = this.props
|
|
||||||
|
if (height == 0) {
|
||||||
if (name == 'Recent') {
|
this.maxMargin = 0
|
||||||
let { custom } = this.props
|
} else {
|
||||||
let frequentlyUsed = recent || frequently.get(perLine)
|
this.maxMargin = height - labelHeight
|
||||||
|
}
|
||||||
if (frequentlyUsed.length) {
|
}
|
||||||
emojis = frequentlyUsed
|
|
||||||
.map((id) => {
|
lazyload() {
|
||||||
const emoji = custom.filter((e) => e.id === id)[0]
|
this.removeLazyloadObserver()
|
||||||
if (emoji) {
|
this.lazyloadImages = this.container.querySelectorAll(".lazy");
|
||||||
return emoji
|
|
||||||
}
|
this.lazyloadImages.forEach((image) => {
|
||||||
|
this.imageObserver.observe(image);
|
||||||
return id
|
});
|
||||||
})
|
}
|
||||||
.filter((id) => !!getData(id, null, null, this.data))
|
|
||||||
}
|
removeLazyloadObserver() {
|
||||||
|
this.lazyloadImages.forEach((image) => {
|
||||||
if (emojis.length === 0 && frequentlyUsed.length > 0) {
|
this.imageObserver.unobserve(image);
|
||||||
return null
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
handleScroll(scrollTop) {
|
||||||
if (emojis) {
|
var margin = scrollTop - this.top
|
||||||
emojis = emojis.slice(0)
|
margin = margin < this.minMargin ? this.minMargin : margin
|
||||||
}
|
margin = margin > this.maxMargin ? this.maxMargin : margin
|
||||||
|
|
||||||
return emojis
|
if (margin == this.margin) return
|
||||||
}
|
|
||||||
|
if (!this.props.hasStickyPosition) {
|
||||||
updateDisplay(display) {
|
this.label.style.top = `${margin}px`
|
||||||
var emojis = this.getEmojis()
|
}
|
||||||
|
|
||||||
if (!emojis || !this.container) {
|
this.margin = margin
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
this.container.style.display = display
|
getEmojis() {
|
||||||
}
|
var { name, emojis, recent, perLine } = this.props
|
||||||
|
|
||||||
setContainerRef(c) {
|
if (name == 'Recent') {
|
||||||
this.container = c
|
let { custom } = this.props
|
||||||
}
|
let frequentlyUsed = recent || frequently.get(perLine)
|
||||||
|
|
||||||
setLabelRef(c) {
|
if (frequentlyUsed.length) {
|
||||||
this.label = c
|
emojis = frequentlyUsed
|
||||||
}
|
.map((id) => {
|
||||||
|
const emoji = custom.filter((e) => e.id === id)[0]
|
||||||
render() {
|
if (emoji) {
|
||||||
var {
|
return emoji
|
||||||
id,
|
}
|
||||||
name,
|
|
||||||
hasStickyPosition,
|
return id
|
||||||
emojiProps,
|
})
|
||||||
i18n,
|
.filter((id) => !!getData(id, null, null, this.data))
|
||||||
notFound,
|
}
|
||||||
notFoundEmoji,
|
|
||||||
} = this.props,
|
if (emojis.length === 0 && frequentlyUsed.length > 0) {
|
||||||
emojis = this.getEmojis(),
|
return null
|
||||||
labelStyles = {},
|
}
|
||||||
labelSpanStyles = {},
|
}
|
||||||
containerStyles = {}
|
|
||||||
|
if (emojis) {
|
||||||
if (!emojis) {
|
emojis = emojis.slice(0)
|
||||||
containerStyles = {
|
}
|
||||||
display: 'none',
|
|
||||||
}
|
return emojis
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasStickyPosition) {
|
updateDisplay(display) {
|
||||||
labelStyles = {
|
var emojis = this.getEmojis()
|
||||||
height: 28,
|
|
||||||
}
|
if (!emojis || !this.container) {
|
||||||
|
return
|
||||||
labelSpanStyles = {
|
}
|
||||||
position: 'absolute',
|
|
||||||
}
|
this.container.style.display = display
|
||||||
}
|
}
|
||||||
|
|
||||||
const label = i18n.categories[id] || name
|
setContainerRef(c) {
|
||||||
|
this.container = c
|
||||||
return (
|
}
|
||||||
<section
|
|
||||||
ref={this.setContainerRef}
|
setLabelRef(c) {
|
||||||
className="emoji-mart-category"
|
this.label = c
|
||||||
aria-label={label}
|
}
|
||||||
style={containerStyles}
|
|
||||||
>
|
render() {
|
||||||
<div
|
var {
|
||||||
style={labelStyles}
|
id,
|
||||||
data-name={name}
|
name,
|
||||||
className="emoji-mart-category-label"
|
hasStickyPosition,
|
||||||
>
|
emojiProps,
|
||||||
<span
|
i18n,
|
||||||
style={labelSpanStyles}
|
notFound,
|
||||||
ref={this.setLabelRef}
|
notFoundEmoji,
|
||||||
aria-hidden={true /* already labeled by the section aria-label */}
|
} = this.props,
|
||||||
>
|
emojis = this.getEmojis(),
|
||||||
{label}
|
labelStyles = {},
|
||||||
</span>
|
labelSpanStyles = {},
|
||||||
</div>
|
containerStyles = {}
|
||||||
|
|
||||||
<ul className="emoji-mart-category-list">
|
if (!emojis) {
|
||||||
{emojis &&
|
containerStyles = {
|
||||||
emojis.map((emoji) => (
|
display: 'none',
|
||||||
<li
|
}
|
||||||
key={
|
}
|
||||||
(emoji.short_names && emoji.short_names.join('_')) || emoji
|
|
||||||
}
|
if (!hasStickyPosition) {
|
||||||
>
|
labelStyles = {
|
||||||
{NimbleEmoji({ emoji: emoji, data: this.data, ...emojiProps })}
|
height: 28,
|
||||||
</li>
|
}
|
||||||
))}
|
|
||||||
</ul>
|
labelSpanStyles = {
|
||||||
|
position: 'absolute',
|
||||||
{emojis && !emojis.length && (
|
}
|
||||||
<NotFound
|
}
|
||||||
i18n={i18n}
|
|
||||||
notFound={notFound}
|
const label = i18n.categories[id] || name
|
||||||
notFoundEmoji={notFoundEmoji}
|
|
||||||
data={this.data}
|
return (
|
||||||
emojiProps={emojiProps}
|
<section
|
||||||
/>
|
ref={this.setContainerRef}
|
||||||
)}
|
className="emoji-mart-category"
|
||||||
</section>
|
aria-label={label}
|
||||||
)
|
style={containerStyles}
|
||||||
}
|
>
|
||||||
}
|
<div
|
||||||
|
style={labelStyles}
|
||||||
Category.propTypes /* remove-proptypes */ = {
|
data-name={name}
|
||||||
emojis: PropTypes.array,
|
className="emoji-mart-category-label"
|
||||||
hasStickyPosition: PropTypes.bool,
|
>
|
||||||
name: PropTypes.string.isRequired,
|
<span
|
||||||
native: PropTypes.bool.isRequired,
|
style={labelSpanStyles}
|
||||||
perLine: PropTypes.number.isRequired,
|
ref={this.setLabelRef}
|
||||||
emojiProps: PropTypes.object.isRequired,
|
aria-hidden={true /* already labeled by the section aria-label */}
|
||||||
recent: PropTypes.arrayOf(PropTypes.string),
|
>
|
||||||
notFound: PropTypes.func,
|
{label}
|
||||||
notFoundEmoji: PropTypes.string.isRequired,
|
</span>
|
||||||
}
|
</div>
|
||||||
|
|
||||||
Category.defaultProps = {
|
<ul className="emoji-mart-category-list">
|
||||||
emojis: [],
|
{emojis &&
|
||||||
hasStickyPosition: true,
|
emojis.map((emoji) => (
|
||||||
}
|
<li
|
||||||
|
key={
|
||||||
|
(emoji.short_names && emoji.short_names.join('_')) || emoji
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{NimbleEmoji({ emoji: emoji, data: this.data, ...emojiProps, lazy: true })}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{emojis && !emojis.length && (
|
||||||
|
<NotFound
|
||||||
|
i18n={i18n}
|
||||||
|
notFound={notFound}
|
||||||
|
notFoundEmoji={notFoundEmoji}
|
||||||
|
data={this.data}
|
||||||
|
emojiProps={emojiProps}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
|
@ -1,222 +1,240 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import { getData, getSanitizedData, unifiedToNative } from '../../utils'
|
import { getData, getSanitizedData, unifiedToNative } from '../../utils'
|
||||||
import { uncompress } from '../../utils/data'
|
import { uncompress } from '../../utils/data'
|
||||||
import { EmojiPropTypes } from '../../utils/shared-props'
|
import { EmojiPropTypes } from '../../utils/shared-props'
|
||||||
import { EmojiDefaultProps } from '../../utils/shared-default-props'
|
import { EmojiDefaultProps } from '../../utils/shared-default-props'
|
||||||
|
|
||||||
const _getData = (props) => {
|
const _getData = (props) => {
|
||||||
var { emoji, skin, set, data } = props
|
var { emoji, skin, set, data } = props
|
||||||
return getData(emoji, skin, set, data)
|
return getData(emoji, skin, set, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
const _getPosition = (props) => {
|
const _getPosition = (props) => {
|
||||||
var { sheet_x, sheet_y } = _getData(props),
|
var { sheet_x, sheet_y } = _getData(props),
|
||||||
multiplyX = 100 / (props.sheetColumns - 1),
|
multiplyX = 100 / (props.sheetColumns - 1),
|
||||||
multiplyY = 100 / (props.sheetRows - 1)
|
multiplyY = 100 / (props.sheetRows - 1)
|
||||||
|
|
||||||
return `${multiplyX * sheet_x}% ${multiplyY * sheet_y}%`
|
return `${multiplyX * sheet_x}% ${multiplyY * sheet_y}%`
|
||||||
}
|
}
|
||||||
|
|
||||||
const _getSanitizedData = (props) => {
|
const _getSanitizedData = (props) => {
|
||||||
var { emoji, skin, set, data } = props
|
var { emoji, skin, set, data } = props
|
||||||
return getSanitizedData(emoji, skin, set, data)
|
return getSanitizedData(emoji, skin, set, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
const _handleClick = (e, props) => {
|
const _handleClick = (e, props) => {
|
||||||
if (!props.onClick) {
|
if (!props.onClick) {
|
||||||
return
|
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) {
|
if (!props.onOver) {
|
||||||
return
|
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) {
|
if (!props.onLeave) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var { onLeave } = props,
|
var { onLeave } = props,
|
||||||
emoji = _getSanitizedData(props)
|
emoji = _getSanitizedData(props)
|
||||||
|
|
||||||
onLeave(emoji, e)
|
onLeave(emoji, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
const _isNumeric = (value) => {
|
const _isNumeric = (value) => {
|
||||||
return !isNaN(value - parseFloat(value))
|
return !isNaN(value - parseFloat(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
const _convertStyleToCSS = (style) => {
|
const _convertStyleToCSS = (style) => {
|
||||||
let div = document.createElement('div')
|
let div = document.createElement('div')
|
||||||
|
|
||||||
for (let key in style) {
|
for (let key in style) {
|
||||||
let value = style[key]
|
let value = style[key]
|
||||||
|
|
||||||
if (_isNumeric(value)) {
|
if (_isNumeric(value)) {
|
||||||
value += 'px'
|
value += 'px'
|
||||||
}
|
}
|
||||||
|
|
||||||
div.style[key] = value
|
div.style[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
return div.getAttribute('style')
|
return div.getAttribute('style')
|
||||||
}
|
}
|
||||||
|
|
||||||
const NimbleEmoji = (props) => {
|
const NimbleEmoji = (props) => {
|
||||||
if (props.data.compressed) {
|
if (props.data.compressed) {
|
||||||
uncompress(props.data)
|
uncompress(props.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let k in NimbleEmoji.defaultProps) {
|
for (let k in NimbleEmoji.defaultProps) {
|
||||||
if (props[k] == undefined && NimbleEmoji.defaultProps[k] != undefined) {
|
if (props[k] == undefined && NimbleEmoji.defaultProps[k] != undefined) {
|
||||||
props[k] = NimbleEmoji.defaultProps[k]
|
props[k] = NimbleEmoji.defaultProps[k]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = _getData(props)
|
let data = _getData(props)
|
||||||
if (!data) {
|
if (!data) {
|
||||||
if (props.fallback) {
|
if (props.fallback) {
|
||||||
return props.fallback(null, props)
|
return props.fallback(null, props)
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let { unified, custom, short_names, imageUrl } = data,
|
let { unified, custom, short_names, imageUrl } = data,
|
||||||
style = {},
|
style = {},
|
||||||
children = props.children,
|
children = props.children,
|
||||||
className = 'emoji-mart-emoji',
|
className = 'emoji-mart-emoji',
|
||||||
nativeEmoji = unified && unifiedToNative(unified),
|
nativeEmoji = unified && unifiedToNative(unified),
|
||||||
// combine the emoji itself and all shortcodes into an accessible label
|
// combine the emoji itself and all shortcodes into an accessible label
|
||||||
label = [nativeEmoji]
|
label = [nativeEmoji]
|
||||||
.concat(short_names)
|
.concat(short_names)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(', '),
|
.join(', '),
|
||||||
title = null
|
title = null
|
||||||
|
|
||||||
if (!unified && !custom) {
|
if (!unified && !custom) {
|
||||||
if (props.fallback) {
|
if (props.fallback) {
|
||||||
return props.fallback(data, props)
|
return props.fallback(data, props)
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.tooltip) {
|
if (props.tooltip) {
|
||||||
title = short_names[0]
|
title = short_names[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.native && unified) {
|
if (props.native && unified) {
|
||||||
className += ' emoji-mart-emoji-native'
|
className += ' emoji-mart-emoji-native'
|
||||||
style = { fontSize: props.size }
|
style = { fontSize: props.size }
|
||||||
children = nativeEmoji
|
children = nativeEmoji
|
||||||
|
|
||||||
if (props.forceSize) {
|
if (props.forceSize) {
|
||||||
style.display = 'inline-block'
|
style.display = 'inline-block'
|
||||||
style.width = props.size
|
style.width = props.size
|
||||||
style.height = props.size
|
style.height = props.size
|
||||||
style.wordBreak = 'keep-all'
|
style.wordBreak = 'keep-all'
|
||||||
}
|
}
|
||||||
} else if (custom) {
|
} else if (custom) {
|
||||||
className += ' emoji-mart-emoji-custom'
|
className += ' emoji-mart-emoji-custom'
|
||||||
style = {
|
style = {
|
||||||
width: props.size,
|
width: props.size,
|
||||||
height: props.size,
|
height: props.size,
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
}
|
}
|
||||||
if (data.spriteUrl) {
|
if (data.spriteUrl) {
|
||||||
style = {
|
style = {
|
||||||
...style,
|
...style,
|
||||||
backgroundImage: `url(${data.spriteUrl})`,
|
backgroundImage: `url(${data.spriteUrl})`,
|
||||||
backgroundSize: `${100 * props.sheetColumns}% ${100 *
|
backgroundSize: `${100 * props.sheetColumns}% ${100 *
|
||||||
props.sheetRows}%`,
|
props.sheetRows}%`,
|
||||||
backgroundPosition: _getPosition(props),
|
backgroundPosition: _getPosition(props),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
style = {
|
style = {
|
||||||
...style,
|
...style,
|
||||||
backgroundImage: `url(${imageUrl})`,
|
backgroundImage: `url(${imageUrl})`,
|
||||||
backgroundSize: 'contain',
|
backgroundSize: 'contain',
|
||||||
backgroundRepeat: 'no-repeat',
|
backgroundRepeat: 'no-repeat',
|
||||||
backgroundPosition: 'center',
|
backgroundPosition: 'center',
|
||||||
}
|
}
|
||||||
}
|
if(props.lazy){
|
||||||
} else {
|
delete style.backgroundImage
|
||||||
let setHasEmoji =
|
delete style.backgroundSize
|
||||||
data[`has_img_${props.set}`] == undefined || data[`has_img_${props.set}`]
|
delete style.backgroundRepeat
|
||||||
|
delete style.backgroundPosition
|
||||||
if (!setHasEmoji) {
|
style.objectFit = 'contain'
|
||||||
if (props.fallback) {
|
}
|
||||||
return props.fallback(data, props)
|
}
|
||||||
} else {
|
} else {
|
||||||
return null
|
let setHasEmoji =
|
||||||
}
|
data[`has_img_${props.set}`] == undefined || data[`has_img_${props.set}`]
|
||||||
} else {
|
|
||||||
style = {
|
if (!setHasEmoji) {
|
||||||
width: props.size,
|
if (props.fallback) {
|
||||||
height: props.size,
|
return props.fallback(data, props)
|
||||||
display: 'inline-block',
|
} else {
|
||||||
backgroundImage: `url(${props.backgroundImageFn(
|
return null
|
||||||
props.set,
|
}
|
||||||
props.sheetSize,
|
} else {
|
||||||
)})`,
|
style = {
|
||||||
backgroundSize: `${100 * props.sheetColumns}% ${100 *
|
width: props.size,
|
||||||
props.sheetRows}%`,
|
height: props.size,
|
||||||
backgroundPosition: _getPosition(props),
|
display: 'inline-block',
|
||||||
}
|
backgroundImage: `url(${props.backgroundImageFn(
|
||||||
}
|
props.set,
|
||||||
}
|
props.sheetSize,
|
||||||
|
)})`,
|
||||||
var Tag = {
|
backgroundSize: `${100 * props.sheetColumns}% ${100 *
|
||||||
name: 'span',
|
props.sheetRows}%`,
|
||||||
props: {},
|
backgroundPosition: _getPosition(props),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (props.onClick && props.useButton) {
|
}
|
||||||
Tag.name = 'button'
|
|
||||||
Tag.props = {
|
var Tag = {
|
||||||
type: 'button',
|
name: 'span',
|
||||||
}
|
props: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.html) {
|
if (props.onClick && props.useButton) {
|
||||||
style = _convertStyleToCSS(style)
|
Tag.name = 'button'
|
||||||
return `<${Tag.name} style='${style}' aria-label='${label}' ${
|
Tag.props = {
|
||||||
title ? `title='${title}'` : ''
|
type: 'button',
|
||||||
} class='${className}'>${children || ''}</${Tag.name}>`
|
}
|
||||||
} else {
|
}
|
||||||
return (
|
|
||||||
<Tag.name
|
if (props.html) {
|
||||||
onClick={(e) => _handleClick(e, props)}
|
style = _convertStyleToCSS(style)
|
||||||
onMouseEnter={(e) => _handleOver(e, props)}
|
return `<${Tag.name} style='${style}' aria-label='${label}' ${
|
||||||
onMouseLeave={(e) => _handleLeave(e, props)}
|
title ? `title='${title}'` : ''
|
||||||
aria-label={label}
|
} class='${className}'>${children || ''}</${Tag.name}>`
|
||||||
title={title}
|
} else {
|
||||||
className={className}
|
return (
|
||||||
{...Tag.props}
|
<Tag.name
|
||||||
>
|
onClick={(e) => _handleClick(e, props)}
|
||||||
<span style={style}>{children}</span>
|
onMouseEnter={(e) => _handleOver(e, props)}
|
||||||
</Tag.name>
|
onMouseLeave={(e) => _handleLeave(e, props)}
|
||||||
)
|
aria-label={label}
|
||||||
}
|
title={title}
|
||||||
}
|
className={className}
|
||||||
|
{...Tag.props}
|
||||||
NimbleEmoji.propTypes /* remove-proptypes */ = {
|
>
|
||||||
...EmojiPropTypes,
|
{
|
||||||
data: PropTypes.object.isRequired,
|
custom && !data.spriteUrl && props.lazy
|
||||||
}
|
?
|
||||||
NimbleEmoji.defaultProps = EmojiDefaultProps
|
<img
|
||||||
|
style={style}
|
||||||
export default NimbleEmoji
|
className="lazy"
|
||||||
|
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP89B8AAukB8/71MdcAAAAASUVORK5CYII="
|
||||||
|
data-src={imageUrl}
|
||||||
|
/>
|
||||||
|
:
|
||||||
|
<span style={style}>{children}</span>
|
||||||
|
}
|
||||||
|
</Tag.name>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NimbleEmoji.propTypes /* remove-proptypes */ = {
|
||||||
|
...EmojiPropTypes,
|
||||||
|
data: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
NimbleEmoji.defaultProps = EmojiDefaultProps
|
||||||
|
|
||||||
|
export default NimbleEmoji
|
||||||
|
|
Loading…
Reference in New Issue