Compare commits
293 Commits
Author | SHA1 | Date |
---|---|---|
mashirozx | d496014be7 | |
mashirozx | dac9386e73 | |
mashirozx | 818aba94a0 | |
mashirozx | 7edf171664 | |
Ross Gardiner | fe28ab637b | |
Etienne Lemay | 5912b6b902 | |
Etienne Lemay | 37c3c6267c | |
Erin Hinson | ca6a7fd74b | |
Matt Krick | 612dae7b08 | |
Sagar Jain | 3a97898c5b | |
Sagar Jain | 4f8ef7255a | |
Etienne Lemay | ca3d4e5f0e | |
Etienne Lemay | cd29d5b9f6 | |
Etienne Lemay | 3b6fd1516f | |
Etienne Lemay | 2dacd30dc8 | |
Etienne Lemay | b548c38624 | |
Etienne Lemay | d1138c00e8 | |
Etienne Lemay | c41fc5ec7a | |
Etienne Lemay | 0e299ff4dd | |
Etienne Lemay | 17cf50f7ba | |
Etienne Lemay | 22ffd5b85e | |
Etienne Lemay | b8fad36c6d | |
Etienne Lemay | 56ae7b49c5 | |
SaraRandolph | 6ca158bb36 | |
SaraRandolph | cdb6c26a08 | |
Etienne Lemay | 769b55c875 | |
Etienne Lemay | dc4ca683d2 | |
Etienne Lemay | 16ca493f3c | |
Etienne Lemay | cf4a1043f7 | |
Etienne Lemay | 5c083a8026 | |
Etienne Lemay | f8ce5a6814 | |
Etienne Lemay | fcae7a913b | |
Thomas Piard | 57cabf6f75 | |
Thomas Piard | 9bab24f3c6 | |
Thomas Piard | 4404e71264 | |
Thomas Piard | 3941549f6a | |
Thomas Piard | a253148b86 | |
Thomas Piard | cdb74f28c7 | |
Etienne Lemay | 113b07abcf | |
Etienne Lemay | bfada8f5c1 | |
Etienne Lemay | 39c2c9d6ee | |
rugk | e57118c6f3 | |
Nolan Lawson | 835c2e9c36 | |
Nolan Lawson | c8305f6013 | |
Nolan Lawson | 97f6ffde2d | |
Nolan Lawson | 0bd369144b | |
Nolan Lawson | 99eae3605d | |
Nolan Lawson | 6bb1932db8 | |
Etienne Lemay | 85577c0b58 | |
Etienne Lemay | 7b2f760df2 | |
Etienne Lemay | 3440a74328 | |
Etienne Lemay | f1a988ca4b | |
Etienne Lemay | 2860851c0b | |
Etienne Lemay | e66be9dc4e | |
Etienne Lemay | e39c1e53d8 | |
Etienne Lemay | c778bc6084 | |
Etienne Lemay | ff9d416300 | |
Nolan Lawson | 61c0bd4e4e | |
Nolan Lawson | 7a025243b4 | |
Eugen Rochko | 1a9d5f97b6 | |
Nolan Lawson | 8cff39f6fd | |
Mohan Raj | 848fc76396 | |
dependabot[bot] | 830c69a4e1 | |
dependabot[bot] | 1b69530f53 | |
dependabot[bot] | 6c60ac1242 | |
dependabot[bot] | 364ae72ba3 | |
Carl Tessier | f3387cdce2 | |
Peder Johnsen | edcd64b101 | |
Hiro-Aki Hotta | 208099c2dc | |
Ryan McCue | f10510b262 | |
Alex Brioux | 76ac008169 | |
Nolan Lawson | 3576091fc0 | |
Xavier Shay | 956aaa91f3 | |
Nolan Lawson | a0ce9d8122 | |
Nolan Lawson | cdd3229de6 | |
rugk | f8322a8c5d | |
Etienne Lemay | ae24948861 | |
Etienne Lemay | 75dfed01f5 | |
The-Code-Monkey | af37a7a20f | |
The-Code-Monkey | 14c5d4f2b4 | |
The-Code-Monkey | 0cfb0787ab | |
Etienne Lemay | f654ef4050 | |
Etienne Lemay | 1d09d3758e | |
Etienne Lemay | 8d4d928973 | |
Etienne Lemay | 5d1b84cf1d | |
Etienne Lemay | 9b3a4487a1 | |
Etienne Lemay | 7f05e22d12 | |
Etienne Lemay | 32282a6dc7 | |
Etienne Lemay | 4fda4dcc01 | |
Etienne Lemay | abc2cdaf02 | |
Etienne Lemay | 1bcc52e587 | |
Etienne Lemay | 5f065d4793 | |
Etienne Lemay | cbad12426c | |
Nolan Lawson | 7a94080f5f | |
Nolan Lawson | 7039517939 | |
Nolan Lawson | 7d8e2458d9 | |
Peder Johnsen | ab2f6004ac | |
Peder Johnsen | d140dd8f04 | |
Peder Johnsen | 5570a7ce1a | |
Peder Johnsen | 5c64cc6908 | |
Peder Johnsen | 90b36d829f | |
Peder Johnsen | 0ab34e20a3 | |
Peder Johnsen | a8c491273c | |
Nolan Lawson | d6598deb2e | |
Peder Johnsen | dce30b3f09 | |
Peder Johnsen | 37340679ec | |
Hinaloe | 39fc02bfe3 | |
Nolan Lawson | 3c0c0caffc | |
Nolan Lawson | d9eda6a7a5 | |
Nolan Lawson | 43ddfa78ad | |
Nolan Lawson | 5538272c94 | |
Peder Johnsen | ed241d1d42 | |
Peder Johnsen | 236cd3d612 | |
Peder Johnsen | aaa12fe918 | |
Peder Johnsen | 127dea28a5 | |
Peder Johnsen | 88310345d8 | |
Peder Johnsen | e00371c86e | |
Peder Johnsen | b76be74e96 | |
Peder Johnsen | ab2f17cfc1 | |
Peder Johnsen | 51a0879ec1 | |
Peder Johnsen | 9afc613fee | |
Peder Johnsen | f1901ed94c | |
Nolan Lawson | fa7141653d | |
Nolan Lawson | 6fb9c9afa7 | |
Nolan Lawson | 8bea0331ff | |
Nolan Lawson | 290f442daa | |
Nolan Lawson | e17b7b9fcd | |
Peder Johnsen | 51d59341c8 | |
Peder Johnsen | f760c55440 | |
Peder Johnsen | 22a5ca587f | |
hina | a1a12abcd5 | |
Nolan Lawson | d53510bd4f | |
Nolan Lawson | 8cf6515298 | |
Etienne Lemay | d739f27714 | |
Etienne Lemay | c80b9bfa02 | |
Etienne Lemay | dce1244b8a | |
Etienne Lemay | e3bb26b894 | |
Etienne Lemay | 20fc1366ef | |
Etienne Lemay | e03fc9ac2e | |
Nolan Lawson | 3b4d5ee25a | |
Nolan Lawson | ca66d6c9af | |
Nolan Lawson | 9b6676a25d | |
Nolan Lawson | a8ea3506a5 | |
Nolan Lawson | 5dac39e179 | |
Nolan Lawson | c6c302ecae | |
Nolan Lawson | 7c6a28fb76 | |
Nolan Lawson | 165d1a9736 | |
Nolan Lawson | 8fd11b0e2a | |
Nolan Lawson | 302663f8bf | |
Nolan Lawson | 5f0c868fd9 | |
Nolan Lawson | d1978c096f | |
Nolan Lawson | f53d9b8c71 | |
Nolan Lawson | 42447642c7 | |
Nolan Lawson | f98526a7ed | |
Nolan Lawson | e3c39bd2fa | |
Nolan Lawson | 19bac54d8a | |
Nolan Lawson | 585b4b374f | |
Nolan Lawson | 058cdec053 | |
Nolan Lawson | af29bd19b0 | |
Nolan Lawson | 94404ad339 | |
Nolan Lawson | 7e207ba851 | |
Nolan Lawson | 978e7b68a1 | |
Nolan Lawson | 5ef7a2a7da | |
Nolan Lawson | e3106ac637 | |
Nolan Lawson | 27d6a383bd | |
Nolan Lawson | e2694b544b | |
Nolan Lawson | 92c5399ab5 | |
Nolan Lawson | 1347c1765a | |
Nolan Lawson | 0f35206687 | |
Nolan Lawson | 740eccb6d0 | |
Nolan Lawson | c2c7092fc4 | |
Nolan Lawson | 445d2d4656 | |
Nolan Lawson | 646ad7f7c7 | |
Nolan Lawson | 558de6a994 | |
Nolan Lawson | 2fc7816116 | |
Nolan Lawson | 27f1b8cd63 | |
Nolan Lawson | f3cff33eda | |
Nolan Lawson | 12c2abba9d | |
Nolan Lawson | 13e1dd2e82 | |
Nolan Lawson | bd172943d2 | |
Nolan Lawson | ef71101cd6 | |
Nolan Lawson | 8f6145e383 | |
Nolan Lawson | 59c4d87839 | |
Nolan Lawson | e77c63bc9a | |
Nolan Lawson | b0fee348c0 | |
Nolan Lawson | 5052ecd399 | |
Nolan Lawson | d20f60cba1 | |
Nolan Lawson | c13b730dbe | |
Nolan Lawson | b1be155787 | |
Nolan Lawson | 8c80e7d4e5 | |
Nolan Lawson | 28c05b2861 | |
Nolan Lawson | a871cacbf2 | |
Kaylee Mann | 22aa42acf4 | |
Kaylee Mann | caba7d0b34 | |
Nolan Lawson | ce777216cd | |
Nolan Lawson | e8b4cfd4a8 | |
Nolan Lawson | c27e62456f | |
Nolan Lawson | f60220870e | |
Nolan Lawson | 420e2c7e86 | |
Nolan Lawson | bae7afb282 | |
Nolan Lawson | 10bfbd0594 | |
Dimitri Wijesinghe | 17db4cc913 | |
Ryann | 9b9410e70c | |
Nolan Lawson | e975284b29 | |
Etienne Lemay | 7c2e2a840b | |
Etienne Lemay | 993074fd03 | |
kennybll | 2ff225b131 | |
kennybll | 94baec171d | |
Peder Johnsen | 682d8d8be4 | |
Peder Johnsen | f0b5e1eeae | |
Peder Johnsen | bbbdcc512d | |
Peder Johnsen | fe17925fac | |
Peder Johnsen | fd4056025a | |
Peder Johnsen | f90defbed7 | |
Peder Johnsen | 1c7a5d6ec6 | |
Peder Johnsen | 54f6893c98 | |
Etienne Lemay | 3482a56d60 | |
Etienne Lemay | aaa91c949e | |
Etienne Lemay | 7186a10d4f | |
Etienne Lemay | 08eb6db270 | |
Etienne Lemay | 1c05b38a9e | |
Etienne Lemay | 21b3e92bb2 | |
Etienne Lemay | 9196a87769 | |
Etienne Lemay | a09730d6a8 | |
Etienne Lemay | e4d4226045 | |
Etienne Lemay | d54b7f2171 | |
Ross Khanas | c0a418fa57 | |
Ross Khanas | be27ba5779 | |
Ross Khanas | 9cad93d015 | |
Adam Bowles | 745cd2a9b5 | |
hozefaj | 937e33534d | |
Etienne Lemay | 016ef7ccce | |
Etienne Lemay | 1c14c868b1 | |
Etienne Lemay | 7c090c99d1 | |
Justine De Caires | c6b36947d3 | |
Etienne Lemay | 8ee9858aa0 | |
Etienne Lemay | 5e15356379 | |
Etienne Lemay | f5a4a488f8 | |
Etienne Lemay | 94e7b2d878 | |
Etienne Lemay | 2c060c56bc | |
Etienne Lemay | 83bd22dffd | |
Etienne Lemay | 757f1b023c | |
Etienne Lemay | 9b523425c6 | |
Etienne Lemay | 175d08a612 | |
Etienne Lemay | 0c508deee8 | |
Etienne Lemay | 7c55c05935 | |
Trond Kjetil Bremnes | 57a548b199 | |
Justine De Caires | 385cb8f8c2 | |
Rena Ryumae | f1d5bc0095 | |
Etienne Lemay | 1588712ca0 | |
Etienne Lemay | 34ba02fc4b | |
Etienne Lemay | c236437f91 | |
Etienne Lemay | 58ceb30d3d | |
Etienne Lemay | a0075d7054 | |
Etienne Lemay | 60d3b9767b | |
Etienne Lemay | 7915d5472f | |
Etienne Lemay | 0021d6ff38 | |
Etienne Lemay | 2cea3df86a | |
Rena Ryumae | 31cc0ab215 | |
Etienne Lemay | 767b2fdcc6 | |
Etienne Lemay | 4bb41b9796 | |
Etienne Lemay | 8ddd8725e8 | |
Etienne Lemay | 3dc3e2fd95 | |
Etienne Lemay | a7e37edcde | |
Etienne Lemay | 98af838d60 | |
Etienne Lemay | 6fac845580 | |
Rena Ryumae | 8e6d363d8b | |
Rena Ryumae | 5e03ee3e16 | |
Luis Belloch | 086ed6991e | |
Etienne Lemay | b1c499fc8d | |
Etienne Lemay | 9cda3c974c | |
Etienne Lemay | f9d47e9b13 | |
Etienne Lemay | f2b5035f12 | |
Etienne Lemay | 2428f3c1ba | |
Diogo Franco | c2f11adec3 | |
Christian Savard | 8df31b1c42 | |
Christian Savard | 0fff524ed7 | |
Etienne Lemay | 4715fe8f48 | |
Etienne Lemay | aa42453a0e | |
Etienne Lemay | 59601a08cf | |
Etienne Lemay | c6b86b25b9 | |
Etienne Lemay | 1edf3eaa96 | |
Etienne Lemay | 57662665d3 | |
Etienne Lemay | 22b37b6e36 | |
Etienne Lemay | 2e97b1faa6 | |
Etienne Lemay | 2f5fe6164e | |
Etienne Lemay | 0f37b428f6 | |
Etienne Lemay | 253ef4de89 | |
Etienne Lemay | 446fdf9544 | |
Etienne Lemay | a8b81f1858 | |
Etienne Lemay | d17594315c | |
Etienne Lemay | 8660a146e2 | |
Dave Cilley | 892096ea27 |
50
.babelrc
50
.babelrc
|
@ -1,50 +0,0 @@
|
|||
{
|
||||
"presets": ["react"],
|
||||
"plugins": [
|
||||
"check-es2015-constants",
|
||||
"transform-es2015-arrow-functions",
|
||||
"transform-es2015-block-scoped-functions",
|
||||
"transform-es2015-block-scoping",
|
||||
"transform-es2015-classes",
|
||||
"transform-es2015-computed-properties",
|
||||
"transform-es2015-destructuring",
|
||||
"transform-es2015-duplicate-keys",
|
||||
"transform-es2015-for-of",
|
||||
"transform-es2015-function-name",
|
||||
"transform-es2015-literals",
|
||||
"transform-es2015-object-super",
|
||||
"transform-es2015-parameters",
|
||||
"transform-es2015-shorthand-properties",
|
||||
"transform-es2015-spread",
|
||||
"transform-es2015-sticky-regex",
|
||||
"transform-es2015-template-literals",
|
||||
"transform-es2015-unicode-regex",
|
||||
"transform-regenerator",
|
||||
|
||||
"transform-object-rest-spread",
|
||||
"transform-runtime",
|
||||
"transform-react-remove-prop-types",
|
||||
[
|
||||
"transform-define", "scripts/define.js"
|
||||
],
|
||||
[
|
||||
"module-resolver",
|
||||
{
|
||||
"alias": {
|
||||
"babel-runtime/core-js/object/get-prototype-of": "./src/polyfills/objectGetPrototypeOf",
|
||||
"babel-runtime/helpers/extends": "./src/polyfills/extends",
|
||||
"babel-runtime/helpers/inherits": "./src/polyfills/inherits",
|
||||
"babel-runtime/helpers/createClass": "./src/polyfills/createClass",
|
||||
"babel-runtime/helpers/possibleConstructorReturn": "./src/polyfills/possibleConstructorReturn"
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"env": {
|
||||
"cjs": {
|
||||
"plugins": [
|
||||
"transform-es2015-modules-commonjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
[*]
|
||||
indent_size = 2
|
|
@ -1,6 +1,8 @@
|
|||
.DS_Store
|
||||
node_modules/
|
||||
dist/
|
||||
dist-es/
|
||||
dist-modern/
|
||||
stats.json
|
||||
report.html
|
||||
/src/data/data.js
|
||||
package-lock.json
|
||||
|
|
|
@ -4,7 +4,6 @@ scripts/
|
|||
|
||||
src/
|
||||
docs/
|
||||
spec/
|
||||
example/
|
||||
karma.conf.js
|
||||
yarn.lock
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
*.md
|
||||
*.css
|
|
@ -0,0 +1,12 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 10
|
||||
sudo: false
|
||||
script: yarn test
|
||||
before_script:
|
||||
- yarn prettier:check
|
||||
- yarn test:size
|
||||
- yarn test:ssr
|
||||
branches:
|
||||
only:
|
||||
- master
|
|
@ -0,0 +1,647 @@
|
|||
### Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
#### [v3.0.1](https://github.com/missive/emoji-mart/compare/v3.0.0...v3.0.1)
|
||||
|
||||
> February 24 2021
|
||||
|
||||
##### Fixes 🐛
|
||||
- Safely access search input #419
|
||||
- Custom category aria-label #480
|
||||
|
||||
##### Chores 🧹
|
||||
- React v17 support #475
|
||||
|
||||
#### [v3.0.0](https://github.com/missive/emoji-mart/compare/v2.11.2...v3.0.0)
|
||||
|
||||
> March 16 2020
|
||||
|
||||
##### New 🎉
|
||||
- [Emoji 12.1](https://emojipedia.org/emoji-12.1) 👩🦳👨🦰🦾 [`#411`](https://github.com/missive/emoji-mart/pull/411)
|
||||
- Option to disable use of `<button>` in Picker [`17cf50f`](https://github.com/missive/emoji-mart/commit/17cf50f7bafbbd2dbff9cabe0737e457a8aa1e72)
|
||||
|
||||
##### Breaking 🚨
|
||||
- As part of the Emoji 12.1 support and the upgrade of our data provider, `emojione` is no longer available [`emoji-data/142`](https://github.com/iamcal/emoji-data/pull/142)
|
||||
- `messenger` has been removed. Facebook has unified their emojis and is no longer mainting a different set for Messenger. Use `facebook` instead [`emoji-data/165#issuecomment-572795078`](https://github.com/iamcal/emoji-data/pull/165#issuecomment-572795078)
|
||||
- `darkMode` Picker prop superseded by `theme`. Defaults to `light` [`d1138c0`](https://github.com/missive/emoji-mart/commit/d1138c00e8d2e79c990ea75b89aaea4c7e819c7b)
|
||||
- No more auto-sorting of the “Frequently used” category. Use `enableFrequentEmojiSort` to enable [`#417`](https://github.com/missive/emoji-mart/pull/417)
|
||||
|
||||
##### Fixes 🐛
|
||||
- Horizontal scoll overflow [`#410`](https://github.com/missive/emoji-mart/pull/410)
|
||||
|
||||
##### Chores 🧹
|
||||
- Remove core-js dependency [`#394`](https://github.com/missive/emoji-mart/pull/394)
|
||||
- Upgrade to Babel V7 [`#397`](https://github.com/missive/emoji-mart/pull/397)
|
||||
- Remove _JSON hack [`#401`](https://github.com/missive/emoji-mart/pull/401)
|
||||
- Remove rAF polyfill [`#402`](https://github.com/missive/emoji-mart/pull/402)
|
||||
|
||||
#### [v2.11.2](https://github.com/missive/emoji-mart/compare/v2.11.1...v2.11.2)
|
||||
|
||||
> 23 December 2019
|
||||
|
||||
- chore(deps): bump lodash from 4.17.11 to 4.17.15 [`#390`](https://github.com/missive/emoji-mart/pull/390)
|
||||
- chore(deps): bump handlebars from 4.1.0 to 4.5.3 [`#389`](https://github.com/missive/emoji-mart/pull/389)
|
||||
- chore(deps): bump lodash-es from 4.17.11 to 4.17.15 [`#388`](https://github.com/missive/emoji-mart/pull/388)
|
||||
- chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 [`#387`](https://github.com/missive/emoji-mart/pull/387)
|
||||
- fix: gracefully ignore bad JSON in localstorage [`#385`](https://github.com/missive/emoji-mart/pull/385)
|
||||
- docs: Move `With custom data` to correct position [`#377`](https://github.com/missive/emoji-mart/pull/377)
|
||||
- fix: Use getDerivedStateFromProps instead of componentWillReceiveProps [`#372`](https://github.com/missive/emoji-mart/pull/372)
|
||||
- fix: Ensure emoji backgrounds do not tile [`#362`](https://github.com/missive/emoji-mart/pull/362)
|
||||
- Fix: Allowing emoji selection on enter [`#386`](https://github.com/missive/emoji-mart/pull/386)
|
||||
- fix: ensure unique keys for React list [`#352`](https://github.com/missive/emoji-mart/pull/352)
|
||||
- fix: Deterministic sorting of search results. [`#343`](https://github.com/missive/emoji-mart/pull/343)
|
||||
- docs: document how to remove the footer [`#330`](https://github.com/missive/emoji-mart/pull/330)
|
||||
- test: add basic skins test [`#315`](https://github.com/missive/emoji-mart/pull/315)
|
||||
- docs: Add tip for l10n to use CLDR [`#344`](https://github.com/missive/emoji-mart/pull/344)
|
||||
- Add support for more than one custom category [`#224`](https://github.com/missive/emoji-mart/issues/224)
|
||||
- Update gh-pages [`ff9d416`](https://github.com/missive/emoji-mart/commit/ff9d416300e30a6bb14262066cb1a63f9790c336)
|
||||
- Add theme selection to gh-pages [`e66be9d`](https://github.com/missive/emoji-mart/commit/e66be9dc4efb753b26ecaaf8583392e83c933b9c)
|
||||
- fix: dark mode CSS tweaks, add storybook/matchMedia/docs [`8cff39f`](https://github.com/missive/emoji-mart/commit/8cff39f6fd7add3a15ba7695bc117fe4794d3688)
|
||||
|
||||
#### [v2.11.1](https://github.com/missive/emoji-mart/compare/v2.11.0...v2.11.1)
|
||||
|
||||
> 9 May 2019
|
||||
|
||||
- Added `type={"button"}` to anchors.js [`#338`](https://github.com/missive/emoji-mart/pull/338)
|
||||
- Update gh-pages [`f654ef4`](https://github.com/missive/emoji-mart/commit/f654ef4050dd8fe4e06af96818bbddebcf8c4650)
|
||||
- Release v2.11.1 [`ae24948`](https://github.com/missive/emoji-mart/commit/ae24948861119f4cd366ad9432f74afff5cfddff)
|
||||
- attempt 2 to fix prettier error [`af37a7a`](https://github.com/missive/emoji-mart/commit/af37a7a20f66f172ef6f8e75dbcd59d36a91df05)
|
||||
|
||||
#### [v2.11.0](https://github.com/missive/emoji-mart/compare/v2.10.0...v2.11.0)
|
||||
|
||||
> 28 March 2019
|
||||
|
||||
- fix: use span for non-clickable emojis [`#329`](https://github.com/missive/emoji-mart/pull/329)
|
||||
- docs: fix travis CI badge [`#316`](https://github.com/missive/emoji-mart/pull/316)
|
||||
- fix: consistently return short_names from sanitize [`#317`](https://github.com/missive/emoji-mart/pull/317)
|
||||
- test: add test for short_names in custom emoji [`#323`](https://github.com/missive/emoji-mart/pull/323)
|
||||
- Get emoji data from native [`#250`](https://github.com/missive/emoji-mart/pull/250)
|
||||
- Fix typo [`#324`](https://github.com/missive/emoji-mart/pull/324)
|
||||
- Return skin emoji on search [`#321`](https://github.com/missive/emoji-mart/pull/321)
|
||||
- Add ignore for package-lock.json [`#322`](https://github.com/missive/emoji-mart/pull/322)
|
||||
- Add .editorconfig [`#320`](https://github.com/missive/emoji-mart/pull/320)
|
||||
- chore: add Travis CI tests [`#306`](https://github.com/missive/emoji-mart/pull/306)
|
||||
- keep short_names on sanitize [`#308`](https://github.com/missive/emoji-mart/pull/308)
|
||||
- docs: add example of how to use outside React [`#307`](https://github.com/missive/emoji-mart/pull/307)
|
||||
- docs: add example of how to use outside React [`#305`](https://github.com/missive/emoji-mart/issues/305)
|
||||
- Return emojis with skin tone from store on nimble search [`51a0879`](https://github.com/missive/emoji-mart/commit/51a0879ec17fa30bcdd0be3ea39c50af067e86ec)
|
||||
- Delete package-lock.json [`aaa12fe`](https://github.com/missive/emoji-mart/commit/aaa12fe9183f4b30cc483380f4e923ab2b9bd91a)
|
||||
- Upgrade some dev dependencies [`d739f27`](https://github.com/missive/emoji-mart/commit/d739f27714c4b1e28f3d92f654a5ba83933c2816)
|
||||
|
||||
#### [v2.10.0](https://github.com/missive/emoji-mart/compare/v2.9.2...v2.10.0)
|
||||
|
||||
> 15 March 2019
|
||||
|
||||
- chore: fix prettier linting [`#304`](https://github.com/missive/emoji-mart/pull/304)
|
||||
- test: replace karma with jest [`#302`](https://github.com/missive/emoji-mart/pull/302)
|
||||
- chore: `yarn clean` should remove dist-modern [`#301`](https://github.com/missive/emoji-mart/pull/301)
|
||||
- fix: improve requestIdleCallback usage [`#300`](https://github.com/missive/emoji-mart/pull/300)
|
||||
- fix: make each emoji category into a list [`#299`](https://github.com/missive/emoji-mart/pull/299)
|
||||
- chore: fix custom emoji URLs in storybook [`#298`](https://github.com/missive/emoji-mart/pull/298)
|
||||
- fix: improve a11y of skin tone picker [`#297`](https://github.com/missive/emoji-mart/pull/297)
|
||||
- fix: improve accessible page structure [`#296`](https://github.com/missive/emoji-mart/pull/296)
|
||||
- fix: use tabIndex, not tabindex [`#295`](https://github.com/missive/emoji-mart/pull/295)
|
||||
- fix: fix search input when value is prepopulated [`#290`](https://github.com/missive/emoji-mart/pull/290)
|
||||
- fix: fix emoji.id undefined error [`#289`](https://github.com/missive/emoji-mart/pull/289)
|
||||
- fix: remove unused notFoundString prop [`#288`](https://github.com/missive/emoji-mart/pull/288)
|
||||
- perf: throttle keyboard input to improve responsiveness [`#287`](https://github.com/missive/emoji-mart/pull/287)
|
||||
- fix: fix preact compatibility [`#285`](https://github.com/missive/emoji-mart/pull/285)
|
||||
- fix: improve a11y of emoji list [`#284`](https://github.com/missive/emoji-mart/pull/284)
|
||||
- fix: makes skin tone picker more accessible [`#283`](https://github.com/missive/emoji-mart/pull/283)
|
||||
- fix: make categories into accessible nav buttons [`#282`](https://github.com/missive/emoji-mart/pull/282)
|
||||
- fix: improve search/clear a11y [`#281`](https://github.com/missive/emoji-mart/pull/281)
|
||||
- fix: add prop-types to dependencies [`#280`](https://github.com/missive/emoji-mart/pull/280)
|
||||
- feat: add slim builds for modern browsers [`#260`](https://github.com/missive/emoji-mart/pull/260)
|
||||
- fix: fix babel-runtime not found [`#278`](https://github.com/missive/emoji-mart/pull/278)
|
||||
- Support case where showPreview is false but showSkinTones is true. Also add prepare script. [`#277`](https://github.com/missive/emoji-mart/pull/277)
|
||||
- docs: add more explicit dev docs [`#276`](https://github.com/missive/emoji-mart/pull/276)
|
||||
- fix: allow prop-types to be removed in production [`#258`](https://github.com/missive/emoji-mart/pull/258)
|
||||
- Fixed bug where selecting the first emoji search result with the ENTER KEY ignores skin tone selection [`#270`](https://github.com/missive/emoji-mart/pull/270)
|
||||
- fix: forces emoji's not to break line [`#261`](https://github.com/missive/emoji-mart/pull/261)
|
||||
- fix: fix native emoji on Linux [`#256`](https://github.com/missive/emoji-mart/pull/256)
|
||||
- fix: improve a11y of emoji list [`#218`](https://github.com/missive/emoji-mart/issues/218)
|
||||
- fix: makes skin tone picker more accessible [`#220`](https://github.com/missive/emoji-mart/issues/220)
|
||||
- fix: fix emoji.id undefined error [`#201`](https://github.com/missive/emoji-mart/issues/201)
|
||||
- fix: fix preact compatibility [`#254`](https://github.com/missive/emoji-mart/issues/254)
|
||||
- fix: make categories into accessible nav buttons [`#219`](https://github.com/missive/emoji-mart/issues/219)
|
||||
- fix: improve search/clear a11y [`#221`](https://github.com/missive/emoji-mart/issues/221)
|
||||
- feat: add slim builds for modern browsers [`#259`](https://github.com/missive/emoji-mart/issues/259)
|
||||
- fix: fix babel-runtime not found [`#228`](https://github.com/missive/emoji-mart/issues/228)
|
||||
- docs: add more explicit dev docs [`#227`](https://github.com/missive/emoji-mart/issues/227)
|
||||
- fix: allow prop-types to be removed in production [`#257`](https://github.com/missive/emoji-mart/issues/257)
|
||||
- fix: fix native emoji on Linux [`#255`](https://github.com/missive/emoji-mart/issues/255)
|
||||
- tweak babelrc to use runtime helpers for Object.assign [`c13b730`](https://github.com/missive/emoji-mart/commit/c13b730dbe75c34eb6ee4391715ca4041011dc93)
|
||||
- fix webkit CSS, fix clear button [`bd17294`](https://github.com/missive/emoji-mart/commit/bd172943d28982d751cfb6b9c7a7c731728bace1)
|
||||
- fix prettier [`ef71101`](https://github.com/missive/emoji-mart/commit/ef71101cd6bb0ebb7538615a6ccaa1edad62cb9c)
|
||||
|
||||
#### [v2.9.2](https://github.com/missive/emoji-mart/compare/v2.9.1...v2.9.2)
|
||||
|
||||
> 3 December 2018
|
||||
|
||||
- Adds Spritesheets for Custom Emojis [`#251`](https://github.com/missive/emoji-mart/pull/251)
|
||||
- Add sprite support [`94baec1`](https://github.com/missive/emoji-mart/commit/94baec171dc894e204c805b47d5da2c90a11d827)
|
||||
- Add `getEmojiDataFromNative` util function to get emoji data from native [`1c7a5d6`](https://github.com/missive/emoji-mart/commit/1c7a5d6ec6b0591408426b1413fc4f7092063c27)
|
||||
- Add `Get emoji data from Native` story [`f90defb`](https://github.com/missive/emoji-mart/commit/f90defbed702381a808cf282683acb10d43e4492)
|
||||
|
||||
#### [v2.9.1](https://github.com/missive/emoji-mart/compare/v2.9.0...v2.9.1)
|
||||
|
||||
> 14 November 2018
|
||||
|
||||
- Update gh-pages [`08eb6db`](https://github.com/missive/emoji-mart/commit/08eb6db2700e4a38cdbd3b2ae505d876f71c513e)
|
||||
- Release v2.9.1 [`aaa91c9`](https://github.com/missive/emoji-mart/commit/aaa91c949e2fe42475564dd36053921b84971edf)
|
||||
- Update gh-pages [`3482a56`](https://github.com/missive/emoji-mart/commit/3482a56d602590fab9a8773ce8cf2165465af6b8)
|
||||
|
||||
#### [v2.9.0](https://github.com/missive/emoji-mart/compare/v2.8.1...v2.9.0)
|
||||
|
||||
> 13 November 2018
|
||||
|
||||
- fix(a11y): ability to tab through different categories [`#226`](https://github.com/missive/emoji-mart/pull/226)
|
||||
- Add trailing colon to :octocat [`#231`](https://github.com/missive/emoji-mart/pull/231)
|
||||
- Import compoments directly to avoid components/picker/index.js and have smaller bundle [`#245`](https://github.com/missive/emoji-mart/pull/245)
|
||||
- Update yarn.lock [`9196a87`](https://github.com/missive/emoji-mart/commit/9196a877697698a46f3e331050c1fd96d939e8b1)
|
||||
- Get rid of components index [`21b3e92`](https://github.com/missive/emoji-mart/commit/21b3e92bb2122953d79cbabc21d3225ef2262ad4)
|
||||
- Update nimble-picker.js [`9cad93d`](https://github.com/missive/emoji-mart/commit/9cad93d015051979177d274c75ba9db47ba6e505)
|
||||
|
||||
#### [v2.8.1](https://github.com/missive/emoji-mart/compare/v2.8.0...v2.8.1)
|
||||
|
||||
> 16 August 2018
|
||||
|
||||
- Fixes display of non-52x52 sprite sheets in the preview bar [`#215`](https://github.com/missive/emoji-mart/pull/215)
|
||||
- Release v2.8.1 [`1c14c86`](https://github.com/missive/emoji-mart/commit/1c14c868b17b5000fae039fa7d60a42ca393227c)
|
||||
- Fixes display of non-52x52 sheets in the preview bar [`c6b3694`](https://github.com/missive/emoji-mart/commit/c6b36947d341b78555c327f94af718989a553927)
|
||||
|
||||
#### [v2.8.0](https://github.com/missive/emoji-mart/compare/v2.7.0...v2.8.0)
|
||||
|
||||
> 10 August 2018
|
||||
|
||||
- Custom emoji for skin tone selector [`#209`](https://github.com/missive/emoji-mart/pull/209)
|
||||
- Add sheetColumns and sheetRows props for non-square sprite sheets [`#212`](https://github.com/missive/emoji-mart/pull/212)
|
||||
- fix typo in README.md [`#213`](https://github.com/missive/emoji-mart/pull/213)
|
||||
- Update gh-pages [`5e15356`](https://github.com/missive/emoji-mart/commit/5e15356379e0942e47a35cd4f9780d5a6a8fbf23)
|
||||
- :lipstick: [`94e7b2d`](https://github.com/missive/emoji-mart/commit/94e7b2d8784258b0f530c8d46871946016a948f3)
|
||||
- Rename “skinIcon” => “skinEmoji” [`2c060c5`](https://github.com/missive/emoji-mart/commit/2c060c56bc83276fbe68e7e8fcda9ddc79851fea)
|
||||
|
||||
#### [v2.7.0](https://github.com/missive/emoji-mart/compare/v2.6.1...v2.7.0)
|
||||
|
||||
> 31 July 2018
|
||||
|
||||
- Customizable Category Icons [`#208`](https://github.com/missive/emoji-mart/pull/208)
|
||||
- Not Found Component for emoji search [`#206`](https://github.com/missive/emoji-mart/pull/206)
|
||||
- Adding search icon in search input field [`#205`](https://github.com/missive/emoji-mart/pull/205)
|
||||
- Added font stack to support native emojis in IE11/Edge [`#203`](https://github.com/missive/emoji-mart/pull/203)
|
||||
- Call fallback when emoji name isn’t recognized [Fix #199] [`#199`](https://github.com/missive/emoji-mart/issues/199)
|
||||
- Update gh-pages [`34ba02f`](https://github.com/missive/emoji-mart/commit/34ba02fc4b9e43734304a47c4868a2ff88cba1b2)
|
||||
- Add notFoundEmoji props to Picker [`4bb41b9`](https://github.com/missive/emoji-mart/commit/4bb41b9796fdd8a36c9ac51aefb8007eb5d1dbc4)
|
||||
- Don’t apply `emoji-mart-no-results` class when using custom notFound component [`3dc3e2f`](https://github.com/missive/emoji-mart/commit/3dc3e2fd954fbf7da4ea9825a103bc42661856e9)
|
||||
|
||||
#### [v2.6.1](https://github.com/missive/emoji-mart/compare/v2.6.0...v2.6.1)
|
||||
|
||||
> 11 May 2018
|
||||
|
||||
- Add missing onSelect to shared props [`#183`](https://github.com/missive/emoji-mart/pull/183)
|
||||
- Correct NimbleEmojiIndex reexport [`#187`](https://github.com/missive/emoji-mart/pull/187)
|
||||
- Fix crash in NimbleEmojiIndex when using custom emojis [`#185`](https://github.com/missive/emoji-mart/pull/185)
|
||||
- Update gh-pages [`9cda3c9`](https://github.com/missive/emoji-mart/commit/9cda3c974c25012578d4cc9f7ac03ca4eff5dd65)
|
||||
- Update README [`4715fe8`](https://github.com/missive/emoji-mart/commit/4715fe8f487a51796127626db23b3708a58b2539)
|
||||
- Release v2.6.1 [`b1c499f`](https://github.com/missive/emoji-mart/commit/b1c499fc8d7fbcd89f5bd23015df3d10dcc440e3)
|
||||
|
||||
#### [v2.6.0](https://github.com/missive/emoji-mart/compare/v2.5.1...v2.6.0)
|
||||
|
||||
> 30 April 2018
|
||||
|
||||
- Add parent components and data property for components that reference data.js Issue#86 [`#178`](https://github.com/missive/emoji-mart/pull/178)
|
||||
- Update gh-pages [`5766266`](https://github.com/missive/emoji-mart/commit/57662665d3f7e1fbc4cc961525316219f79ba6ff)
|
||||
- Add data property to any components that import data.js, and use that under the hood [`892096e`](https://github.com/missive/emoji-mart/commit/892096ea27e8a1f0ba7f87f4eba3df44f6e953f4)
|
||||
- Restructure data and components [`2e97b1f`](https://github.com/missive/emoji-mart/commit/2e97b1faa671c017fc74dd1df8da1468f84d5cb7)
|
||||
|
||||
#### [v2.5.1](https://github.com/missive/emoji-mart/compare/v2.5.0...v2.5.1)
|
||||
|
||||
> 27 March 2018
|
||||
|
||||
- Select first emoji in list with `enter` [`#175`](https://github.com/missive/emoji-mart/pull/175)
|
||||
- Clearing custom emojis from index and pool when necessary [`#172`](https://github.com/missive/emoji-mart/pull/172)
|
||||
- doc: add css in readme [`#174`](https://github.com/missive/emoji-mart/pull/174)
|
||||
- :lipstick: Add prettier.config.js [`c113dc5`](https://github.com/missive/emoji-mart/commit/c113dc5e3b934e0b867fdd568d7137d5f041cf46)
|
||||
- Update gh-pages [`6d557a5`](https://github.com/missive/emoji-mart/commit/6d557a5beed8f40000d89a5473c85b6e78125826)
|
||||
- Add keyboard selection with enter [`0765bf5`](https://github.com/missive/emoji-mart/commit/0765bf56f751457e36765bed0dbb44a3d4c721ed)
|
||||
|
||||
#### [v2.5.0](https://github.com/missive/emoji-mart/compare/v2.4.2...v2.5.0)
|
||||
|
||||
> 2 March 2018
|
||||
|
||||
- Custom Emojis as a changing prop [`#167`](https://github.com/missive/emoji-mart/pull/167)
|
||||
- fix Categories sort compareFunction return to -1 from 0 in Picker component [`#164`](https://github.com/missive/emoji-mart/pull/164)
|
||||
- Add `contentEditable` guide to README [Close #169] [`#169`](https://github.com/missive/emoji-mart/issues/169)
|
||||
- Add `onSkinChange` prop to Picker [Close #165] [`#165`](https://github.com/missive/emoji-mart/issues/165)
|
||||
- Set RECENT_CATEGORY, CUSTOM_CATEGORY and SEARCH_CATEGORY on Picker instances [Fix #166] [`#166`](https://github.com/missive/emoji-mart/issues/166)
|
||||
- Update gh-pages [`a7cd5e5`](https://github.com/missive/emoji-mart/commit/a7cd5e5d9637f04757af0fb910d80456b88ab578)
|
||||
- Add `showSkinTones` prop to Picker [Ref #165] [`c010035`](https://github.com/missive/emoji-mart/commit/c010035015524cf09d75e26b7cffd544c663d1fc)
|
||||
- Add `defaultSkin` prop to Picker and allow forcing skin tone with `skin` prop [Ref #165] [`af2fdc7`](https://github.com/missive/emoji-mart/commit/af2fdc71a1c725622e6cdc24bc4e9ef59f627407)
|
||||
|
||||
#### [v2.4.2](https://github.com/missive/emoji-mart/compare/v2.4.1...v2.4.2)
|
||||
|
||||
> 24 January 2018
|
||||
|
||||
- remove unused name [`#159`](https://github.com/missive/emoji-mart/pull/159)
|
||||
- Emoji fallback shouldn't apply styling #157 [`#158`](https://github.com/missive/emoji-mart/pull/158)
|
||||
- Release v2.4.2 [`b1ba2b7`](https://github.com/missive/emoji-mart/commit/b1ba2b777a03fa60c7f67e2d9ee57f3d93793ff9)
|
||||
- Don't render fallback inside an emoji `<span>` [`4008363`](https://github.com/missive/emoji-mart/commit/4008363e73b573234adbbe72e65d3773e9675ebc)
|
||||
- Remove Emoji fallback defaultProp [`238b2d2`](https://github.com/missive/emoji-mart/commit/238b2d2ff245eb62bf6300642ce6d9648d3cf627)
|
||||
|
||||
#### [v2.4.1](https://github.com/missive/emoji-mart/compare/v2.4.0...v2.4.1)
|
||||
|
||||
> 9 January 2018
|
||||
|
||||
- Fix search with custom data and filter [`#153`](https://github.com/missive/emoji-mart/pull/153)
|
||||
- Bug Fix: Ensure category ids are not dropped after emojisToShowFilter call [`#154`](https://github.com/missive/emoji-mart/pull/154)
|
||||
- add required props in <Emoji /> example [`#155`](https://github.com/missive/emoji-mart/pull/155)
|
||||
- Support providing a fallback to unsupported emojis [Fix #157] [`#157`](https://github.com/missive/emoji-mart/issues/157)
|
||||
- Update gh-pages [`e698358`](https://github.com/missive/emoji-mart/commit/e698358ea732cd2b792f33b273e33894791ead9c)
|
||||
- Add `html` props to Emoji component [Ref #79] [`6d095a0`](https://github.com/missive/emoji-mart/commit/6d095a072c4a7e80c4645ec2550297d5a15cd542)
|
||||
- :lipstick: [`68a4711`](https://github.com/missive/emoji-mart/commit/68a4711658fb97501cfa730703be8b0c4f432c7d)
|
||||
|
||||
#### [v2.4.0](https://github.com/missive/emoji-mart/compare/v2.3.0...v2.4.0)
|
||||
|
||||
> 15 December 2017
|
||||
|
||||
- Fix include / exclude [Fix #149] [`#149`](https://github.com/missive/emoji-mart/issues/149)
|
||||
- Update gh-pages [`373c009`](https://github.com/missive/emoji-mart/commit/373c0090659cbfee644ce9901596565d9552e265)
|
||||
- Revert "Merge pull request #99 from chadoh/countries-search" [`c70568c`](https://github.com/missive/emoji-mart/commit/c70568c3927ca53e95bce72121852bf38a3e070b)
|
||||
- Use 256-color indexed sheets by default [`8f63c38`](https://github.com/missive/emoji-mart/commit/8f63c3830814e257e2931fa4d8a6fc0e240753ff)
|
||||
|
||||
#### [v2.3.0](https://github.com/missive/emoji-mart/compare/v2.2.1...v2.3.0)
|
||||
|
||||
> 8 December 2017
|
||||
|
||||
- Update gh-pages [`e3ddfa5`](https://github.com/missive/emoji-mart/commit/e3ddfa584b27ab499b5598709cea6bf8d5f95ce5)
|
||||
- Fix getting category names from i18n [`fdf3c2d`](https://github.com/missive/emoji-mart/commit/fdf3c2d3a3575845f6aa1cf3be1037c402dae4ed)
|
||||
- Update category names [`66f9776`](https://github.com/missive/emoji-mart/commit/66f97765839686a95b82bbaff2b2dbb1daef0b5e)
|
||||
|
||||
#### [v2.2.1](https://github.com/missive/emoji-mart/compare/v2.2.0...v2.2.1)
|
||||
|
||||
> 10 November 2017
|
||||
|
||||
- Handle invalid emoji name in `Emoji` component [Fix #143] [`#143`](https://github.com/missive/emoji-mart/issues/143)
|
||||
- Add /docs [`772b9ab`](https://github.com/missive/emoji-mart/commit/772b9ab534bc7288ec3f3aebfe61f388a7fea2d7)
|
||||
- Fix CSS in /docs [`deeba72`](https://github.com/missive/emoji-mart/commit/deeba72831e18b5be78568903ba51ac8dd5918e6)
|
||||
- Reduce svgs/index.js size 10% [`cecb92b`](https://github.com/missive/emoji-mart/commit/cecb92bb9f0b755373887dd018e2d4e83e610b35)
|
||||
|
||||
#### [v2.2.0](https://github.com/missive/emoji-mart/compare/v2.1.2...v2.2.0)
|
||||
|
||||
> 9 November 2017
|
||||
|
||||
- Fix CSS for IE10 [Close #135] [`#135`](https://github.com/missive/emoji-mart/issues/135)
|
||||
- Provide more data to `emojisToShowFilter` in search [Fix #141] [`#141`](https://github.com/missive/emoji-mart/issues/141)
|
||||
- Retinafy images [`724bed6`](https://github.com/missive/emoji-mart/commit/724bed6e4e672ce8f50f7748c62f0cfbeae76eef)
|
||||
- Update README [`d4c86bc`](https://github.com/missive/emoji-mart/commit/d4c86bc6e17820bcefa1fee82e45c2f978136dd4)
|
||||
- Release v2.2.0 [`c4c2584`](https://github.com/missive/emoji-mart/commit/c4c258466a2ab85d4f735902406056fbc3efdb5c)
|
||||
|
||||
#### [v2.1.2](https://github.com/missive/emoji-mart/compare/v2.1.1...v2.1.2)
|
||||
|
||||
> 8 November 2017
|
||||
|
||||
- Feature filter invalid emojis [`#133`](https://github.com/missive/emoji-mart/pull/133)
|
||||
- Allow passing down a `recent` prop instead of localStorage [`#132`](https://github.com/missive/emoji-mart/pull/132)
|
||||
- Early return `measureScrollbar` when document isn’t defined [Fix #136] [`#136`](https://github.com/missive/emoji-mart/issues/136)
|
||||
- Fix #129 - Passing down a `recent` prop instead of localStorage [`#129`](https://github.com/missive/emoji-mart/issues/129)
|
||||
- Prettier :lipstick: [`3021758`](https://github.com/missive/emoji-mart/commit/30217581153077ac0c760d85bf93ff1ade78ff06)
|
||||
- Handle using custom storage instead of localStorage [`9cd6494`](https://github.com/missive/emoji-mart/commit/9cd6494c394add8283cabc03dd7823e3a39041e7)
|
||||
- :lipstick: [`b24b0cc`](https://github.com/missive/emoji-mart/commit/b24b0ccee563f91d292ddfd0016ef02916c2413e)
|
||||
|
||||
#### [v2.1.1](https://github.com/missive/emoji-mart/compare/v2.1.0...v2.1.1)
|
||||
|
||||
> 6 October 2017
|
||||
|
||||
- Intersect search results [Fix #131] [`#131`](https://github.com/missive/emoji-mart/issues/131)
|
||||
- Add test for thinking_face/woman-facepalming [`9b6ddf0`](https://github.com/missive/emoji-mart/commit/9b6ddf0c9cd78d7a235950d0f7074d82d1015450)
|
||||
- Release v2.1.1 [`5f2ffcc`](https://github.com/missive/emoji-mart/commit/5f2ffcc0be0ec46dc413d3e9739338174ca10b4a)
|
||||
- Fix spec syntax error [`b0e1d44`](https://github.com/missive/emoji-mart/commit/b0e1d44d6eb3ce3c2ca43dc483949c03b3c8f0e6)
|
||||
|
||||
#### [v2.1.0](https://github.com/missive/emoji-mart/compare/v2.0.1...v2.1.0)
|
||||
|
||||
> 6 October 2017
|
||||
|
||||
- Fix tests [`#130`](https://github.com/missive/emoji-mart/pull/130)
|
||||
- Build as ES module as well as CommonJS [`#120`](https://github.com/missive/emoji-mart/pull/120)
|
||||
- Remove function binds in render wherever possible, use PureComponent [`#125`](https://github.com/missive/emoji-mart/pull/125)
|
||||
- Fix headless search with custom emojis [Fix #118] [`#118`](https://github.com/missive/emoji-mart/issues/118)
|
||||
- Fix include sorting [Fix #116] [`#116`](https://github.com/missive/emoji-mart/issues/116)
|
||||
- Set `background-size: cover` for custom emojis [Fix #117] [`#117`](https://github.com/missive/emoji-mart/issues/117)
|
||||
- Fix TypeError on emoji click when picker has been unmounted [Fix #126] [`#126`](https://github.com/missive/emoji-mart/issues/126)
|
||||
- Revert Emoji back to a functional component [`22d1a03`](https://github.com/missive/emoji-mart/commit/22d1a0375dd9f3814db6623461785784858b9c86)
|
||||
- Signify custom emoji elements with class [Ref #117] [`1a2d400`](https://github.com/missive/emoji-mart/commit/1a2d400362f903a9eb8d2a960fc8ee370a766cda)
|
||||
- Exclude flag-un from data [`88cde66`](https://github.com/missive/emoji-mart/commit/88cde669e63dcdb6e7a86bcdd0a44f9f0836c4b4)
|
||||
|
||||
#### [v2.0.1](https://github.com/missive/emoji-mart/compare/v2.0.0...v2.0.1)
|
||||
|
||||
> 29 September 2017
|
||||
|
||||
- Remove function binds in render wherever possible, use PureComponent [`fdb88da`](https://github.com/missive/emoji-mart/commit/fdb88daa31f954b669f08462fa7cbce5c7d34c58)
|
||||
- Use SVGs inline [`81f39b1`](https://github.com/missive/emoji-mart/commit/81f39b138a65ee9e0aa6bdd6d6f8ce0e5f413265)
|
||||
- Move data in src [`e8dc29b`](https://github.com/missive/emoji-mart/commit/e8dc29bfaa868687a61e0d55d59667b9e63cd6e6)
|
||||
|
||||
### [v2.0.0](https://github.com/missive/emoji-mart/compare/v1.0.1...v2.0.0)
|
||||
|
||||
> 28 September 2017
|
||||
|
||||
- Add a storybook [`#124`](https://github.com/missive/emoji-mart/pull/124)
|
||||
- Upgrade to React 16 [`#123`](https://github.com/missive/emoji-mart/pull/123)
|
||||
- Package size reduced from 87.35 KB to 79.43 KB [`#113`](https://github.com/missive/emoji-mart/pull/113)
|
||||
- Use will-change:transform for smoother mobile scrolling [`#119`](https://github.com/missive/emoji-mart/pull/119)
|
||||
- Compress data [`#111`](https://github.com/missive/emoji-mart/pull/111)
|
||||
- Babel fixes [`#110`](https://github.com/missive/emoji-mart/pull/110)
|
||||
- Feature/replace webpack tasks on babel [`#108`](https://github.com/missive/emoji-mart/pull/108)
|
||||
- Reduce npm package size [`#104`](https://github.com/missive/emoji-mart/pull/104)
|
||||
- Add package size profiling tools [`#103`](https://github.com/missive/emoji-mart/pull/103)
|
||||
- Search country flags using country names [`#99`](https://github.com/missive/emoji-mart/pull/99)
|
||||
- Add showPreview props to Picker [Fix #42] [`#42`](https://github.com/missive/emoji-mart/issues/42)
|
||||
- Update emoji-datasource version in README [Fix #115] [`#115`](https://github.com/missive/emoji-mart/issues/115)
|
||||
- Add react-storybook [`a69125c`](https://github.com/missive/emoji-mart/commit/a69125ce4014d41c4a56bb34f2f057cf37637d72)
|
||||
- Size reduced from 87.35 KB to 79.43 KB [`4dc05ef`](https://github.com/missive/emoji-mart/commit/4dc05ef8da8764c58fcdbf5eed98f886cbf38062)
|
||||
- Get rid of /example [`d6e9a6a`](https://github.com/missive/emoji-mart/commit/d6e9a6afae6e45b735686ee290ed60d27c3c5cc8)
|
||||
|
||||
#### [v1.0.1](https://github.com/missive/emoji-mart/compare/v1.0.0...v1.0.1)
|
||||
|
||||
> 27 June 2017
|
||||
|
||||
- Improve support for Internet Explorer [`#92`](https://github.com/missive/emoji-mart/pull/92)
|
||||
- Fix shift when scrollbar is rendered [`#93`](https://github.com/missive/emoji-mart/pull/93)
|
||||
- Text representation of emoji is different from emoticon [`#88`](https://github.com/missive/emoji-mart/pull/88)
|
||||
- Do not store recently used if 'recent' category is excluded. [`#83`](https://github.com/missive/emoji-mart/pull/83)
|
||||
- Fix search with include/exclude [Fix #89] [`#89`](https://github.com/missive/emoji-mart/issues/89)
|
||||
- Make custom emojis work on example page [Ref #87] [`f3f60f5`](https://github.com/missive/emoji-mart/commit/f3f60f58b3b3ac95f27cf22ad6edb9586c5d923f)
|
||||
- Include scrollbar width in total picker width [`385408b`](https://github.com/missive/emoji-mart/commit/385408b51c14f9632bf765a4337cbc104e4958ea)
|
||||
- Use Babel’s transform-runtime plugin [`1b9b898`](https://github.com/missive/emoji-mart/commit/1b9b8983bbae771daf4f9d6b7453fd614eab665f)
|
||||
|
||||
### [v1.0.0](https://github.com/missive/emoji-mart/compare/v0.5.0...v1.0.0)
|
||||
|
||||
> 27 May 2017
|
||||
|
||||
- Add support for custom emojis [`#85`](https://github.com/missive/emoji-mart/pull/85)
|
||||
- Update to latest emoji-datasource [`#78`](https://github.com/missive/emoji-mart/pull/78)
|
||||
- Update react and remove react-addons-test-utils [`#80`](https://github.com/missive/emoji-mart/pull/80)
|
||||
- Allow preview emoji to be hidden. [`#84`](https://github.com/missive/emoji-mart/pull/84)
|
||||
- Update yarn.lock [`#82`](https://github.com/missive/emoji-mart/pull/82)
|
||||
- Installation instructions & stylesheet corrections [`#73`](https://github.com/missive/emoji-mart/pull/73)
|
||||
- update components from React.PropTypes to PropTypes package [`#74`](https://github.com/missive/emoji-mart/pull/74)
|
||||
- give max height to svg for IE support [`#77`](https://github.com/missive/emoji-mart/pull/77)
|
||||
- Add default frequently used defaults (closes #63) [`#64`](https://github.com/missive/emoji-mart/pull/64)
|
||||
- Do not include search input in the scroll container [Close #58] [`#58`](https://github.com/missive/emoji-mart/issues/58)
|
||||
- Add default frequently used defaults (closes #63) [`#63`](https://github.com/missive/emoji-mart/issues/63)
|
||||
- Functional Emoji component [`d2e37ca`](https://github.com/missive/emoji-mart/commit/d2e37cad6d1c7539d9ec4d9e4f2d40aec92e98f8)
|
||||
- Use svg-jsx for anchors [`1d57c21`](https://github.com/missive/emoji-mart/commit/1d57c216f5973d106e9990a35ceae6513ff562a5)
|
||||
- update components from React.PropTypes to PropTypes package to avoid [`ed5a6f1`](https://github.com/missive/emoji-mart/commit/ed5a6f1777d3dc80f6dda5251652f674d1aadb24)
|
||||
|
||||
#### [v0.5.0](https://github.com/missive/emoji-mart/compare/v0.4.4...v0.5.0)
|
||||
|
||||
> 18 April 2017
|
||||
|
||||
- add prop to autofocus search input [`#54`](https://github.com/missive/emoji-mart/pull/54)
|
||||
- Added `include` and `exclude` props to filter emoji categories [`#53`](https://github.com/missive/emoji-mart/pull/53)
|
||||
- Remove “No emoji found” hover [Close #59] [`#59`](https://github.com/missive/emoji-mart/issues/59)
|
||||
- Add “No emoji found” to i18n [Close #52] [`#52`](https://github.com/missive/emoji-mart/issues/52)
|
||||
- Support including/excluding the recent category [`c1bd9ea`](https://github.com/missive/emoji-mart/commit/c1bd9ea52ca96cd1009b50a62593b1f5b4b0015b)
|
||||
- Update “No Emoji Found” layout [`f07c0c0`](https://github.com/missive/emoji-mart/commit/f07c0c063860ecf54ad4878c5ba4420ef512063f)
|
||||
- :lipstick: [`4926b7b`](https://github.com/missive/emoji-mart/commit/4926b7bd43e86737edfcabb59407cbed437830d9)
|
||||
|
||||
#### [v0.4.4](https://github.com/missive/emoji-mart/compare/v0.4.3...v0.4.4)
|
||||
|
||||
> 17 March 2017
|
||||
|
||||
- Include unified in sanitized data [Close #51] [`#51`](https://github.com/missive/emoji-mart/issues/51)
|
||||
- Release v0.4.4 [`9a713ad`](https://github.com/missive/emoji-mart/commit/9a713ad88543f6f43b23037f617dec6b205384b4)
|
||||
|
||||
#### [v0.4.3](https://github.com/missive/emoji-mart/compare/v0.4.2...v0.4.3)
|
||||
|
||||
> 10 March 2017
|
||||
|
||||
- Data file size reduction: strip quotes around keys [`#49`](https://github.com/missive/emoji-mart/pull/49)
|
||||
- Delete empty arrays from data file [`2de8310`](https://github.com/missive/emoji-mart/commit/2de83100a02b8374686ee6a318d882e0e96e820a)
|
||||
- Don’t include keywords in data file [`dbf2207`](https://github.com/missive/emoji-mart/commit/dbf22073c8d25a2c797eab7b2e9cd58147229f1a)
|
||||
- Strip quotes around keys [`0bfd3b3`](https://github.com/missive/emoji-mart/commit/0bfd3b3e52ee60d7e2c303544990aa4ef52a5f37)
|
||||
|
||||
#### [v0.4.2](https://github.com/missive/emoji-mart/compare/v0.4.1...v0.4.2)
|
||||
|
||||
> 17 February 2017
|
||||
|
||||
- Use variations at runtime instead of overriding data [`f5ae64d`](https://github.com/missive/emoji-mart/commit/f5ae64d07ce4bfd341ddcc390d02832792cd87bd)
|
||||
- Release v0.4.2 [`87ab03e`](https://github.com/missive/emoji-mart/commit/87ab03e6bdbf74911d7b2be22031738466c70a54)
|
||||
|
||||
#### [v0.4.1](https://github.com/missive/emoji-mart/compare/v0.4.0...v0.4.1)
|
||||
|
||||
> 17 February 2017
|
||||
|
||||
- Prefer first variation over default unified value [`489641b`](https://github.com/missive/emoji-mart/commit/489641bda6ec6353df9b713094ce570a160eb203)
|
||||
- Release v0.4.1 [`ff0cc12`](https://github.com/missive/emoji-mart/commit/ff0cc12fbc386f571260475fc40bdee309916017)
|
||||
- Fix `watch` script not bundling example [`44d401a`](https://github.com/missive/emoji-mart/commit/44d401ae489009b48df3594c22655b175fc93a42)
|
||||
|
||||
#### [v0.4.0](https://github.com/missive/emoji-mart/compare/v0.3.7...v0.4.0)
|
||||
|
||||
> 17 February 2017
|
||||
|
||||
- Allow picker to display emoji natively [`#40`](https://github.com/missive/emoji-mart/pull/40)
|
||||
- Add karma/jasmine + tests for emoji-index and picker [`#44`](https://github.com/missive/emoji-mart/pull/44)
|
||||
- allow style overrides from user [`#45`](https://github.com/missive/emoji-mart/pull/45)
|
||||
- Fix categories on IE11 [`#46`](https://github.com/missive/emoji-mart/pull/46)
|
||||
- Add emojisToShow filter [`#43`](https://github.com/missive/emoji-mart/pull/43)
|
||||
- Preserve height and width on svgs [`#41`](https://github.com/missive/emoji-mart/pull/41)
|
||||
- Category: export from index.js [`#39`](https://github.com/missive/emoji-mart/pull/39)
|
||||
- Use yarn [`00fdf61`](https://github.com/missive/emoji-mart/commit/00fdf6137ab496baef234333ad48d47b4c3b34fd)
|
||||
- add emojisToShow filter [`1a6e0e0`](https://github.com/missive/emoji-mart/commit/1a6e0e0fd31a8b1fdfc74ec8df09f0ef0997185d)
|
||||
- Uncomment PR #43 specs [`5c27f17`](https://github.com/missive/emoji-mart/commit/5c27f17154376ab2e4d13b2671ee391a489fe4f6)
|
||||
|
||||
#### [v0.3.7](https://github.com/missive/emoji-mart/compare/v0.3.6...v0.3.7)
|
||||
|
||||
> 18 January 2017
|
||||
|
||||
- Add emoji prop change check to Emoji component [`#35`](https://github.com/missive/emoji-mart/pull/35)
|
||||
- Fix issue with operator in skin tone logic [`#29`](https://github.com/missive/emoji-mart/pull/29)
|
||||
- Release v0.3.7 [`a02cca7`](https://github.com/missive/emoji-mart/commit/a02cca753581d33284f7432d41ea291057fa6da5)
|
||||
|
||||
#### [v0.3.6](https://github.com/missive/emoji-mart/compare/v0.3.5...v0.3.6)
|
||||
|
||||
> 16 January 2017
|
||||
|
||||
- wrap localStorage access in try-catch [`#34`](https://github.com/missive/emoji-mart/pull/34)
|
||||
- Release v0.3.6 [`7ffcecf`](https://github.com/missive/emoji-mart/commit/7ffcecf68eb7ae2d55d6165299d5c7369c662237)
|
||||
- Fix issue with operator in skin tone logic [`0db181e`](https://github.com/missive/emoji-mart/commit/0db181e301a1edcb0ef1ff699f9f23e424c69bab)
|
||||
|
||||
#### [v0.3.5](https://github.com/missive/emoji-mart/compare/v0.3.4...v0.3.5)
|
||||
|
||||
> 8 December 2016
|
||||
|
||||
- Allow custom namespace for store [`#27`](https://github.com/missive/emoji-mart/pull/27)
|
||||
- Allow passing children to Emoji component [`#28`](https://github.com/missive/emoji-mart/pull/28)
|
||||
- :lipstick: [`672a6a4`](https://github.com/missive/emoji-mart/commit/672a6a4dfc7e90ae79cb45dd695a18eeef10c83a)
|
||||
- Release v0.3.5 [`1482050`](https://github.com/missive/emoji-mart/commit/1482050298bbe57013835dba94457185dbf49e33)
|
||||
- Use children passed through props [`771b1e4`](https://github.com/missive/emoji-mart/commit/771b1e48f38b25bca6c37741f36b3d96e3a86370)
|
||||
|
||||
#### [v0.3.4](https://github.com/missive/emoji-mart/compare/v0.3.3...v0.3.4)
|
||||
|
||||
> 1 December 2016
|
||||
|
||||
- Allow a custom backgroundImageFn to be passed in [`#26`](https://github.com/missive/emoji-mart/pull/26)
|
||||
- Add backgroundImageFn to allow local image sheets [`a4be90a`](https://github.com/missive/emoji-mart/commit/a4be90aa6e6d56f4e7d4eacc40aed4429a217ed2)
|
||||
- Use dynamic version of emoji-datasource for the default sheet URL [`462ba0c`](https://github.com/missive/emoji-mart/commit/462ba0cd26b5de41392e879c45b2fc54b32b7d25)
|
||||
- Don’t check for backgroundImageFn change in Category#shouldComponentUpdate [`0d39e10`](https://github.com/missive/emoji-mart/commit/0d39e10a71b4d30f2c7553e4dc9027d1ced640b9)
|
||||
|
||||
#### [v0.3.3](https://github.com/missive/emoji-mart/compare/v0.3.2...v0.3.3)
|
||||
|
||||
> 17 November 2016
|
||||
|
||||
- Normalize line-height for all elements [Fix #24] [`#24`](https://github.com/missive/emoji-mart/issues/24)
|
||||
- Release v0.3.3 [`2931f55`](https://github.com/missive/emoji-mart/commit/2931f55e9382f0bfe20bbc710b45d4347402968c)
|
||||
|
||||
#### [v0.3.2](https://github.com/missive/emoji-mart/compare/v0.3.1...v0.3.2)
|
||||
|
||||
> 1 November 2016
|
||||
|
||||
- Isolate .emoji-mart-anchors from page line-height [`#22`](https://github.com/missive/emoji-mart/pull/22)
|
||||
- Update example [`4076bb4`](https://github.com/missive/emoji-mart/commit/4076bb40905263f10cdf2a7342afd1569296ee40)
|
||||
- Add `native` prop to Emoji [`dad72bc`](https://github.com/missive/emoji-mart/commit/dad72bc0fb823e2d0f8b8d2eabc5880d6695f48c)
|
||||
- Support :colons: syntax [`c460474`](https://github.com/missive/emoji-mart/commit/c4604741d980dc1406372b9d1e9ab88f0525b019)
|
||||
|
||||
#### [v0.3.1](https://github.com/missive/emoji-mart/compare/v0.3.0...v0.3.1)
|
||||
|
||||
> 27 October 2016
|
||||
|
||||
- Show only vertical scroll [`#21`](https://github.com/missive/emoji-mart/pull/21)
|
||||
- Add i18n prop to Picker [Close #20] [`#20`](https://github.com/missive/emoji-mart/issues/20)
|
||||
- Add sheetSize prop to Picker & Emoji [Close #18] [`#18`](https://github.com/missive/emoji-mart/issues/18)
|
||||
- :lipstick: [`1dfa582`](https://github.com/missive/emoji-mart/commit/1dfa58239f9b8d245dccf6f0661e090447005015)
|
||||
- Set Emoji.propTypes.skin as an enum [`afe8825`](https://github.com/missive/emoji-mart/commit/afe882560eb1f310e032815e3229b20c915e9623)
|
||||
- Set Emoji.propTypes.set as an enum [`ecc0862`](https://github.com/missive/emoji-mart/commit/ecc086260a7ddc33f4252173abb41472730c2d2c)
|
||||
|
||||
#### [v0.3.0](https://github.com/missive/emoji-mart/compare/v0.2.10...v0.3.0)
|
||||
|
||||
> 19 October 2016
|
||||
|
||||
- Remove “sheetURL” props & add “set” props [`4f2b204`](https://github.com/missive/emoji-mart/commit/4f2b204c0e225daa1f88a2599b8c7eec1dce3d9a)
|
||||
- Release v0.3.0 [`f6348a8`](https://github.com/missive/emoji-mart/commit/f6348a8196e7353a42d3d5bbf28622f98ab10c92)
|
||||
|
||||
#### [v0.2.10](https://github.com/missive/emoji-mart/compare/v0.2.9...v0.2.10)
|
||||
|
||||
> 18 October 2016
|
||||
|
||||
- Use hasOwnProperty to detect if emoji exists [`35a9921`](https://github.com/missive/emoji-mart/commit/35a992118ab62812d71db741192cbeeecf59df31)
|
||||
- Release v0.2.10 [`1b83241`](https://github.com/missive/emoji-mart/commit/1b832414c5ba1956a5dd2031d1b2d395abe042df)
|
||||
|
||||
#### [v0.2.9](https://github.com/missive/emoji-mart/compare/v0.2.8...v0.2.9)
|
||||
|
||||
> 14 October 2016
|
||||
|
||||
- Release v0.2.9 [`e429147`](https://github.com/missive/emoji-mart/commit/e429147d1fe9d1c49bfeccc24e678e8b1c892464)
|
||||
- Fix “Recent” category showing up when clicking an emoji for the first time while searching [`dc93357`](https://github.com/missive/emoji-mart/commit/dc933571374b5cf01157699c771f2f770ea45180)
|
||||
- Also split search terms at “-” & “_” [`996c46c`](https://github.com/missive/emoji-mart/commit/996c46cd9cbb19b0737b0d0288dcf6956acbe84d)
|
||||
|
||||
#### [v0.2.8](https://github.com/missive/emoji-mart/compare/v0.2.7...v0.2.8)
|
||||
|
||||
> 13 October 2016
|
||||
|
||||
- Support all short_names when getting emoji data [Fix #15] [`#15`](https://github.com/missive/emoji-mart/issues/15)
|
||||
- Release v0.2.8 [`0076173`](https://github.com/missive/emoji-mart/commit/00761734d83d815ba3976058867c54e092ba5cb7)
|
||||
|
||||
#### [v0.2.7](https://github.com/missive/emoji-mart/compare/v0.2.5...v0.2.7)
|
||||
|
||||
> 13 October 2016
|
||||
|
||||
- Handle unknown emojis [Fix #14] [`#14`](https://github.com/missive/emoji-mart/issues/14)
|
||||
- Release v0.2.7 [`00eea58`](https://github.com/missive/emoji-mart/commit/00eea587600eca1d7754c50c04d55de428916080)
|
||||
|
||||
#### [v0.2.5](https://github.com/missive/emoji-mart/compare/v0.2.4...v0.2.5)
|
||||
|
||||
> 4 October 2016
|
||||
|
||||
- Add support for server-side rendering [Fix #7] [`#7`](https://github.com/missive/emoji-mart/issues/7)
|
||||
- :lipstick: [`903395e`](https://github.com/missive/emoji-mart/commit/903395e31f3b429321e859b378252c4f1423ea54)
|
||||
- Release v0.2.4 [`ac4feba`](https://github.com/missive/emoji-mart/commit/ac4feba228c18199ecf6a6a960223d0221668e1c)
|
||||
|
||||
#### [v0.2.4](https://github.com/missive/emoji-mart/compare/v0.2.3...v0.2.4)
|
||||
|
||||
> 30 September 2016
|
||||
|
||||
- Replace npmcdn.com with unpkg.com [`#12`](https://github.com/missive/emoji-mart/pull/12)
|
||||
- Update webpack React externals [Fix #11, Fix #8] [`#11`](https://github.com/missive/emoji-mart/issues/11) [`#8`](https://github.com/missive/emoji-mart/issues/8)
|
||||
- Release v0.2.4 [`29063f2`](https://github.com/missive/emoji-mart/commit/29063f2f646e7aa9b4970110a819123e1c96c125)
|
||||
|
||||
#### [v0.2.3](https://github.com/missive/emoji-mart/compare/v0.2.2...v0.2.3)
|
||||
|
||||
> 29 July 2016
|
||||
|
||||
- Add GH Star button to demo page [`af3b792`](https://github.com/missive/emoji-mart/commit/af3b7928b376a38aa81bb9660ea6831432749903)
|
||||
- Update README [`b25b25b`](https://github.com/missive/emoji-mart/commit/b25b25b5ebe11f5908c4960892c9cf24f5d2ccee)
|
||||
- Release v0.2.3 [`3303566`](https://github.com/missive/emoji-mart/commit/33035669b6157b739b7f01fc8ff1600d631956ed)
|
||||
|
||||
#### [v0.2.2](https://github.com/missive/emoji-mart/compare/v0.2.1...v0.2.2)
|
||||
|
||||
> 29 July 2016
|
||||
|
||||
- Update demo page [`df0c920`](https://github.com/missive/emoji-mart/commit/df0c920f6695faee43ce66a633eed98689ea03bd)
|
||||
- Build example in `example/bundle.js` [`ecf3784`](https://github.com/missive/emoji-mart/commit/ecf3784d32b9c5d6e95537f82ff7934cdbb8e038)
|
||||
- Update README [`f01ad53`](https://github.com/missive/emoji-mart/commit/f01ad53b6f1e4585c2beddaa7a3f308dc33e2ce7)
|
||||
|
||||
#### [v0.2.1](https://github.com/missive/emoji-mart/compare/v0.2.0...v0.2.1)
|
||||
|
||||
> 28 July 2016
|
||||
|
||||
- Update README [`9c7e461`](https://github.com/missive/emoji-mart/commit/9c7e461e21b46f13540fd80382a67fe60f1e5008)
|
||||
- BSD Simplified license [`3dd27d3`](https://github.com/missive/emoji-mart/commit/3dd27d3a1359ff7008012114d3045646f665d0fd)
|
||||
- Release v0.2.1 [`16a4256`](https://github.com/missive/emoji-mart/commit/16a42565cc898055c798b5d38a7040b9f476e938)
|
||||
|
||||
#### [v0.2.0](https://github.com/missive/emoji-mart/compare/v0.1.5...v0.2.0)
|
||||
|
||||
> 27 July 2016
|
||||
|
||||
- Ignore data & dist folders and add prepublish npm script [`3f04c9c`](https://github.com/missive/emoji-mart/commit/3f04c9cafa2d1029cb277effd5eaa7a9fef88492)
|
||||
- 🏬 Emoji Mart™ [`9648c7d`](https://github.com/missive/emoji-mart/commit/9648c7d8e20f10b407a8786e77b5e73d07314815)
|
||||
- Release v0.2.0 [`d10f914`](https://github.com/missive/emoji-mart/commit/d10f914f17e2665616bb7a19c31b9f9fc4761b87)
|
||||
|
||||
#### [v0.1.5](https://github.com/missive/emoji-mart/compare/v0.1.4...v0.1.5)
|
||||
|
||||
> 26 July 2016
|
||||
|
||||
- Sort search results by score [Close #1] [`#1`](https://github.com/missive/emoji-mart/issues/1)
|
||||
- Release v0.1.5 [`760d140`](https://github.com/missive/emoji-mart/commit/760d140410d730b45916d7af85b0002ddcc08980)
|
||||
- Update emojis search string [`9feee08`](https://github.com/missive/emoji-mart/commit/9feee08e069b11ea93025fdb2003736d7a7138f9)
|
||||
- Export frequently util [`2b734d8`](https://github.com/missive/emoji-mart/commit/2b734d8ef6075017746bffeb71e2151013898e6a)
|
||||
|
||||
#### [v0.1.4](https://github.com/missive/emoji-mart/compare/v0.1.3...v0.1.4)
|
||||
|
||||
> 22 July 2016
|
||||
|
||||
- Release v0.1.4 [`b702397`](https://github.com/missive/emoji-mart/commit/b7023971ad714a9c19d18e3758e36241aeafb101)
|
||||
- Use custom search index instead of lunr [`be1e670`](https://github.com/missive/emoji-mart/commit/be1e6705c3bf18f254768eaf541134b882618d15)
|
||||
- Support searching for multiple (2) terms [`5721f5f`](https://github.com/missive/emoji-mart/commit/5721f5f6949a8a72339de0b26be5a9cccc553fc2)
|
||||
|
||||
#### [v0.1.3](https://github.com/missive/emoji-mart/compare/v0.1.2...v0.1.3)
|
||||
|
||||
> 20 July 2016
|
||||
|
||||
- Release v0.1.3 [`aed099c`](https://github.com/missive/emoji-mart/commit/aed099cd1c3efa0192ef74ae49b9e3caf8d33c50)
|
||||
- Move some reusable logic into utils [`a51626a`](https://github.com/missive/emoji-mart/commit/a51626ae79383bd21df3e912ee46afd3aa468a1d)
|
||||
- Fix circular dependencies [`0ebd5c4`](https://github.com/missive/emoji-mart/commit/0ebd5c4a5e8bb8dfa76b79a62b805a1ed53bfc2a)
|
||||
|
||||
#### [v0.1.2](https://github.com/missive/emoji-mart/compare/v0.1.1...v0.1.2)
|
||||
|
||||
> 15 July 2016
|
||||
|
||||
- Release v0.1.2 [`1615fc1`](https://github.com/missive/emoji-mart/commit/1615fc1f34f015e3630319db1dca17deefd57c4a)
|
||||
- Only render first 3 categories on first render [`9eb8f0b`](https://github.com/missive/emoji-mart/commit/9eb8f0b6ac3ecdd814dc55470fbaf44e801a395d)
|
||||
- Make picker’s title and emoji customizable [`b0893c3`](https://github.com/missive/emoji-mart/commit/b0893c39be88fbc9479cddf18e8662d842d95249)
|
||||
|
||||
#### [v0.1.1](https://github.com/missive/emoji-mart/compare/v0.1.0...v0.1.1)
|
||||
|
||||
> 12 July 2016
|
||||
|
||||
- Do not generate .map files [`820bb3d`](https://github.com/missive/emoji-mart/commit/820bb3d966ffe0a1bc0de83b78769bae55f232c5)
|
||||
- Release v0.1.1 [`ce3ab53`](https://github.com/missive/emoji-mart/commit/ce3ab5340047076a9dd74f362d547e29c4381f1b)
|
||||
- Fix external React lib name [`d9f5cd3`](https://github.com/missive/emoji-mart/commit/d9f5cd3101b64d349d5bed69435fe724ff789ec1)
|
||||
|
||||
#### v0.1.0
|
||||
|
||||
> 11 July 2016
|
||||
|
||||
- Release v0.1.0 [`17a86d5`](https://github.com/missive/emoji-mart/commit/17a86d52688d2b6fda9eec051084483e64d2bc4d)
|
||||
- Do not ignore data and dist folders [`69e9dfe`](https://github.com/missive/emoji-mart/commit/69e9dfea0026c7ca05231af94273d74b9b5d63d3)
|
||||
- Initial commit [`e108b00`](https://github.com/missive/emoji-mart/commit/e108b00768b009540b18738349b049800f58f296)
|
273
README.md
273
README.md
|
@ -1,7 +1,8 @@
|
|||
<div align="center">
|
||||
<br><b>Emoji Mart</b> is a Slack-like customizable<br>emoji picker component for React
|
||||
<br><a href="https://missive.github.io/emoji-mart">Demo</a> • <a href="https://github.com/missive/emoji-mart/releases">Changelog</a>
|
||||
<br><br><img width="338" alt="picker" src="https://user-images.githubusercontent.com/436043/32532554-08be471c-c400-11e7-906a-c745dc3ec630.png">
|
||||
<br><a href="https://missive.github.io/emoji-mart">Demo</a> • <a href="https://github.com/missive/emoji-mart/blob/master/CHANGELOG.md">Changelog</a>
|
||||
<br><br><a href="https://travis-ci.org/missive/emoji-mart"><img src="https://travis-ci.org/missive/emoji-mart.svg?branch=master" alt="Build Status"></a>
|
||||
<br><br><img width="420" alt="picker" src="https://user-images.githubusercontent.com/436043/71363432-1b69d000-2567-11ea-9416-88446025e03c.png">
|
||||
<br><br><a title="Team email, team chat, team tasks, one app" href="https://missiveapp.com"><img width="30" alt="Missive | Team email, team chat, team tasks, one app" src="https://user-images.githubusercontent.com/436043/32532559-0d15ddfc-c400-11e7-8a24-64d0157d0cb0.png"></a>
|
||||
<br>Brought to you by the <a title="Team email, team chat, team tasks, one app" href="https://missiveapp.com">Missive</a> team
|
||||
</div>
|
||||
|
@ -16,7 +17,7 @@
|
|||
import 'emoji-mart/css/emoji-mart.css'
|
||||
import { Picker } from 'emoji-mart'
|
||||
|
||||
<Picker set='emojione' />
|
||||
<Picker set='apple' />
|
||||
<Picker onSelect={this.addEmoji} />
|
||||
<Picker title='Pick your emoji…' emoji='point_up' />
|
||||
<Picker style={{ position: 'absolute', bottom: '20px', right: '20px' }} />
|
||||
|
@ -32,6 +33,7 @@ import { Picker } from 'emoji-mart'
|
|||
| **exclude** | | `[]` | Don't load excluded categories. Accepts [I18n categories keys](#i18n). |
|
||||
| **custom** | | `[]` | [Custom emojis](#custom-emojis) |
|
||||
| **recent** | | | Pass your own frequently used emojis as array of string IDs |
|
||||
| **enableFrequentEmojiSort** | | `false` | Instantly sort “Frequently Used” category |
|
||||
| **emojiSize** | | `24` | The emoji width and height |
|
||||
| **onClick** | | | Params: `(emoji, event) => {}`. Not called when emoji is selected with `enter` |
|
||||
| **onSelect** | | | Params: `(emoji) => {}` |
|
||||
|
@ -39,26 +41,35 @@ import { Picker } from 'emoji-mart'
|
|||
| **perLine** | | `9` | Number of emojis per line. While there’s no minimum or maximum, this will affect the picker’s width. This will set *Frequently Used* length as well (`perLine * 4`) |
|
||||
| **i18n** | | [`{…}`](#i18n) | [An object](#i18n) containing localized strings |
|
||||
| **native** | | `false` | Renders the native unicode emoji |
|
||||
| **set** | | `apple` | The emoji set: `'apple', 'google', 'twitter', 'emojione', 'messenger', 'facebook'` |
|
||||
| **set** | | `apple` | The emoji set: `'apple', 'google', 'twitter', 'facebook'` |
|
||||
| **theme** | | `light` | The picker theme: `'auto', 'light', 'dark'` |
|
||||
| **sheetSize** | | `64` | The emoji [sheet size](#sheet-sizes): `16, 20, 32, 64` |
|
||||
| **backgroundImageFn** | | ```((set, sheetSize) => …)``` | A Fn that returns that image sheet to use for emojis. Useful for avoiding a request if you have the sheet locally. |
|
||||
| **emojisToShowFilter** | | ```((emoji) => true)``` | A Fn to choose whether an emoji should be displayed or not |
|
||||
| **showPreview** | | `true` | Display preview section |
|
||||
| **showSkinTones** | | `true` | Display skin tones picker |
|
||||
| **showSkinTones** | | `true` | Display skin tones picker. Disable both this and `showPreview` to remove the footer entirely. |
|
||||
| **emojiTooltip** | | `false` | Show emojis short name when hovering (title) |
|
||||
| **useButton** | | `true` | When clickable, render emojis with a `<button>`. Some browsers have issues rendering certain emojis on a button, so you might want to disable this. It is better for accessibility to use buttons. |
|
||||
| **skin** | | | Forces skin color: `1, 2, 3, 4, 5, 6` |
|
||||
| **defaultSkin** | | `1` | Default skin color: `1, 2, 3, 4, 5, 6` |
|
||||
| **skinEmoji** | | | The emoji used to pick a skin tone. Uses an emoji-less skin tone picker by default |
|
||||
| **style** | | | Inline styles applied to the root element. Useful for positioning |
|
||||
| **title** | | `Emoji Mart™` | The title shown when no emojis are hovered |
|
||||
| **notFoundEmoji** | | `sleuth_or_spy` | The emoji shown when there are no search results |
|
||||
| **notFound** | | | [Not Found](#not-found) |
|
||||
| **icons** | | `{}` | [Custom icons](#custom-icons) |
|
||||
|
||||
#### I18n
|
||||
```js
|
||||
search: 'Search',
|
||||
clear: 'Clear', // Accessible label on "clear" button
|
||||
notfound: 'No Emoji Found',
|
||||
skintext: 'Choose your default skin tone',
|
||||
categories: {
|
||||
search: 'Search Results',
|
||||
recent: 'Frequently Used',
|
||||
people: 'Smileys & People',
|
||||
smileys: 'Smileys & Emotion',
|
||||
people: 'People & Body',
|
||||
nature: 'Animals & Nature',
|
||||
foods: 'Food & Drink',
|
||||
activity: 'Activity',
|
||||
|
@ -67,38 +78,49 @@ categories: {
|
|||
symbols: 'Symbols',
|
||||
flags: 'Flags',
|
||||
custom: 'Custom',
|
||||
}
|
||||
},
|
||||
categorieslabel: 'Emoji categories', // Accessible title for the list of categories
|
||||
skintones: {
|
||||
1: 'Default Skin Tone',
|
||||
2: 'Light Skin Tone',
|
||||
3: 'Medium-Light Skin Tone',
|
||||
4: 'Medium Skin Tone',
|
||||
5: 'Medium-Dark Skin Tone',
|
||||
6: 'Dark Skin Tone',
|
||||
},
|
||||
```
|
||||
|
||||
**Tip:** You usually do not need to translate the categories and skin tones by youself, because this data and their translations [should be included in the Unicode CLDR](http://cldr.unicode.org/) (the ["Common Locale Data Repository"](https://en.wikipedia.org/wiki/Common_Locale_Data_Repository)). You can look them up and just take them from there.
|
||||
|
||||
#### Sheet sizes
|
||||
Sheets are served from [unpkg](https://unpkg.com), a global CDN that serves files published to [npm](https://www.npmjs.com).
|
||||
|
||||
| Set | sheetSize | Size |
|
||||
| --------- | --------- | -------- |
|
||||
| apple | 16 | 334 KB |
|
||||
| apple | 20 | 459 KB |
|
||||
| apple | 32 | 1.08 MB |
|
||||
| apple | 64 | 2.94 MB |
|
||||
| emojione | 16 | 315 KB |
|
||||
| emojione | 20 | 435 KB |
|
||||
| emojione | 32 | 1020 KB |
|
||||
| emojione | 64 | 2.33 MB |
|
||||
| facebook | 16 | 322 KB |
|
||||
| facebook | 20 | 439 KB |
|
||||
| facebook | 32 | 1020 KB |
|
||||
| facebook | 64 | 2.5 MB |
|
||||
| google | 16 | 301 KB |
|
||||
| google | 20 | 409 KB |
|
||||
| google | 32 | 907 KB |
|
||||
| google | 64 | 2.17 MB |
|
||||
| messenger | 16 | 325 KB |
|
||||
| messenger | 20 | 449 MB |
|
||||
| messenger | 32 | 1.05 MB |
|
||||
| messenger | 64 | 2.69 MB |
|
||||
| twitter | 16 | 288 KB |
|
||||
| twitter | 20 | 389 KB |
|
||||
| twitter | 32 | 839 KB |
|
||||
| twitter | 64 | 1.82 MB |
|
||||
| Set | Size (`sheetSize: 16`) | Size (`sheetSize: 20`) | Size (`sheetSize: 32`) | Size (`sheetSize: 64`) |
|
||||
| --------- | ---------------------- | ---------------------- | ---------------------- | ---------------------- |
|
||||
| apple | 407 KB | 561 KB | 1.34 MB | 3.60 MB |
|
||||
| facebook | 416 KB | 579 KB | 1.38 MB | 3.68 MB |
|
||||
| google | 362 KB | 489 KB | 1.12 MB | 2.78 MB |
|
||||
| twitter | 361 KB | 485 KB | 1.05 MB | 2.39 MB |
|
||||
|
||||
#### Datasets
|
||||
While all sets are available by default, you may want to include only a single set data to reduce the size of your bundle.
|
||||
|
||||
| Set | Size (on disk) |
|
||||
| --------- | -------------- |
|
||||
| all | 611 KB |
|
||||
| apple | 548 KB |
|
||||
| facebook | 468 KB |
|
||||
| google | 518 KB |
|
||||
| twitter | 517 KB |
|
||||
|
||||
To use these data files (or any other custom data), use the `NimblePicker` component:
|
||||
|
||||
```js
|
||||
import data from 'emoji-mart/data/google.json'
|
||||
import { NimblePicker } from 'emoji-mart'
|
||||
|
||||
<NimblePicker set='google' data={data} />
|
||||
```
|
||||
|
||||
#### Examples of `emoji` object:
|
||||
```js
|
||||
|
@ -128,11 +150,11 @@ Sheets are served from [unpkg](https://unpkg.com), a global CDN that serves file
|
|||
{
|
||||
id: 'octocat',
|
||||
name: 'Octocat',
|
||||
colons: ':octocat',
|
||||
colons: ':octocat:',
|
||||
text: '',
|
||||
emoticons: [],
|
||||
custom: true,
|
||||
imageUrl: 'https://assets-cdn.github.com/images/icons/emoji/octocat.png?v7'
|
||||
imageUrl: 'https://github.githubassets.com/images/icons/emoji/octocat.png'
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -143,7 +165,7 @@ import { Emoji } from 'emoji-mart'
|
|||
|
||||
<Emoji emoji={{ id: 'santa', skin: 3 }} size={16} />
|
||||
<Emoji emoji=':santa::skin-tone-3:' size={16} />
|
||||
<Emoji emoji='santa' set='emojione' size={16} />
|
||||
<Emoji emoji='santa' set='apple' size={16} />
|
||||
```
|
||||
|
||||
| Prop | Required | Default | Description |
|
||||
|
@ -154,8 +176,8 @@ import { Emoji } from 'emoji-mart'
|
|||
| **onClick** | | | Params: `(emoji, event) => {}` |
|
||||
| **onLeave** | | | Params: `(emoji, event) => {}` |
|
||||
| **onOver** | | | Params: `(emoji, event) => {}` |
|
||||
| [**fallback**](#unsupported-emojis-fallback) | | | Params: `(emoji) => {}` |
|
||||
| **set** | | `apple` | The emoji set: `'apple', 'google', 'twitter', 'emojione'` |
|
||||
| [**fallback**](#unsupported-emojis-fallback) | | | Params: `(emoji, props) => {}` |
|
||||
| **set** | | `apple` | The emoji set: `'apple', 'google', 'twitter'` |
|
||||
| **sheetSize** | | `64` | The emoji [sheet size](#sheet-sizes): `16, 20, 32, 64` |
|
||||
| **backgroundImageFn** | | ```((set, sheetSize) => `https://unpkg.com/emoji-datasource@3.0.0/sheet_${set}_${sheetSize}.png`)``` | A Fn that returns that image sheet to use for emojis. Useful for avoiding a request if you have the sheet locally. |
|
||||
| **skin** | | `1` | Skin color: `1, 2, 3, 4, 5, 6` |
|
||||
|
@ -163,17 +185,17 @@ import { Emoji } from 'emoji-mart'
|
|||
| [**html**](#using-with-dangerouslysetinnerhtml) | | `false` | Returns an HTML string to use with `dangerouslySetInnerHTML` |
|
||||
|
||||
#### Unsupported emojis fallback
|
||||
Certain sets don’t support all emojis (i.e. Messenger & Facebook don’t support `:shrug:`). By default the Emoji component will not render anything so that the emojis’ don’t take space in the picker when not available. When using the standalone Emoji component, you can however render anything you want by providing the `fallback` props.
|
||||
Certain sets don’t support all emojis. By default the Emoji component will not render anything so that the emojis’ don’t take space in the picker when not available. When using the standalone Emoji component, you can however render anything you want by providing the `fallback` props.
|
||||
|
||||
To have the component render `:shrug:` you would need to:
|
||||
|
||||
```js
|
||||
<Emoji
|
||||
set={'messenger'}
|
||||
set={'apple'}
|
||||
emoji={'shrug'}
|
||||
size={24}
|
||||
fallback={(emoji) => {
|
||||
return `:${emoji.short_names[0]}:`
|
||||
fallback={(emoji, props) => {
|
||||
return emoji ? `:${emoji.short_names[0]}:` : props.emoji
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
@ -211,7 +233,7 @@ Following the `dangerouslySetInnerHTML` example above, make sure the wrapping `s
|
|||
```
|
||||
|
||||
## Custom emojis
|
||||
You can provide custom emojis which will show up in their own category.
|
||||
You can provide custom emojis which will show up in their own category. You can either use a single image as imageUrl or use a spritesheet as shown in the second object.
|
||||
|
||||
```js
|
||||
import { Picker } from 'emoji-mart'
|
||||
|
@ -223,13 +245,58 @@ const customEmojis = [
|
|||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['github'],
|
||||
imageUrl: 'https://assets-cdn.github.com/images/icons/emoji/octocat.png?v7'
|
||||
imageUrl: 'https://github.githubassets.com/images/icons/emoji/octocat.png',
|
||||
customCategory: 'GitHub'
|
||||
},
|
||||
{
|
||||
name: 'Test Flag',
|
||||
short_names: ['test'],
|
||||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['test', 'flag'],
|
||||
spriteUrl: 'https://unpkg.com/emoji-datasource-twitter@4.0.4/img/twitter/sheets-256/64.png',
|
||||
sheet_x: 1,
|
||||
sheet_y: 1,
|
||||
size: 64,
|
||||
sheetColumns: 52,
|
||||
sheetRows: 52,
|
||||
},
|
||||
]
|
||||
|
||||
<Picker custom={customEmojis} />
|
||||
```
|
||||
|
||||
The `customCategory` string is optional. If you include it, then the custom emoji will be shown in whatever
|
||||
categories you define. If you don't include it, then there will just be one category called "Custom."
|
||||
|
||||
## Not Found
|
||||
You can provide a custom Not Found object which will allow the appearance of the not found search results to change. In this case, we change the default 'sleuth_or_spy' emoji to Octocat when our search finds no results.
|
||||
|
||||
```js
|
||||
import { Picker } from 'emoji-mart'
|
||||
|
||||
const notFound = () => <img src='https://github.githubassets.com/images/icons/emoji/octocat.png' />
|
||||
|
||||
<Picker notFound={notFound} />
|
||||
```
|
||||
|
||||
## Custom icons
|
||||
You can provide custom icons which will override the default icons.
|
||||
|
||||
```js
|
||||
import { Picker } from 'emoji-mart'
|
||||
|
||||
const customIcons = {
|
||||
categories: {
|
||||
recent: () => <img src='https://github.githubassets.com/images/icons/emoji/octocat.png' />,
|
||||
foods: () => <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0l6.084 24H8L1.916 0zM21 5h-4l-1-4H4l3 12h3l1 4h13L21 5zM6.563 3h7.875l2 8H8.563l-2-8zm8.832 10l-2.856 1.904L12.063 13h3.332zM19 13l-1.5-6h1.938l2 8H16l3-2z"/></svg>,
|
||||
people: () => <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M3 2l10 6-10 6z"></path></svg>
|
||||
}
|
||||
}
|
||||
|
||||
<Picker icons={customIcons} />
|
||||
```
|
||||
|
||||
## Headless search
|
||||
The `Picker` doesn’t have to be mounted for you to take advantage of the advanced search results.
|
||||
|
||||
|
@ -240,6 +307,45 @@ emojiIndex.search('christmas').map((o) => o.native)
|
|||
// => [🎄, 🎅🏼, 🔔, 🎁, ⛄️, ❄️]
|
||||
```
|
||||
|
||||
### With custom data
|
||||
```js
|
||||
import data from 'emoji-mart/datasets/apple'
|
||||
import { NimbleEmojiIndex } from 'emoji-mart'
|
||||
|
||||
let emojiIndex = new NimbleEmojiIndex(data)
|
||||
emojiIndex.search('christmas')
|
||||
```
|
||||
|
||||
## Get emoji data from Native
|
||||
You can get emoji data from native emoji unicode using the `getEmojiDataFromNative` util function.
|
||||
|
||||
```js
|
||||
import { getEmojiDataFromNative, Emoji } from 'emoji-mart'
|
||||
import data from 'emoji-mart/data/all.json'
|
||||
|
||||
const emojiData = getEmojiDataFromNative('🏊🏽♀️', 'apple', data)
|
||||
|
||||
<Emoji
|
||||
emoji={emojiData}
|
||||
set={'apple'}
|
||||
skin={emojiData.skin || 1}
|
||||
size={48}
|
||||
/>
|
||||
```
|
||||
|
||||
#### Example of `emojiData` object:
|
||||
```js
|
||||
emojiData: {
|
||||
"id": "woman-swimming",
|
||||
"name": "Woman Swimming",
|
||||
"colons": ":woman-swimming::skin-tone-4:",
|
||||
"emoticons": [],
|
||||
"unified": "1f3ca-1f3fd-200d-2640-fe0f",
|
||||
"skin": 4,
|
||||
"native": "🏊🏽♀️"
|
||||
}
|
||||
```
|
||||
|
||||
## Storage
|
||||
By default EmojiMart will store user chosen skin and frequently used emojis in `localStorage`. That can however be overwritten should you want to store these in your own storage.
|
||||
|
||||
|
@ -299,19 +405,86 @@ It can however be overwritten as per user preference.
|
|||
<img width="98" alt="customizable-skin" src="https://user-images.githubusercontent.com/436043/32532883-2c620e7c-c402-11e7-976c-50d32be0566c.png">
|
||||
|
||||
#### Multiple sets supported
|
||||
Apple / Google / Twitter / EmojiOne / Messenger / Facebook
|
||||
Apple / Google / Twitter / Facebook
|
||||
|
||||
<img width="214" alt="sets" src="https://user-images.githubusercontent.com/436043/33786868-d4226e60-dc38-11e7-840a-e4cf490f5f4a.png">
|
||||
|
||||
## Not opinionated
|
||||
**Emoji Mart** doesn’t automatically insert anything into a text input, nor does it show or hide itself. It simply returns an `emoji` object. It’s up to the developer to mount/unmount (it’s fast!) and position the picker. You can use the returned object as props for the `EmojiMart.Emoji` component. You could also use `emoji.colons` to insert text into a textarea or `emoji.native` to use the emoji.
|
||||
|
||||
## Development
|
||||
```sh
|
||||
$ yarn build
|
||||
$ yarn start
|
||||
$ yarn storybook
|
||||
## Usage outside React
|
||||
|
||||
**Emoji Mart** can be used with React alternatives such as [Preact](https://preactjs.com/), [Inferno](https://www.infernojs.org/), and [react-lite](https://github.com/Lucifier129/react-lite).
|
||||
|
||||
Furthermore, you can use it as a [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) using [remount](https://github.com/rstacruz/remount), meaning that you can use it within any JavaScript framework (or vanilla JS).
|
||||
|
||||
For an end-to-end example of how to do this, see [emoji-mart-outside-react](https://github.com/nolanlawson/emoji-mart-outside-react).
|
||||
|
||||
## Optimizing for production
|
||||
|
||||
### Modern/ES builds
|
||||
|
||||
**Emoji Mart** comes in three flavors:
|
||||
|
||||
```
|
||||
dist
|
||||
dist-es
|
||||
dist-modern
|
||||
```
|
||||
|
||||
- `dist` is the standard build with the highest level of compatibility.
|
||||
- `dist-es` is the same, but uses ES modules for better tree-shaking.
|
||||
- `dist-modern` removes features not needed in modern evergreen browsers (i.e. latest Chrome, Edge, Firefox, and Safari).
|
||||
|
||||
The default builds are `dist` and `dist-es`. (In Webpack, one or the other will be chosen based on your [resolve main fields](https://webpack.js.org/configuration/resolve/#resolve-mainfields).)
|
||||
If you want to use `dist-modern`, you must explicitly import it:
|
||||
|
||||
```js
|
||||
import { Picker } from 'emoji-mart/dist-modern/index.js'
|
||||
```
|
||||
|
||||
Using something like Babel, you can transpile the modern build to suit your own needs.
|
||||
|
||||
### Removing prop-types
|
||||
|
||||
To remove [prop-types](https://github.com/facebook/prop-types) in production, use [babel-plugin-transform-react-remove-prop-types](https://github.com/oliviertassinari/babel-plugin-transform-react-remove-prop-types):
|
||||
|
||||
```bash
|
||||
npm install --save-dev babel-plugin-transform-react-remove-prop-types
|
||||
```
|
||||
|
||||
Then add to your `.babelrc`:
|
||||
|
||||
```json
|
||||
"plugins": [
|
||||
[
|
||||
"transform-react-remove-prop-types",
|
||||
{
|
||||
"removeImport": true,
|
||||
"additionalLibraries": [
|
||||
"../../utils/shared-props"
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
You'll also need to ensure that Babel is transpiling `emoji-mart`, e.g. [by not excluding `node_modules` in `babel-loader`](https://github.com/babel/babel-loader#usage).
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
In two separate tabs:
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
yarn storybook
|
||||
```
|
||||
|
||||
The storybook is hosted at `localhost:6006`, and the code will be built on-the-fly.
|
||||
|
||||
## 🎩 Hat tips!
|
||||
Powered by [iamcal/emoji-data](https://github.com/iamcal/emoji-data) and inspired by [iamcal/js-emoji](https://github.com/iamcal/js-emoji).<br>
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
const { devDependencies } = require('./package.json')
|
||||
|
||||
module.exports = {
|
||||
presets: ['@babel/preset-react'],
|
||||
plugins: [
|
||||
'@babel/plugin-transform-runtime',
|
||||
[
|
||||
'babel-plugin-transform-define',
|
||||
{
|
||||
'process.env.NODE_ENV': 'production',
|
||||
EMOJI_DATASOURCE_VERSION: devDependencies['emoji-datasource'],
|
||||
},
|
||||
],
|
||||
],
|
||||
env: {
|
||||
'legacy-es': {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'legacy-cjs': {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: 'cjs',
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
modern: {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
chrome: '77',
|
||||
edge: '18',
|
||||
firefox: '71',
|
||||
safari: '13',
|
||||
},
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
test: {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
node: 'current',
|
||||
}
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
|
@ -37,7 +37,6 @@
|
|||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 0 6px;
|
||||
color: #858585;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
|
@ -45,12 +44,19 @@
|
|||
position: relative;
|
||||
display: block;
|
||||
flex: 1 1 auto;
|
||||
color: #858585;
|
||||
text-align: center;
|
||||
padding: 12px 4px;
|
||||
overflow: hidden;
|
||||
transition: color .1s ease-out;
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
.emoji-mart-anchor:focus { outline: 0 }
|
||||
.emoji-mart-anchor:hover,
|
||||
.emoji-mart-anchor:focus,
|
||||
.emoji-mart-anchor-selected {
|
||||
color: #464646;
|
||||
}
|
||||
|
@ -72,13 +78,16 @@
|
|||
max-width: 22px;
|
||||
}
|
||||
|
||||
.emoji-mart-anchors svg {
|
||||
.emoji-mart-anchors svg,
|
||||
.emoji-mart-anchors img {
|
||||
fill: currentColor;
|
||||
max-height: 18px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.emoji-mart-scroll {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 270px;
|
||||
padding: 0 6px 6px 6px;
|
||||
will-change: transform; /* avoids "repaints on scroll" in mobile Chrome */
|
||||
|
@ -87,17 +96,39 @@
|
|||
.emoji-mart-search {
|
||||
margin-top: 6px;
|
||||
padding: 0 6px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.emoji-mart-search input {
|
||||
font-size: 16px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: .2em .6em;
|
||||
border-radius: 25px;
|
||||
padding: 5px 25px 6px 10px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #d9d9d9;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.emoji-mart-search input,
|
||||
.emoji-mart-search input::-webkit-search-decoration,
|
||||
.emoji-mart-search input::-webkit-search-cancel-button,
|
||||
.emoji-mart-search input::-webkit-search-results-button,
|
||||
.emoji-mart-search input::-webkit-search-results-decoration {
|
||||
/* remove webkit/blink styles for <input type="search">
|
||||
* via https://stackoverflow.com/a/9422689 */
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.emoji-mart-search-icon {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 11px;
|
||||
z-index: 2;
|
||||
padding: 2px 5px 1px;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.emoji-mart-category .emoji-mart-emoji span {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
|
@ -106,7 +137,7 @@
|
|||
}
|
||||
|
||||
.emoji-mart-category .emoji-mart-emoji:hover:before {
|
||||
z-index: 0;
|
||||
z-index: -1;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
|
@ -132,10 +163,31 @@
|
|||
background-color: rgba(255, 255, 255, .95);
|
||||
}
|
||||
|
||||
.emoji-mart-category-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.emoji-mart-category-list li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.emoji-mart-emoji {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font-size: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.emoji-mart-emoji-native {
|
||||
font-family: "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "Android Emoji";
|
||||
}
|
||||
|
||||
.emoji-mart-no-results {
|
||||
|
@ -144,6 +196,12 @@
|
|||
padding-top: 70px;
|
||||
color: #858585;
|
||||
}
|
||||
.emoji-mart-no-results-img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 50%;
|
||||
}
|
||||
.emoji-mart-no-results .emoji-mart-category-label {
|
||||
display: none;
|
||||
}
|
||||
|
@ -181,6 +239,11 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.emoji-mart-preview-skins.custom {
|
||||
right: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.emoji-mart-preview-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
@ -223,12 +286,18 @@
|
|||
background-color: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch {
|
||||
.emoji-mart-skin-swatches.custom {
|
||||
font-size: 0;
|
||||
border: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches.opened .emoji-mart-skin-swatch {
|
||||
width: 16px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch-selected:after {
|
||||
.emoji-mart-skin-swatches.opened .emoji-mart-skin-swatch.selected:after {
|
||||
opacity: .75;
|
||||
}
|
||||
|
||||
|
@ -248,12 +317,13 @@
|
|||
.emoji-mart-skin-swatch:nth-child(5) { transition-delay: .12s }
|
||||
.emoji-mart-skin-swatch:nth-child(6) { transition-delay: .15s }
|
||||
|
||||
.emoji-mart-skin-swatch-selected {
|
||||
.emoji-mart-skin-swatch.selected {
|
||||
position: relative;
|
||||
width: 16px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
.emoji-mart-skin-swatch-selected:after {
|
||||
|
||||
.emoji-mart-skin-swatch.selected:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
|
@ -266,9 +336,63 @@
|
|||
transition: opacity .2s ease-out;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatch.custom {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 38px;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
transition-property: width, height;
|
||||
transition-duration: .125s;
|
||||
transition-timing-function: ease-out;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatch.custom.selected {
|
||||
position: relative;
|
||||
width: 36px;
|
||||
height: 38px;
|
||||
padding: 0 2px 0 0;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatch.custom.selected:after {
|
||||
content: "";
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches.custom .emoji-mart-skin-swatch.custom:hover {
|
||||
background-color: #f4f4f4;
|
||||
border-radius: 10%;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches.custom.opened .emoji-mart-skin-swatch.custom {
|
||||
width: 36px;
|
||||
height: 38px;
|
||||
padding: 0 2px 0 0;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches.custom.opened .emoji-mart-skin-swatch.custom.selected:after {
|
||||
opacity: .75;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-text.opened {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
text-align: left;
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
padding: 5px 2px;
|
||||
width: 95px;
|
||||
height: 40px;
|
||||
border-radius: 10%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-skin {
|
||||
display: inline-block;
|
||||
width: 100%; padding-top: 100%;
|
||||
width: 100%;
|
||||
padding-top: 100%;
|
||||
max-width: 12px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
@ -279,3 +403,59 @@
|
|||
.emoji-mart-skin-tone-4 { background-color: #bf8f68 }
|
||||
.emoji-mart-skin-tone-5 { background-color: #9b643d }
|
||||
.emoji-mart-skin-tone-6 { background-color: #594539 }
|
||||
|
||||
/* For screenreaders only, via https://stackoverflow.com/a/19758620 */
|
||||
.emoji-mart-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dark mode styles
|
||||
*/
|
||||
|
||||
.emoji-mart-dark {
|
||||
color: #fff;
|
||||
border-color: #555453;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-bar {
|
||||
border-color: #555453;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-search input {
|
||||
color: #fff;
|
||||
border-color: #555453;
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-search-icon svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-category .emoji-mart-emoji:hover:before {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-category-label span {
|
||||
background-color: #222;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-skin-swatches {
|
||||
border-color: #555453;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-anchor:hover,
|
||||
.emoji-mart-dark .emoji-mart-anchor:focus,
|
||||
.emoji-mart-dark .emoji-mart-anchor-selected {
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6521
docs/bundle.js
6521
docs/bundle.js
File diff suppressed because one or more lines are too long
|
@ -37,7 +37,6 @@
|
|||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 0 6px;
|
||||
color: #858585;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
|
@ -45,12 +44,19 @@
|
|||
position: relative;
|
||||
display: block;
|
||||
flex: 1 1 auto;
|
||||
color: #858585;
|
||||
text-align: center;
|
||||
padding: 12px 4px;
|
||||
overflow: hidden;
|
||||
transition: color .1s ease-out;
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
.emoji-mart-anchor:focus { outline: 0 }
|
||||
.emoji-mart-anchor:hover,
|
||||
.emoji-mart-anchor:focus,
|
||||
.emoji-mart-anchor-selected {
|
||||
color: #464646;
|
||||
}
|
||||
|
@ -72,13 +78,16 @@
|
|||
max-width: 22px;
|
||||
}
|
||||
|
||||
.emoji-mart-anchors svg {
|
||||
.emoji-mart-anchors svg,
|
||||
.emoji-mart-anchors img {
|
||||
fill: currentColor;
|
||||
max-height: 18px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.emoji-mart-scroll {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 270px;
|
||||
padding: 0 6px 6px 6px;
|
||||
will-change: transform; /* avoids "repaints on scroll" in mobile Chrome */
|
||||
|
@ -87,17 +96,39 @@
|
|||
.emoji-mart-search {
|
||||
margin-top: 6px;
|
||||
padding: 0 6px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.emoji-mart-search input {
|
||||
font-size: 16px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: .2em .6em;
|
||||
border-radius: 25px;
|
||||
padding: 5px 25px 6px 10px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #d9d9d9;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.emoji-mart-search input,
|
||||
.emoji-mart-search input::-webkit-search-decoration,
|
||||
.emoji-mart-search input::-webkit-search-cancel-button,
|
||||
.emoji-mart-search input::-webkit-search-results-button,
|
||||
.emoji-mart-search input::-webkit-search-results-decoration {
|
||||
/* remove webkit/blink styles for <input type="search">
|
||||
* via https://stackoverflow.com/a/9422689 */
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.emoji-mart-search-icon {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 11px;
|
||||
z-index: 2;
|
||||
padding: 2px 5px 1px;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.emoji-mart-category .emoji-mart-emoji span {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
|
@ -132,10 +163,31 @@
|
|||
background-color: rgba(255, 255, 255, .95);
|
||||
}
|
||||
|
||||
.emoji-mart-category-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.emoji-mart-category-list li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.emoji-mart-emoji {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font-size: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.emoji-mart-emoji-native {
|
||||
font-family: "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "Android Emoji";
|
||||
}
|
||||
|
||||
.emoji-mart-no-results {
|
||||
|
@ -144,6 +196,12 @@
|
|||
padding-top: 70px;
|
||||
color: #858585;
|
||||
}
|
||||
.emoji-mart-no-results-img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 50%;
|
||||
}
|
||||
.emoji-mart-no-results .emoji-mart-category-label {
|
||||
display: none;
|
||||
}
|
||||
|
@ -181,6 +239,11 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.emoji-mart-preview-skins.custom {
|
||||
right: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.emoji-mart-preview-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
@ -223,12 +286,18 @@
|
|||
background-color: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch {
|
||||
.emoji-mart-skin-swatches.custom {
|
||||
font-size: 0;
|
||||
border: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches.opened .emoji-mart-skin-swatch {
|
||||
width: 16px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch-selected:after {
|
||||
.emoji-mart-skin-swatches.opened .emoji-mart-skin-swatch.selected:after {
|
||||
opacity: .75;
|
||||
}
|
||||
|
||||
|
@ -248,12 +317,13 @@
|
|||
.emoji-mart-skin-swatch:nth-child(5) { transition-delay: .12s }
|
||||
.emoji-mart-skin-swatch:nth-child(6) { transition-delay: .15s }
|
||||
|
||||
.emoji-mart-skin-swatch-selected {
|
||||
.emoji-mart-skin-swatch.selected {
|
||||
position: relative;
|
||||
width: 16px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
.emoji-mart-skin-swatch-selected:after {
|
||||
|
||||
.emoji-mart-skin-swatch.selected:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
|
@ -266,9 +336,63 @@
|
|||
transition: opacity .2s ease-out;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatch.custom {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 38px;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
transition-property: width, height;
|
||||
transition-duration: .125s;
|
||||
transition-timing-function: ease-out;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatch.custom.selected {
|
||||
position: relative;
|
||||
width: 36px;
|
||||
height: 38px;
|
||||
padding: 0 2px 0 0;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatch.custom.selected:after {
|
||||
content: "";
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches.custom .emoji-mart-skin-swatch.custom:hover {
|
||||
background-color: #f4f4f4;
|
||||
border-radius: 10%;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches.custom.opened .emoji-mart-skin-swatch.custom {
|
||||
width: 36px;
|
||||
height: 38px;
|
||||
padding: 0 2px 0 0;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-swatches.custom.opened .emoji-mart-skin-swatch.custom.selected:after {
|
||||
opacity: .75;
|
||||
}
|
||||
|
||||
.emoji-mart-skin-text.opened {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
text-align: left;
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
padding: 5px 2px;
|
||||
width: 95px;
|
||||
height: 40px;
|
||||
border-radius: 10%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-skin {
|
||||
display: inline-block;
|
||||
width: 100%; padding-top: 100%;
|
||||
width: 100%;
|
||||
padding-top: 100%;
|
||||
max-width: 12px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
@ -279,3 +403,59 @@
|
|||
.emoji-mart-skin-tone-4 { background-color: #bf8f68 }
|
||||
.emoji-mart-skin-tone-5 { background-color: #9b643d }
|
||||
.emoji-mart-skin-tone-6 { background-color: #594539 }
|
||||
|
||||
/* For screenreaders only, via https://stackoverflow.com/a/19758620 */
|
||||
.emoji-mart-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dark mode styles
|
||||
*/
|
||||
|
||||
.emoji-mart-dark {
|
||||
color: #fff;
|
||||
border-color: #555453;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-bar {
|
||||
border-color: #555453;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-search input {
|
||||
color: #fff;
|
||||
border-color: #555453;
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-search-icon svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-category .emoji-mart-emoji:hover:before {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-category-label span {
|
||||
background-color: #222;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-skin-swatches {
|
||||
border-color: #555453;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.emoji-mart-dark .emoji-mart-anchor:hover,
|
||||
.emoji-mart-dark .emoji-mart-anchor:focus,
|
||||
.emoji-mart-dark .emoji-mart-anchor-selected {
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
button + button { margin-left: .5em }
|
||||
button {
|
||||
.sets button + button { margin-left: .5em }
|
||||
.sets button {
|
||||
padding: .4em .6em;
|
||||
border-radius: 5px;
|
||||
border: 1px solid rgba(0, 0, 0, .1);
|
||||
|
@ -26,7 +26,7 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
button[disabled] {
|
||||
.sets button[disabled] {
|
||||
border-color: #ae65c5;
|
||||
cursor: default;
|
||||
}
|
||||
|
@ -35,11 +35,13 @@
|
|||
font-family: Courier;
|
||||
}
|
||||
|
||||
.row + .row {
|
||||
.row + .row,
|
||||
.row-small + .row {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.row-small {
|
||||
.row + .row-small,
|
||||
.row-small + .row-small {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
|
@ -51,9 +53,21 @@
|
|||
font-size: 21px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div></div>
|
||||
<div class="row" id="picker"></div>
|
||||
|
||||
<div class="row-small">
|
||||
<a class="github-button" href="https://github.com/missive/emoji-mart" data-size="large" data-show-count="true" aria-label="Star missive/emoji-mart on GitHub">Star</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<a title="Team email, team chat, team tasks, one app" href="https://missiveapp.com"><img width="30" alt="Missive | Team email, team chat, team tasks, one app" src="https://user-images.githubusercontent.com/436043/32532559-0d15ddfc-c400-11e7-8a24-64d0157d0cb0.png"></a>
|
||||
<br>Brought to you by the <a title="Team email, team chat, team tasks, one app" href="https://missiveapp.com">Missive</a> team
|
||||
</div>
|
||||
|
||||
<script src="./bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
118
docs/index.js
118
docs/index.js
|
@ -1,26 +1,26 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
|
||||
import { Picker, Emoji } from '../src'
|
||||
import { Picker, Emoji } from '../dist'
|
||||
|
||||
const CUSTOM_EMOJIS = [
|
||||
{
|
||||
name: 'Party Parrot',
|
||||
short_names: ['parrot'],
|
||||
keywords: ['party'],
|
||||
imageUrl: './images/parrot.gif'
|
||||
short_names: ['party_parrot'],
|
||||
keywords: ['party', 'parrot'],
|
||||
imageUrl: './images/parrot.gif',
|
||||
},
|
||||
{
|
||||
name: 'Octocat',
|
||||
short_names: ['octocat'],
|
||||
keywords: ['github'],
|
||||
imageUrl: 'https://assets-cdn.github.com/images/icons/emoji/octocat.png?v7'
|
||||
imageUrl: 'https://github.githubassets.com/images/icons/emoji/octocat.png',
|
||||
},
|
||||
{
|
||||
name: 'Squirrel',
|
||||
short_names: ['shipit', 'squirrel'],
|
||||
keywords: ['github'],
|
||||
imageUrl: 'https://assets-cdn.github.com/images/icons/emoji/shipit.png?v7'
|
||||
imageUrl: 'https://github.githubassets.com/images/icons/emoji/shipit.png',
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -30,60 +30,74 @@ class Example extends React.Component {
|
|||
this.state = {
|
||||
native: true,
|
||||
set: 'apple',
|
||||
theme: 'auto',
|
||||
emoji: 'point_up',
|
||||
title: 'Pick your emoji…',
|
||||
custom: CUSTOM_EMOJIS,
|
||||
useButton: false,
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div>
|
||||
<div className="row">
|
||||
<h1>Emoji Mart 🏬</h1>
|
||||
return (
|
||||
<div>
|
||||
<div className="row">
|
||||
<h1>Emoji Mart 🏬</h1>
|
||||
</div>
|
||||
|
||||
<div className="row sets">
|
||||
Set:
|
||||
{['native', 'apple', 'google', 'twitter', 'facebook'].map((set) => {
|
||||
var props = {
|
||||
disabled: !this.state.native && set == this.state.set,
|
||||
}
|
||||
|
||||
if (set == 'native' && this.state.native) {
|
||||
props.disabled = true
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
key={set}
|
||||
value={set}
|
||||
onClick={() => {
|
||||
if (set == 'native') {
|
||||
this.setState({ native: true })
|
||||
} else {
|
||||
this.setState({ set: set, native: false })
|
||||
}
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{set}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="row-small sets">
|
||||
Theme:
|
||||
{['auto', 'light', 'dark'].map((theme) => {
|
||||
return (
|
||||
<button
|
||||
key={theme}
|
||||
disabled={theme == this.state.theme}
|
||||
onClick={() => {
|
||||
this.setState({ theme })
|
||||
}}
|
||||
>
|
||||
{theme}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<Picker {...this.state} onSelect={console.log} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
{['native', 'apple', 'google', 'twitter', 'emojione', 'messenger', 'facebook'].map((set) => {
|
||||
var props = { disabled: !this.state.native && set == this.state.set }
|
||||
|
||||
if (set == 'native' && this.state.native) {
|
||||
props.disabled = true
|
||||
}
|
||||
|
||||
return <button
|
||||
key={set}
|
||||
value={set}
|
||||
onClick={() => {
|
||||
if (set == 'native') {
|
||||
this.setState({ native: true })
|
||||
} else {
|
||||
this.setState({ set: set, native: false })
|
||||
}
|
||||
}}
|
||||
{...props}>
|
||||
{set}
|
||||
</button>
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<Picker
|
||||
{...this.state}
|
||||
onSelect={console.log}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="row-small">
|
||||
<iframe
|
||||
src='https://ghbtns.com/github-btn.html?user=missive&repo=emoji-mart&type=star&count=true'
|
||||
frameBorder='0'
|
||||
scrolling='0'
|
||||
width='90px'
|
||||
height='20px'
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<Example />, document.querySelector('div'))
|
||||
ReactDOM.render(<Example />, document.querySelector('#picker'))
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
// Karma configuration
|
||||
// Generated on Fri Jan 27 2017 13:33:03 GMT-0700 (MST)
|
||||
var webpackConfig = require('./spec/webpack.config.js');
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '',
|
||||
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||
frameworks: ['jasmine'],
|
||||
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'spec/*spec.js',
|
||||
],
|
||||
|
||||
|
||||
// list of files to exclude
|
||||
exclude: [
|
||||
],
|
||||
|
||||
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
||||
preprocessors: {
|
||||
'spec/*spec.js': ['webpack'],
|
||||
},
|
||||
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ['progress'],
|
||||
|
||||
|
||||
// web server port
|
||||
port: 9876,
|
||||
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors: true,
|
||||
|
||||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: true,
|
||||
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||
browsers: ['Chrome'],
|
||||
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: true,
|
||||
|
||||
// Concurrency level
|
||||
// how many browser should be started simultaneous
|
||||
concurrency: Infinity,
|
||||
|
||||
webpack: webpackConfig,
|
||||
})
|
||||
}
|
177
package.json
177
package.json
|
@ -1,88 +1,89 @@
|
|||
{
|
||||
"name": "emoji-mart",
|
||||
"version": "2.5.1",
|
||||
"description": "Customizable Slack-like emoji picker for React",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist-es/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:missive/emoji-mart.git"
|
||||
},
|
||||
"keywords": [
|
||||
"react",
|
||||
"emoji",
|
||||
"picker"
|
||||
],
|
||||
"author": "Etienne Lemay",
|
||||
"license": "BSD-3-Clause",
|
||||
"bugs": {
|
||||
"url": "https://github.com/missive/emoji-mart/issues"
|
||||
},
|
||||
"homepage": "https://github.com/missive/emoji-mart",
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"react": "^0.14.0 || ^15.0.0-0 || ^16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-actions": "^3.2.11",
|
||||
"@storybook/addon-knobs": "^3.2.10",
|
||||
"@storybook/addon-links": "^3.2.10",
|
||||
"@storybook/addon-options": "3.2.10",
|
||||
"@storybook/react": "^3.2.11",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "6.7.2",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-module-resolver": "2.7.1",
|
||||
"babel-plugin-transform-define": "^1.3.0",
|
||||
"babel-plugin-transform-es2015-destructuring": "6.9.0",
|
||||
"babel-plugin-transform-object-rest-spread": "6.8.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.8",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-es2015": "6.6.0",
|
||||
"babel-preset-react": "6.5.0",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"emoji-datasource": "4.0.2",
|
||||
"emojilib": "^2.2.1",
|
||||
"inflection": "1.10.0",
|
||||
"jasmine-core": "^2.5.2",
|
||||
"karma": "^1.4.0",
|
||||
"karma-chrome-launcher": "^2.0.0",
|
||||
"karma-cli": "^1.0.1",
|
||||
"karma-jasmine": "^1.1.0",
|
||||
"karma-webpack": "^2.0.4",
|
||||
"mkdirp": "0.5.1",
|
||||
"prettier": "1.11.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"rimraf": "2.5.2",
|
||||
"size-limit": "^0.11.4",
|
||||
"webpack": "^3.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf dist/ dist-es/ src/data/data.js",
|
||||
"build:data": "node scripts/build-data",
|
||||
"build:dist": "npm run build:cjs && npm run build:es",
|
||||
"build:cjs": "BABEL_ENV=cjs babel src --out-dir dist --copy-files",
|
||||
"build:es": "babel src --out-dir dist-es --copy-files",
|
||||
"build:docs": "cp css/emoji-mart.css docs && webpack --config ./docs/webpack.config.js",
|
||||
"build": "npm run clean && npm run build:data && npm run build:dist",
|
||||
"watch": "BABEL_ENV=cjs babel src --watch --out-dir dist --copy-files",
|
||||
"start": "npm run watch",
|
||||
"stats": "webpack --config ./spec/webpack.config.js --json > spec/stats.json",
|
||||
"react:clean": "rimraf node_modules/{react,react-dom,react-addons-test-utils}",
|
||||
"react:14": "npm run react:clean && npm i react@^0.14 react-dom@^0.14 react-addons-test-utils@^0.14 --save-dev",
|
||||
"react:15": "npm run react:clean && npm i react@^15 react-dom@^15 react-addons-test-utils@^15 --save-dev",
|
||||
"test": "NODE_ENV=test karma start && size-limit",
|
||||
"prepublishOnly": "npm run build",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"build-storybook": "build-storybook",
|
||||
"prettier": "prettier --write \"{src,spec}/**/*.js\""
|
||||
},
|
||||
"size-limit": [
|
||||
{
|
||||
"path": "dist-es/index.js",
|
||||
"limit": "80 KB"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"name": "emoji-mart-lazyload",
|
||||
"version": "3.0.1k",
|
||||
"description": "Customizable Slack-like emoji picker for React",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist-es/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:mashirozx/emoji-mart.git"
|
||||
},
|
||||
"keywords": [
|
||||
"react",
|
||||
"emoji",
|
||||
"picker"
|
||||
],
|
||||
"author": "Etienne Lemay",
|
||||
"license": "BSD-3-Clause",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mashirozx/emoji-mart/issues"
|
||||
},
|
||||
"homepage": "https://github.com/mashirozx/emoji-mart",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.0.0",
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"@babel/preset-react": "7.0.0",
|
||||
"@storybook/addon-actions": "^3.2.11",
|
||||
"@storybook/addon-knobs": "^3.2.10",
|
||||
"@storybook/addon-links": "^3.2.10",
|
||||
"@storybook/addon-options": "3.2.10",
|
||||
"@storybook/react": "^3.2.11",
|
||||
"babel-jest": "^24.9.0",
|
||||
"babel-loader": "^8.0.0",
|
||||
"babel-plugin-transform-define": "^2.0.0",
|
||||
"emoji-datasource": "5.0.1",
|
||||
"emojilib": "^2.2.1",
|
||||
"enzyme": "^3.9.0",
|
||||
"enzyme-adapter-react-16": "^1.11.2",
|
||||
"inflection": "1.10.0",
|
||||
"jest": "^24.9.0",
|
||||
"mkdirp": "0.5.1",
|
||||
"prettier": "^1.16.4",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-test-renderer": "^16.8.4",
|
||||
"rimraf": "2.5.2",
|
||||
"size-limit": "^0.11.4",
|
||||
"webpack": "^3.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf dist/ dist-es/ dist-modern/",
|
||||
"build:data": "node scripts/build-data",
|
||||
"build:dist": "npm run build:cjs && npm run build:es && npm run build:modern",
|
||||
"build:cjs": "BABEL_ENV=legacy-cjs babel src --out-dir dist --ignore '**/__tests__/*'",
|
||||
"build:es": "BABEL_ENV=legacy-es babel src --out-dir dist-es --ignore '**/__tests__/*'",
|
||||
"build:modern": "BABEL_ENV=modern babel src --out-dir dist-modern --ignore '**/__tests__/*'",
|
||||
"build:docs": "cp css/emoji-mart.css docs && webpack --config ./docs/webpack.config.js",
|
||||
"build": "npm run clean && npm run build:dist",
|
||||
"watch": "BABEL_ENV=legacy-cjs babel src --watch --out-dir dist --ignore '**/__tests__/*'",
|
||||
"start": "npm run watch",
|
||||
"react:clean": "rimraf node_modules/{react,react-dom,react-addons-test-utils}",
|
||||
"react:14": "npm run react:clean && npm i react@^0.14 react-dom@^0.14 react-addons-test-utils@^0.14 --save-dev",
|
||||
"react:15": "npm run react:clean && npm i react@^15 react-dom@^15 react-addons-test-utils@^15 --save-dev",
|
||||
"test": "npm run clean && jest",
|
||||
"test:size": "size-limit",
|
||||
"test:ssr": "node test/ssr.js",
|
||||
"prepublishOnly": "npm run build",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"build-storybook": "build-storybook",
|
||||
"prettier": "prettier --write \"{src,scripts,test,stories}/**/*.js\"",
|
||||
"prettier:check": "prettier --check \"{src,scripts,test,stories}/**/*.js\"",
|
||||
"prepare": "npm run build:dist"
|
||||
},
|
||||
"size-limit": [
|
||||
{
|
||||
"path": "dist-es/index.js",
|
||||
"limit": "82 KB"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,107 +1,11 @@
|
|||
var fs = require('fs'),
|
||||
emojiData = require('emoji-datasource'),
|
||||
emojiLib = require('emojilib'),
|
||||
inflection = require('inflection'),
|
||||
mkdirp = require('mkdirp')
|
||||
const build = require('./build')
|
||||
const sets = ['apple', 'facebook', 'google', 'twitter']
|
||||
|
||||
var data = { categories: [], emojis: {}, skins: {}, short_names: {} },
|
||||
categoriesIndex = {}
|
||||
build({ output: 'data/all.json' })
|
||||
|
||||
var categories = [
|
||||
['Smileys & People', 'people'],
|
||||
['Animals & Nature', 'nature'],
|
||||
['Food & Drink', 'foods'],
|
||||
['Activities', 'activity'],
|
||||
['Travel & Places', 'places'],
|
||||
['Objects', 'objects'],
|
||||
['Symbols', 'symbols'],
|
||||
['Flags', 'flags'],
|
||||
]
|
||||
|
||||
categories.forEach((category, i) => {
|
||||
let [name, id] = category
|
||||
data.categories[i] = { id: id, name: name, emojis: [] }
|
||||
categoriesIndex[name] = i
|
||||
})
|
||||
|
||||
emojiData.sort((a, b) => {
|
||||
var aTest = a.sort_order || a.short_name,
|
||||
bTest = b.sort_order || b.short_name
|
||||
|
||||
return aTest - bTest
|
||||
})
|
||||
|
||||
emojiData.forEach((datum) => {
|
||||
var category = datum.category,
|
||||
keywords = [],
|
||||
categoryIndex
|
||||
|
||||
if (!datum.category) {
|
||||
throw new Error('“' + datum.short_name + '” doesn’t have a category')
|
||||
}
|
||||
|
||||
datum.name || (datum.name = datum.short_name.replace(/\-/g, ' '))
|
||||
datum.name = inflection.titleize(datum.name || '')
|
||||
|
||||
if (!datum.name) {
|
||||
throw new Error('“' + datum.short_name + '” doesn’t have a name')
|
||||
}
|
||||
|
||||
datum.emoticons = datum.texts || []
|
||||
datum.text = datum.text || ''
|
||||
delete datum.texts
|
||||
|
||||
if (emojiLib.lib[datum.short_name]) {
|
||||
datum.keywords = emojiLib.lib[datum.short_name].keywords
|
||||
}
|
||||
|
||||
if (datum.category == 'Skin Tones') {
|
||||
data.skins[datum.short_name] = datum
|
||||
} else {
|
||||
categoryIndex = categoriesIndex[category]
|
||||
data.categories[categoryIndex].emojis.push(datum.short_name)
|
||||
data.emojis[datum.short_name] = datum
|
||||
}
|
||||
|
||||
datum.short_names.forEach((short_name, i) => {
|
||||
if (i == 0) { return }
|
||||
data.short_names[short_name] = datum.short_name
|
||||
sets.forEach((set) => {
|
||||
build({
|
||||
output: `data/${set}.json`,
|
||||
sets: [set],
|
||||
})
|
||||
|
||||
datum.short_names = datum.short_names.filter(i => i !== datum.short_name)
|
||||
datum.sheet = [datum.sheet_x, datum.sheet_y]
|
||||
|
||||
if (datum.text === '') delete datum.text
|
||||
if (datum.added_in === '6.0') delete datum.added_in
|
||||
|
||||
delete datum.docomo
|
||||
delete datum.au
|
||||
delete datum.softbank
|
||||
delete datum.google
|
||||
delete datum.image
|
||||
delete datum.short_name
|
||||
delete datum.category
|
||||
delete datum.sort_order
|
||||
delete datum.sheet_x
|
||||
delete datum.sheet_y
|
||||
|
||||
for (let key in datum) {
|
||||
let value = datum[key]
|
||||
|
||||
if (Array.isArray(value) && !value.length) {
|
||||
delete datum[key]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var flags = data.categories[categoriesIndex['Flags']]
|
||||
flags.emojis = flags.emojis.filter((flag) => {
|
||||
// Until browsers support Flag UN
|
||||
if (flag == 'flag-un') return
|
||||
return true
|
||||
}).sort()
|
||||
|
||||
const stringified = JSON.stringify(data).replace(/\"([A-Za-z_]+)\":/g, '$1:')
|
||||
fs.writeFile('src/data/data.js', `export default ${stringified}`, (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
var fs = require('fs'),
|
||||
emojiLib = require('emojilib'),
|
||||
inflection = require('inflection'),
|
||||
mkdirp = require('mkdirp')
|
||||
|
||||
var { compress } = require('../dist/utils/data')
|
||||
|
||||
var categories = [
|
||||
['Smileys & Emotion', 'smileys'],
|
||||
['People & Body', 'people'],
|
||||
['Animals & Nature', 'nature'],
|
||||
['Food & Drink', 'foods'],
|
||||
['Activities', 'activity'],
|
||||
['Travel & Places', 'places'],
|
||||
['Objects', 'objects'],
|
||||
['Symbols', 'symbols'],
|
||||
['Flags', 'flags'],
|
||||
]
|
||||
|
||||
var sets = ['apple', 'facebook', 'google', 'twitter']
|
||||
|
||||
module.exports = (options) => {
|
||||
delete require.cache[require.resolve('emoji-datasource')]
|
||||
var emojiData = require('emoji-datasource')
|
||||
|
||||
var data = { compressed: true, categories: [], emojis: {}, aliases: {} },
|
||||
categoriesIndex = {}
|
||||
|
||||
categories.forEach((category, i) => {
|
||||
let [name, id] = category
|
||||
data.categories[i] = { id: id, name: name, emojis: [] }
|
||||
categoriesIndex[name] = i
|
||||
})
|
||||
|
||||
emojiData.sort((a, b) => {
|
||||
var aTest = a.sort_order || a.short_name,
|
||||
bTest = b.sort_order || b.short_name
|
||||
|
||||
return aTest - bTest
|
||||
})
|
||||
|
||||
emojiData.forEach((datum) => {
|
||||
var category = datum.category,
|
||||
keywords = [],
|
||||
categoryIndex
|
||||
|
||||
if (!datum.category) {
|
||||
throw new Error('“' + datum.short_name + '” doesn’t have a category')
|
||||
}
|
||||
|
||||
if (options.sets) {
|
||||
var keepEmoji = false
|
||||
|
||||
options.sets.forEach((set) => {
|
||||
if (keepEmoji) return
|
||||
if (datum[`has_img_${set}`]) {
|
||||
keepEmoji = true
|
||||
}
|
||||
})
|
||||
|
||||
if (!keepEmoji) {
|
||||
return
|
||||
}
|
||||
|
||||
sets.forEach((set) => {
|
||||
if (options.sets.length == 1 || options.sets.indexOf(set) == -1) {
|
||||
var key = `has_img_${set}`
|
||||
delete datum[key]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
datum.name || (datum.name = datum.short_name.replace(/\-/g, ' '))
|
||||
datum.name = inflection.titleize(datum.name || '')
|
||||
|
||||
if (!datum.name) {
|
||||
throw new Error('“' + datum.short_name + '” doesn’t have a name')
|
||||
}
|
||||
|
||||
datum.emoticons = datum.texts || []
|
||||
datum.text = datum.text || ''
|
||||
delete datum.texts
|
||||
|
||||
if (emojiLib.lib[datum.short_name]) {
|
||||
datum.keywords = emojiLib.lib[datum.short_name].keywords
|
||||
}
|
||||
|
||||
if (datum.category != 'Skin Tones') {
|
||||
categoryIndex = categoriesIndex[category]
|
||||
data.categories[categoryIndex].emojis.push(datum.short_name)
|
||||
data.emojis[datum.short_name] = datum
|
||||
}
|
||||
|
||||
datum.short_names.forEach((short_name, i) => {
|
||||
if (i == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
data.aliases[short_name] = datum.short_name
|
||||
})
|
||||
|
||||
delete datum.docomo
|
||||
delete datum.au
|
||||
delete datum.softbank
|
||||
delete datum.google
|
||||
delete datum.image
|
||||
delete datum.category
|
||||
delete datum.sort_order
|
||||
|
||||
compress(datum)
|
||||
})
|
||||
|
||||
var flags = data.categories[categoriesIndex['Flags']]
|
||||
flags.emojis = flags.emojis
|
||||
.filter((flag) => {
|
||||
// Until browsers support Flag UN
|
||||
if (flag == 'flag-un') return
|
||||
return true
|
||||
})
|
||||
.sort()
|
||||
|
||||
// Merge “Smileys & Emotion” and “People & Body” into a single category
|
||||
let smileys = data.categories[0]
|
||||
let people = data.categories[1]
|
||||
let smileysAndPeople = { id: 'people', name: 'Smileys & People' }
|
||||
smileysAndPeople.emojis = []
|
||||
.concat(smileys.emojis.slice(0, 114))
|
||||
.concat(people.emojis)
|
||||
.concat(smileys.emojis.slice(114))
|
||||
|
||||
data.categories.unshift(smileysAndPeople)
|
||||
data.categories.splice(1, 2)
|
||||
|
||||
fs.writeFile(options.output, JSON.stringify(data), (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
var pack = require('../package.json')
|
||||
|
||||
module.exports = {
|
||||
'process.env.NODE_ENV': 'production',
|
||||
EMOJI_DATASOURCE_VERSION: pack.devDependencies['emoji-datasource']
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
import emojiIndex from '../src/utils/emoji-index'
|
||||
|
||||
describe('#emojiIndex', () => {
|
||||
describe('search', function() {
|
||||
it('should work', () => {
|
||||
expect(emojiIndex.search('pineapple')).toEqual([
|
||||
{
|
||||
id: 'pineapple',
|
||||
name: 'Pineapple',
|
||||
colons: ':pineapple:',
|
||||
emoticons: [],
|
||||
unified: '1f34d',
|
||||
skin: null,
|
||||
native: '🍍',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('should filter only emojis we care about, exclude pineapple', () => {
|
||||
let emojisToShowFilter = (data) => {
|
||||
data.unified !== '1F34D'
|
||||
}
|
||||
expect(
|
||||
emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id),
|
||||
).not.toContain('pineapple')
|
||||
})
|
||||
|
||||
it('can include/exclude categories', () => {
|
||||
expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([])
|
||||
})
|
||||
|
||||
it('can search for thinking_face', () => {
|
||||
expect(emojiIndex.search('thinking_fac').map((x) => x.id)).toEqual([
|
||||
'thinking_face',
|
||||
])
|
||||
})
|
||||
|
||||
it('can search for woman-facepalming', () => {
|
||||
expect(emojiIndex.search('woman-facep').map((x) => x.id)).toEqual([
|
||||
'woman-facepalming',
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,45 +0,0 @@
|
|||
import React from 'react'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import Picker from '../src/components/picker'
|
||||
|
||||
const { click } = TestUtils.Simulate
|
||||
|
||||
const {
|
||||
renderIntoDocument,
|
||||
scryRenderedComponentsWithType,
|
||||
findRenderedComponentWithType,
|
||||
} = TestUtils
|
||||
|
||||
const render = (props = {}) => {
|
||||
const defaultProps = {}
|
||||
return renderIntoDocument(<Picker {...defaultProps} {...props} />)
|
||||
}
|
||||
|
||||
describe('Picker', () => {
|
||||
let subject
|
||||
|
||||
it('works', () => {
|
||||
subject = render()
|
||||
expect(subject).toBeDefined()
|
||||
})
|
||||
|
||||
describe('categories', () => {
|
||||
it('shows 10 by default', () => {
|
||||
subject = render()
|
||||
expect(subject.categories.length).toEqual(10)
|
||||
})
|
||||
|
||||
it('will not show some based upon our filter', () => {
|
||||
subject = render({ emojisToShowFilter: (unified) => false })
|
||||
expect(subject.categories.length).toEqual(2)
|
||||
})
|
||||
|
||||
it('maintains category ids after it is filtered', () => {
|
||||
subject = render({ emojisToShowFilter: (emoji) => true })
|
||||
const categoriesWithIds = subject.categories.filter(
|
||||
(category) => category.id,
|
||||
)
|
||||
expect(categoriesWithIds.length).toEqual(10)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,61 +0,0 @@
|
|||
var path = require('path')
|
||||
var pack = require('../package.json')
|
||||
var webpack = require('webpack')
|
||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
||||
.BundleAnalyzerPlugin
|
||||
|
||||
var PROD = process.env.NODE_ENV === 'production'
|
||||
var TEST = process.env.NODE_ENV === 'test'
|
||||
|
||||
var config = {
|
||||
entry: path.resolve('src/index.js'),
|
||||
output: {
|
||||
path: path.resolve('spec'),
|
||||
filename: 'bundle.js',
|
||||
library: 'EmojiMart',
|
||||
libraryTarget: 'umd',
|
||||
},
|
||||
|
||||
externals: [],
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: 'babel-loader',
|
||||
include: [path.resolve('src'), path.resolve('spec')],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: ['.js'],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
EMOJI_DATASOURCE_VERSION: `'${pack.devDependencies['emoji-datasource']}'`,
|
||||
}),
|
||||
],
|
||||
|
||||
bail: true,
|
||||
}
|
||||
|
||||
if (!TEST) {
|
||||
config.externals = config.externals.concat([
|
||||
{
|
||||
react: {
|
||||
root: 'React',
|
||||
commonjs2: 'react',
|
||||
commonjs: 'react',
|
||||
amd: 'react',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
config.plugins = config.plugins.concat([
|
||||
new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }),
|
||||
])
|
||||
}
|
||||
|
||||
module.exports = config
|
|
@ -0,0 +1,35 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Renders <NotFound> component 1`] = `
|
||||
<div
|
||||
className="emoji-mart-no-results"
|
||||
>
|
||||
<span
|
||||
aria-label="🕵️, sleuth_or_spy"
|
||||
className="emoji-mart-emoji emoji-mart-emoji-native"
|
||||
onClick={[Function]}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
title={null}
|
||||
>
|
||||
<span
|
||||
style={
|
||||
Object {
|
||||
"display": "inline-block",
|
||||
"fontSize": 38,
|
||||
"height": 38,
|
||||
"width": 38,
|
||||
"wordBreak": "keep-all",
|
||||
}
|
||||
}
|
||||
>
|
||||
🕵️
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
className="emoji-mart-no-results-label"
|
||||
>
|
||||
No Emoji Found
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,32 @@
|
|||
import React from 'react'
|
||||
import NotFound from '../not-found'
|
||||
import renderer from 'react-test-renderer'
|
||||
|
||||
import data from '../../../data/apple'
|
||||
|
||||
const i18n = {
|
||||
notfound: 'No Emoji Found',
|
||||
}
|
||||
|
||||
test('Renders <NotFound> component', () => {
|
||||
const emojiProps = {
|
||||
native: true,
|
||||
skin: 1,
|
||||
size: 24,
|
||||
set: 'apple',
|
||||
sheetSize: 64,
|
||||
forceSize: true,
|
||||
tooltip: false,
|
||||
}
|
||||
const component = renderer.create(
|
||||
<NotFound
|
||||
data={data}
|
||||
notFound={() => {}}
|
||||
notFoundEmoji={'sleuth_or_spy'}
|
||||
emojiProps={emojiProps}
|
||||
i18n={i18n}
|
||||
/>,
|
||||
)
|
||||
let tree = component.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
|
@ -0,0 +1,47 @@
|
|||
import React from 'react'
|
||||
import { shallow, configure } from 'enzyme'
|
||||
import Adapter from 'enzyme-adapter-react-16'
|
||||
import SkinsDot from '../skins-dot'
|
||||
|
||||
configure({ adapter: new Adapter() })
|
||||
|
||||
test('click dot to expand the menu', () => {
|
||||
let currentSkin
|
||||
const onChange = (skin) => {
|
||||
currentSkin = skin
|
||||
}
|
||||
const i18n = {
|
||||
skintones: {
|
||||
1: 'Default Skin Tone',
|
||||
2: 'Light Skin Tone',
|
||||
3: 'Medium-Light Skin Tone',
|
||||
4: 'Medium Skin Tone',
|
||||
5: 'Medium-Dark Skin Tone',
|
||||
6: 'Dark Skin Tone',
|
||||
},
|
||||
}
|
||||
|
||||
const skins = shallow(<SkinsDot skin={1} onChange={onChange} i18n={i18n} />)
|
||||
|
||||
// component should be un-expanded by default
|
||||
expect(skins.find('[aria-haspopup]').prop('aria-label')).toEqual(
|
||||
'Default Skin Tone',
|
||||
)
|
||||
expect(skins.find('[aria-haspopup]').prop('aria-expanded')).toEqual(false)
|
||||
|
||||
// simulate click
|
||||
skins.find('[aria-haspopup]').simulate('click', {
|
||||
currentTarget: {
|
||||
getAttribute(name) {
|
||||
if (name === 'data-skin') {
|
||||
return 1
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// component should now be expanded
|
||||
expect(skins.find('[aria-haspopup]').prop('aria-expanded')).toEqual(true)
|
||||
expect(skins.find('[data-skin=1]').prop('aria-pressed')).toEqual(true)
|
||||
expect(skins.find('[data-skin=2]').prop('aria-pressed')).toEqual(false)
|
||||
})
|
|
@ -1,8 +1,6 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import SVGs from '../svgs'
|
||||
|
||||
export default class Anchors extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
@ -18,21 +16,6 @@ export default class Anchors extends React.PureComponent {
|
|||
this.handleClick = this.handleClick.bind(this)
|
||||
}
|
||||
|
||||
getSVG(id) {
|
||||
this.SVGs || (this.SVGs = {})
|
||||
|
||||
if (this.SVGs[id]) {
|
||||
return this.SVGs[id]
|
||||
} else {
|
||||
let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
${SVGs[id]}
|
||||
</svg>`
|
||||
|
||||
this.SVGs[id] = svg
|
||||
return svg
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(e) {
|
||||
var index = e.currentTarget.getAttribute('data-index')
|
||||
var { categories, onAnchorClick } = this.props
|
||||
|
@ -41,11 +24,11 @@ export default class Anchors extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
var { categories, onAnchorClick, color, i18n } = this.props,
|
||||
var { categories, color, i18n, icons } = this.props,
|
||||
{ selected } = this.state
|
||||
|
||||
return (
|
||||
<div className="emoji-mart-anchors">
|
||||
<nav className="emoji-mart-anchors" aria-label={i18n.categorieslabel}>
|
||||
{categories.map((category, i) => {
|
||||
var { id, name, anchor } = category,
|
||||
isSelected = name == selected
|
||||
|
@ -54,36 +37,44 @@ export default class Anchors extends React.PureComponent {
|
|||
return null
|
||||
}
|
||||
|
||||
const iconId = id.startsWith('custom-') ? 'custom' : id
|
||||
|
||||
return (
|
||||
<span
|
||||
<button
|
||||
key={id}
|
||||
title={i18n.categories[id]}
|
||||
aria-label={i18n.categories[iconId]}
|
||||
title={i18n.categories[iconId]}
|
||||
data-index={i}
|
||||
type={'button'}
|
||||
onClick={this.handleClick}
|
||||
className={`emoji-mart-anchor ${
|
||||
isSelected ? 'emoji-mart-anchor-selected' : ''
|
||||
}`}
|
||||
style={{ color: isSelected ? color : null }}
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: this.getSVG(id) }} />
|
||||
<div className="emoji-mart-anchor-icon">
|
||||
{icons.categories[iconId]()}
|
||||
</div>
|
||||
<span
|
||||
className="emoji-mart-anchor-bar"
|
||||
style={{ backgroundColor: color }}
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Anchors.propTypes = {
|
||||
Anchors.propTypes /* remove-proptypes */ = {
|
||||
categories: PropTypes.array,
|
||||
onAnchorClick: PropTypes.func,
|
||||
icons: PropTypes.object,
|
||||
}
|
||||
|
||||
Anchors.defaultProps = {
|
||||
categories: [],
|
||||
onAnchorClick: () => {},
|
||||
icons: {},
|
||||
}
|
||||
|
|
|
@ -1,224 +1,291 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import frequently from '../utils/frequently'
|
||||
import { getData } from '../utils'
|
||||
import { Emoji } from '.'
|
||||
|
||||
export default class Category extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.setContainerRef = this.setContainerRef.bind(this)
|
||||
this.setLabelRef = this.setLabelRef.bind(this)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.parent = this.container.parentNode
|
||||
|
||||
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() {
|
||||
var { top, height } = this.container.getBoundingClientRect()
|
||||
var { top: parentTop } = this.parent.getBoundingClientRect()
|
||||
var { height: labelHeight } = this.label.getBoundingClientRect()
|
||||
|
||||
this.top = top - parentTop + this.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))
|
||||
}
|
||||
|
||||
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) {
|
||||
return
|
||||
}
|
||||
|
||||
this.container.style.display = display
|
||||
}
|
||||
|
||||
setContainerRef(c) {
|
||||
this.container = c
|
||||
}
|
||||
|
||||
setLabelRef(c) {
|
||||
this.label = c
|
||||
}
|
||||
|
||||
render() {
|
||||
var { id, name, hasStickyPosition, emojiProps, i18n } = this.props,
|
||||
emojis = this.getEmojis(),
|
||||
labelStyles = {},
|
||||
labelSpanStyles = {},
|
||||
containerStyles = {}
|
||||
|
||||
if (!emojis) {
|
||||
containerStyles = {
|
||||
display: 'none',
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasStickyPosition) {
|
||||
labelStyles = {
|
||||
height: 28,
|
||||
}
|
||||
|
||||
labelSpanStyles = {
|
||||
position: 'absolute',
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={this.setContainerRef}
|
||||
className={`emoji-mart-category ${
|
||||
emojis && !emojis.length ? 'emoji-mart-no-results' : ''
|
||||
}`}
|
||||
style={containerStyles}
|
||||
>
|
||||
<div
|
||||
style={labelStyles}
|
||||
data-name={name}
|
||||
className="emoji-mart-category-label"
|
||||
>
|
||||
<span style={labelSpanStyles} ref={this.setLabelRef}>
|
||||
{i18n.categories[id]}
|
||||
</span>
|
||||
</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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Category.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),
|
||||
}
|
||||
|
||||
Category.defaultProps = {
|
||||
emojis: [],
|
||||
hasStickyPosition: true,
|
||||
}
|
||||
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'
|
||||
import 'intersection-observer'
|
||||
|
||||
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)
|
||||
|
||||
this.imageObserver = new window.IntersectionObserver((entries, observer) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
const image = entry.target;
|
||||
image.src = image.dataset.src;
|
||||
image.classList.remove("lazy");
|
||||
this.imageObserver.unobserve(image);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.margin = 0
|
||||
this.minMargin = 0
|
||||
|
||||
this.memoizeSize()
|
||||
|
||||
this.lazyloadImages = []
|
||||
this.addLazyloadObserver()
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.addLazyloadObserver()
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.removeLazyloadObserver()
|
||||
}
|
||||
|
||||
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)
|
||||
shouldUpdate = true
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
addLazyloadObserver() {
|
||||
this.removeLazyloadObserver()
|
||||
this.lazyloadImages = this.container.querySelectorAll(".lazy");
|
||||
|
||||
this.lazyloadImages.forEach((image) => {
|
||||
this.imageObserver.observe(image);
|
||||
});
|
||||
}
|
||||
|
||||
removeLazyloadObserver() {
|
||||
this.lazyloadImages.forEach((image) => {
|
||||
this.imageObserver.unobserve(image);
|
||||
})
|
||||
}
|
||||
|
||||
handleOnContextMenu(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
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 (
|
||||
<section
|
||||
ref={this.setContainerRef}
|
||||
className="emoji-mart-category"
|
||||
aria-label={label}
|
||||
style={containerStyles}
|
||||
>
|
||||
<div
|
||||
style={labelStyles}
|
||||
data-name={name}
|
||||
className="emoji-mart-category-label"
|
||||
>
|
||||
<span
|
||||
style={labelSpanStyles}
|
||||
ref={this.setLabelRef}
|
||||
aria-hidden={true /* already labeled by the section aria-label */}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul className="emoji-mart-category-list">
|
||||
{emojis &&
|
||||
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,203 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import data from '../data'
|
||||
|
||||
import { getData, getSanitizedData, unifiedToNative } from '../utils'
|
||||
|
||||
const SHEET_COLUMNS = 52
|
||||
|
||||
const _getPosition = (props) => {
|
||||
var { sheet_x, sheet_y } = _getData(props),
|
||||
multiply = 100 / (SHEET_COLUMNS - 1)
|
||||
|
||||
return `${multiply * sheet_x}% ${multiply * sheet_y}%`
|
||||
}
|
||||
|
||||
const _getData = (props) => {
|
||||
var { emoji, skin, set } = props
|
||||
return getData(emoji, skin, set)
|
||||
}
|
||||
|
||||
const _getSanitizedData = (props) => {
|
||||
var { emoji, skin, set } = props
|
||||
return getSanitizedData(emoji, skin, set)
|
||||
}
|
||||
|
||||
const _handleClick = (e, props) => {
|
||||
if (!props.onClick) {
|
||||
return
|
||||
}
|
||||
var { onClick } = props,
|
||||
emoji = _getSanitizedData(props)
|
||||
|
||||
onClick(emoji, e)
|
||||
}
|
||||
|
||||
const _handleOver = (e, props) => {
|
||||
if (!props.onOver) {
|
||||
return
|
||||
}
|
||||
var { onOver } = props,
|
||||
emoji = _getSanitizedData(props)
|
||||
|
||||
onOver(emoji, e)
|
||||
}
|
||||
|
||||
const _handleLeave = (e, props) => {
|
||||
if (!props.onLeave) {
|
||||
return
|
||||
}
|
||||
var { onLeave } = props,
|
||||
emoji = _getSanitizedData(props)
|
||||
|
||||
onLeave(emoji, e)
|
||||
}
|
||||
|
||||
const _isNumeric = (value) => {
|
||||
return !isNaN(value - parseFloat(value))
|
||||
}
|
||||
|
||||
const _convertStyleToCSS = (style) => {
|
||||
let div = document.createElement('div')
|
||||
|
||||
for (let key in style) {
|
||||
let value = style[key]
|
||||
|
||||
if (_isNumeric(value)) {
|
||||
value += 'px'
|
||||
}
|
||||
|
||||
div.style[key] = value
|
||||
}
|
||||
|
||||
return div.getAttribute('style')
|
||||
}
|
||||
|
||||
const Emoji = (props) => {
|
||||
for (let k in Emoji.defaultProps) {
|
||||
if (props[k] == undefined && Emoji.defaultProps[k] != undefined) {
|
||||
props[k] = Emoji.defaultProps[k]
|
||||
}
|
||||
}
|
||||
|
||||
let data = _getData(props)
|
||||
if (!data) {
|
||||
return null
|
||||
}
|
||||
|
||||
let { unified, custom, short_names, imageUrl } = data,
|
||||
style = {},
|
||||
children = props.children,
|
||||
className = 'emoji-mart-emoji',
|
||||
title = null
|
||||
|
||||
if (!unified && !custom) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (props.tooltip) {
|
||||
title = short_names[0]
|
||||
}
|
||||
|
||||
if (props.native && unified) {
|
||||
className += ' emoji-mart-emoji-native'
|
||||
style = { fontSize: props.size }
|
||||
children = unifiedToNative(unified)
|
||||
|
||||
if (props.forceSize) {
|
||||
style.display = 'inline-block'
|
||||
style.width = props.size
|
||||
style.height = props.size
|
||||
}
|
||||
} else if (custom) {
|
||||
className += ' emoji-mart-emoji-custom'
|
||||
style = {
|
||||
width: props.size,
|
||||
height: props.size,
|
||||
display: 'inline-block',
|
||||
backgroundImage: `url(${imageUrl})`,
|
||||
backgroundSize: 'contain',
|
||||
}
|
||||
} else {
|
||||
let setHasEmoji = _getData(props)[`has_img_${props.set}`]
|
||||
|
||||
if (!setHasEmoji) {
|
||||
if (props.fallback) {
|
||||
return props.fallback(data)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
style = {
|
||||
width: props.size,
|
||||
height: props.size,
|
||||
display: 'inline-block',
|
||||
backgroundImage: `url(${props.backgroundImageFn(
|
||||
props.set,
|
||||
props.sheetSize,
|
||||
)})`,
|
||||
backgroundSize: `${100 * SHEET_COLUMNS}%`,
|
||||
backgroundPosition: _getPosition(props),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (props.html) {
|
||||
style = _convertStyleToCSS(style)
|
||||
return `<span style='${style}' ${
|
||||
title ? `title='${title}'` : ''
|
||||
} class='${className}'>${children || ''}</span>`
|
||||
} else {
|
||||
return (
|
||||
<span
|
||||
key={props.emoji.id || props.emoji}
|
||||
onClick={(e) => _handleClick(e, props)}
|
||||
onMouseEnter={(e) => _handleOver(e, props)}
|
||||
onMouseLeave={(e) => _handleLeave(e, props)}
|
||||
title={title}
|
||||
className={className}
|
||||
>
|
||||
<span style={style}>{children}</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Emoji.propTypes = {
|
||||
onOver: PropTypes.func,
|
||||
onLeave: PropTypes.func,
|
||||
onClick: PropTypes.func,
|
||||
fallback: PropTypes.func,
|
||||
backgroundImageFn: PropTypes.func,
|
||||
native: PropTypes.bool,
|
||||
forceSize: PropTypes.bool,
|
||||
tooltip: PropTypes.bool,
|
||||
skin: PropTypes.oneOf([1, 2, 3, 4, 5, 6]),
|
||||
sheetSize: PropTypes.oneOf([16, 20, 32, 64]),
|
||||
set: PropTypes.oneOf([
|
||||
'apple',
|
||||
'google',
|
||||
'twitter',
|
||||
'emojione',
|
||||
'messenger',
|
||||
'facebook',
|
||||
]),
|
||||
size: PropTypes.number.isRequired,
|
||||
emoji: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
|
||||
}
|
||||
|
||||
Emoji.defaultProps = {
|
||||
skin: 1,
|
||||
set: 'apple',
|
||||
sheetSize: 64,
|
||||
native: false,
|
||||
forceSize: false,
|
||||
tooltip: false,
|
||||
backgroundImageFn: (set, sheetSize) =>
|
||||
`https://unpkg.com/emoji-datasource-${set}@${EMOJI_DATASOURCE_VERSION}/img/${set}/sheets-256/${sheetSize}.png`,
|
||||
onOver: () => {},
|
||||
onLeave: () => {},
|
||||
onClick: () => {},
|
||||
}
|
||||
|
||||
export default Emoji
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react'
|
||||
|
||||
import data from '../../../data/all.json'
|
||||
import NimbleEmoji from './nimble-emoji'
|
||||
|
||||
import { EmojiPropTypes } from '../../utils/shared-props'
|
||||
import { EmojiDefaultProps } from '../../utils/shared-default-props'
|
||||
|
||||
const Emoji = (props) => {
|
||||
for (let k in Emoji.defaultProps) {
|
||||
if (props[k] == undefined && Emoji.defaultProps[k] != undefined) {
|
||||
props[k] = Emoji.defaultProps[k]
|
||||
}
|
||||
}
|
||||
|
||||
return NimbleEmoji({ ...props })
|
||||
}
|
||||
|
||||
Emoji.propTypes /* remove-proptypes */ = EmojiPropTypes
|
||||
Emoji.defaultProps = { ...EmojiDefaultProps, data }
|
||||
|
||||
export default Emoji
|
|
@ -0,0 +1,242 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { getData, getSanitizedData, unifiedToNative } from '../../utils'
|
||||
import { uncompress } from '../../utils/data'
|
||||
import { EmojiPropTypes } from '../../utils/shared-props'
|
||||
import { EmojiDefaultProps } from '../../utils/shared-default-props'
|
||||
|
||||
const _getData = (props) => {
|
||||
var { emoji, skin, set, data } = props
|
||||
return getData(emoji, skin, set, data)
|
||||
}
|
||||
|
||||
const _getPosition = (props) => {
|
||||
var { sheet_x, sheet_y } = _getData(props),
|
||||
multiplyX = 100 / (props.sheetColumns - 1),
|
||||
multiplyY = 100 / (props.sheetRows - 1)
|
||||
|
||||
return `${multiplyX * sheet_x}% ${multiplyY * sheet_y}%`
|
||||
}
|
||||
|
||||
const _getSanitizedData = (props) => {
|
||||
var { emoji, skin, set, data } = props
|
||||
return getSanitizedData(emoji, skin, set, data)
|
||||
}
|
||||
|
||||
const _handleClick = (e, props) => {
|
||||
if (!props.onClick) {
|
||||
return
|
||||
}
|
||||
var { onClick } = props,
|
||||
emoji = _getSanitizedData(props)
|
||||
|
||||
onClick(emoji, e)
|
||||
}
|
||||
|
||||
const _handleOver = (e, props) => {
|
||||
if (!props.onOver) {
|
||||
return
|
||||
}
|
||||
var { onOver } = props,
|
||||
emoji = _getSanitizedData(props)
|
||||
|
||||
onOver(emoji, e)
|
||||
}
|
||||
|
||||
const _handleLeave = (e, props) => {
|
||||
if (!props.onLeave) {
|
||||
return
|
||||
}
|
||||
var { onLeave } = props,
|
||||
emoji = _getSanitizedData(props)
|
||||
|
||||
onLeave(emoji, e)
|
||||
}
|
||||
|
||||
const _isNumeric = (value) => {
|
||||
return !isNaN(value - parseFloat(value))
|
||||
}
|
||||
|
||||
const _convertStyleToCSS = (style) => {
|
||||
let div = document.createElement('div')
|
||||
|
||||
for (let key in style) {
|
||||
let value = style[key]
|
||||
|
||||
if (_isNumeric(value)) {
|
||||
value += 'px'
|
||||
}
|
||||
|
||||
div.style[key] = value
|
||||
}
|
||||
|
||||
return div.getAttribute('style')
|
||||
}
|
||||
|
||||
const NimbleEmoji = (props) => {
|
||||
if (props.data.compressed) {
|
||||
uncompress(props.data)
|
||||
}
|
||||
|
||||
for (let k in NimbleEmoji.defaultProps) {
|
||||
if (props[k] == undefined && NimbleEmoji.defaultProps[k] != undefined) {
|
||||
props[k] = NimbleEmoji.defaultProps[k]
|
||||
}
|
||||
}
|
||||
|
||||
let data = _getData(props)
|
||||
if (!data) {
|
||||
if (props.fallback) {
|
||||
return props.fallback(null, props)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
let { unified, custom, short_names, imageUrl } = data,
|
||||
style = {},
|
||||
children = props.children,
|
||||
className = 'emoji-mart-emoji',
|
||||
nativeEmoji = unified && unifiedToNative(unified),
|
||||
// combine the emoji itself and all shortcodes into an accessible label
|
||||
label = [nativeEmoji]
|
||||
.concat(short_names)
|
||||
.filter(Boolean)
|
||||
.join(', '),
|
||||
title = null
|
||||
|
||||
if (!unified && !custom) {
|
||||
if (props.fallback) {
|
||||
return props.fallback(data, props)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
if (props.tooltip) {
|
||||
title = short_names[0]
|
||||
}
|
||||
|
||||
if (props.native && unified) {
|
||||
className += ' emoji-mart-emoji-native'
|
||||
style = { fontSize: props.size }
|
||||
children = nativeEmoji
|
||||
|
||||
if (props.forceSize) {
|
||||
style.display = 'inline-block'
|
||||
style.width = props.size
|
||||
style.height = props.size
|
||||
style.wordBreak = 'keep-all'
|
||||
}
|
||||
} else if (custom) {
|
||||
className += ' emoji-mart-emoji-custom'
|
||||
style = {
|
||||
width: props.size,
|
||||
height: props.size,
|
||||
display: 'inline-block',
|
||||
}
|
||||
if (data.spriteUrl) {
|
||||
style = {
|
||||
...style,
|
||||
backgroundImage: `url(${data.spriteUrl})`,
|
||||
backgroundSize: `${100 * props.sheetColumns}% ${100 *
|
||||
props.sheetRows}%`,
|
||||
backgroundPosition: _getPosition(props),
|
||||
}
|
||||
} else {
|
||||
style = {
|
||||
...style,
|
||||
backgroundImage: `url(${imageUrl})`,
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
}
|
||||
if(props.lazy){
|
||||
delete style.backgroundImage
|
||||
delete style.backgroundSize
|
||||
delete style.backgroundRepeat
|
||||
delete style.backgroundPosition
|
||||
style.objectFit = 'contain'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let setHasEmoji =
|
||||
data[`has_img_${props.set}`] == undefined || data[`has_img_${props.set}`]
|
||||
|
||||
if (!setHasEmoji) {
|
||||
if (props.fallback) {
|
||||
return props.fallback(data, props)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
style = {
|
||||
width: props.size,
|
||||
height: props.size,
|
||||
display: 'inline-block',
|
||||
backgroundImage: `url(${props.backgroundImageFn(
|
||||
props.set,
|
||||
props.sheetSize,
|
||||
)})`,
|
||||
backgroundSize: `${100 * props.sheetColumns}% ${100 *
|
||||
props.sheetRows}%`,
|
||||
backgroundPosition: _getPosition(props),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Tag = {
|
||||
name: 'span',
|
||||
props: {},
|
||||
}
|
||||
|
||||
if (props.onClick && props.useButton) {
|
||||
Tag.name = 'button'
|
||||
Tag.props = {
|
||||
type: 'button',
|
||||
}
|
||||
}
|
||||
|
||||
if (props.html) {
|
||||
style = _convertStyleToCSS(style)
|
||||
return `<${Tag.name} style='${style}' aria-label='${label}' ${
|
||||
title ? `title='${title}'` : ''
|
||||
} class='${className}'>${children || ''}</${Tag.name}>`
|
||||
} else {
|
||||
return (
|
||||
<Tag.name
|
||||
onClick={(e) => _handleClick(e, props)}
|
||||
onMouseEnter={(e) => _handleOver(e, props)}
|
||||
onMouseLeave={(e) => _handleLeave(e, props)}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
aria-label={label}
|
||||
title={title}
|
||||
className={className}
|
||||
{...Tag.props}
|
||||
>
|
||||
{
|
||||
custom && !data.spriteUrl && props.lazy
|
||||
?
|
||||
<img
|
||||
style={style}
|
||||
className="lazy"
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP89B8AAukB8/71MdcAAAAASUVORK5CYII="
|
||||
data-src={imageUrl}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
:
|
||||
<span style={style}>{children}</span>
|
||||
}
|
||||
</Tag.name>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NimbleEmoji.propTypes /* remove-proptypes */ = {
|
||||
...EmojiPropTypes,
|
||||
data: PropTypes.object.isRequired,
|
||||
}
|
||||
NimbleEmoji.defaultProps = EmojiDefaultProps
|
||||
|
||||
export default NimbleEmoji
|
|
@ -1,7 +0,0 @@
|
|||
export { default as Anchors } from './anchors'
|
||||
export { default as Category } from './category'
|
||||
export { default as Emoji } from './emoji'
|
||||
export { default as Picker } from './picker'
|
||||
export { default as Preview } from './preview'
|
||||
export { default as Search } from './search'
|
||||
export { default as Skins } from './skins'
|
|
@ -0,0 +1,32 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import NimbleEmoji from './emoji/nimble-emoji'
|
||||
|
||||
export default class NotFound extends React.PureComponent {
|
||||
render() {
|
||||
const { data, emojiProps, i18n, notFound, notFoundEmoji } = this.props
|
||||
|
||||
const component = (notFound && notFound()) || (
|
||||
<div className="emoji-mart-no-results">
|
||||
{NimbleEmoji({
|
||||
data: data,
|
||||
...emojiProps,
|
||||
size: 38,
|
||||
emoji: notFoundEmoji,
|
||||
onOver: null,
|
||||
onLeave: null,
|
||||
onClick: null,
|
||||
})}
|
||||
<div className="emoji-mart-no-results-label">{i18n.notfound}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
return component
|
||||
}
|
||||
}
|
||||
|
||||
NotFound.propTypes /* remove-proptypes */ = {
|
||||
notFound: PropTypes.func.isRequired,
|
||||
emojiProps: PropTypes.object.isRequired,
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
import React from 'react'
|
||||
import NimblePicker from '../nimble-picker'
|
||||
import NimbleEmojiIndex from '../../../utils/emoji-index/nimble-emoji-index'
|
||||
import renderer from 'react-test-renderer'
|
||||
|
||||
import data from '../../../../data/apple'
|
||||
|
||||
function render(props = {}) {
|
||||
const defaultProps = { data }
|
||||
const component = renderer.create(
|
||||
<NimblePicker {...props} {...defaultProps} />,
|
||||
)
|
||||
return component.getInstance()
|
||||
}
|
||||
|
||||
test('shows 10 categories by default', () => {
|
||||
const subject = render()
|
||||
expect(subject.categories.length).toEqual(10)
|
||||
})
|
||||
|
||||
test('will not show some categories based upon our filter', () => {
|
||||
const subject = render({ emojisToShowFilter: () => false })
|
||||
expect(subject.categories.length).toEqual(2)
|
||||
})
|
||||
|
||||
test('maintains category ids after it is filtered', () => {
|
||||
const subject = render({ emojisToShowFilter: () => true })
|
||||
const categoriesWithIds = subject.categories.filter((category) => category.id)
|
||||
expect(categoriesWithIds.length).toEqual(10)
|
||||
})
|
||||
|
||||
test('with custom emoji and tooltip', () => {
|
||||
const custom = [
|
||||
{
|
||||
id: 'custom_name',
|
||||
name: 'custom_name',
|
||||
short_names: ['custom_name'],
|
||||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['custom_name'],
|
||||
imageUrl: 'https://example.com/emoji',
|
||||
custom: true,
|
||||
},
|
||||
{
|
||||
id: 'custom_name2',
|
||||
name: 'custom_name2',
|
||||
short_names: ['custom_name2'],
|
||||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['custom_name2'],
|
||||
imageUrl: 'https://example.com/emoji',
|
||||
custom: true,
|
||||
},
|
||||
]
|
||||
const subject = render({
|
||||
emojiTooltip: true,
|
||||
autoFocus: true,
|
||||
custom,
|
||||
})
|
||||
expect(subject.categories.length).toEqual(11)
|
||||
expect(subject.categories[10].name).toEqual('Custom')
|
||||
subject.handleSearch(
|
||||
new NimbleEmojiIndex(subject.data).search('custom_', { custom }),
|
||||
)
|
||||
})
|
||||
|
||||
test('with custom categories', () => {
|
||||
const custom = [
|
||||
{
|
||||
id: 'custom_name',
|
||||
name: 'custom_name',
|
||||
short_names: ['custom_name'],
|
||||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['custom_name'],
|
||||
imageUrl: 'https://example.com/emoji',
|
||||
custom: true,
|
||||
customCategory: 'Category 1',
|
||||
},
|
||||
{
|
||||
id: 'custom_name2',
|
||||
name: 'custom_name2',
|
||||
short_names: ['custom_name2'],
|
||||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['custom_name2'],
|
||||
imageUrl: 'https://example.com/emoji',
|
||||
custom: true,
|
||||
customCategory: 'Category 2',
|
||||
},
|
||||
]
|
||||
const subject = render({ custom })
|
||||
expect(subject.categories.length).toEqual(12)
|
||||
expect(subject.categories[10].name).toEqual('Category 1')
|
||||
expect(subject.categories[11].name).toEqual('Category 2')
|
||||
})
|
|
@ -1,18 +1,24 @@
|
|||
import '../vendor/raf-polyfill'
|
||||
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import data from '../data'
|
||||
|
||||
import store from '../utils/store'
|
||||
import frequently from '../utils/frequently'
|
||||
import { deepMerge, measureScrollbar } from '../utils'
|
||||
import * as icons from '../../svgs'
|
||||
import store from '../../utils/store'
|
||||
import frequently from '../../utils/frequently'
|
||||
import { deepMerge, measureScrollbar, getSanitizedData } from '../../utils'
|
||||
import { uncompress } from '../../utils/data'
|
||||
import { PickerPropTypes } from '../../utils/shared-props'
|
||||
|
||||
import { Anchors, Category, Emoji, Preview, Search } from '.'
|
||||
import Anchors from '../anchors'
|
||||
import Category from '../category'
|
||||
import Preview from '../preview'
|
||||
import Search from '../search'
|
||||
import { PickerDefaultProps } from '../../utils/shared-default-props'
|
||||
|
||||
const I18N = {
|
||||
search: 'Search',
|
||||
clear: 'Clear', // Accessible label on "clear" button
|
||||
notfound: 'No Emoji Found',
|
||||
skintext: 'Choose your default skin tone',
|
||||
categories: {
|
||||
search: 'Search Results',
|
||||
recent: 'Frequently Used',
|
||||
|
@ -26,14 +32,24 @@ const I18N = {
|
|||
flags: 'Flags',
|
||||
custom: 'Custom',
|
||||
},
|
||||
categorieslabel: 'Emoji categories', // Accessible title for the list of categories
|
||||
skintones: {
|
||||
1: 'Default Skin Tone',
|
||||
2: 'Light Skin Tone',
|
||||
3: 'Medium-Light Skin Tone',
|
||||
4: 'Medium Skin Tone',
|
||||
5: 'Medium-Dark Skin Tone',
|
||||
6: 'Dark Skin Tone',
|
||||
},
|
||||
}
|
||||
|
||||
export default class Picker extends React.PureComponent {
|
||||
export default class NimblePicker extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.CUSTOM = []
|
||||
|
||||
this.RECENT_CATEGORY = { id: 'recent', name: 'Recent', emojis: null }
|
||||
this.CUSTOM_CATEGORY = { id: 'custom', name: 'Custom', emojis: [] }
|
||||
this.SEARCH_CATEGORY = {
|
||||
id: 'search',
|
||||
name: 'Search',
|
||||
|
@ -41,26 +57,52 @@ export default class Picker extends React.PureComponent {
|
|||
anchor: false,
|
||||
}
|
||||
|
||||
this.i18n = deepMerge(I18N, props.i18n)
|
||||
this.state = {
|
||||
skin: props.skin || store.get('skin') || props.defaultSkin,
|
||||
firstRender: true,
|
||||
if (props.data.compressed) {
|
||||
uncompress(props.data)
|
||||
}
|
||||
|
||||
this.data = props.data
|
||||
this.i18n = deepMerge(I18N, props.i18n)
|
||||
this.icons = deepMerge(icons, props.icons)
|
||||
this.state = { firstRender: true }
|
||||
|
||||
this.categories = []
|
||||
let allCategories = [].concat(data.categories)
|
||||
let allCategories = [].concat(this.data.categories)
|
||||
|
||||
if (props.custom.length > 0) {
|
||||
this.CUSTOM_CATEGORY.emojis = props.custom.map((emoji) => {
|
||||
return {
|
||||
const customCategories = {}
|
||||
let customCategoriesCreated = 0
|
||||
|
||||
props.custom.forEach((emoji) => {
|
||||
if (!customCategories[emoji.customCategory]) {
|
||||
customCategories[emoji.customCategory] = {
|
||||
id: emoji.customCategory
|
||||
? `custom-${emoji.customCategory}`
|
||||
: 'custom',
|
||||
name: emoji.customCategory || 'Custom',
|
||||
emojis: [],
|
||||
anchor: customCategoriesCreated === 0,
|
||||
}
|
||||
|
||||
customCategoriesCreated++
|
||||
}
|
||||
|
||||
const category = customCategories[emoji.customCategory]
|
||||
|
||||
const customEmoji = {
|
||||
...emoji,
|
||||
// `<Category />` expects emoji to have an `id`.
|
||||
id: emoji.short_names[0],
|
||||
custom: true,
|
||||
}
|
||||
|
||||
category.emojis.push(customEmoji)
|
||||
this.CUSTOM.push(customEmoji)
|
||||
})
|
||||
|
||||
allCategories.push(this.CUSTOM_CATEGORY)
|
||||
allCategories = allCategories.concat(
|
||||
Object.keys(customCategories).map((key) => customCategories[key]),
|
||||
)
|
||||
}
|
||||
|
||||
this.hideRecent = true
|
||||
|
@ -99,7 +141,7 @@ export default class Picker extends React.PureComponent {
|
|||
const { emojis } = category
|
||||
for (let emojiIndex = 0; emojiIndex < emojis.length; emojiIndex++) {
|
||||
const emoji = emojis[emojiIndex]
|
||||
if (props.emojisToShowFilter(data.emojis[emoji] || emoji)) {
|
||||
if (props.emojisToShowFilter(this.data.emojis[emoji] || emoji)) {
|
||||
newEmojis.push(emoji)
|
||||
}
|
||||
}
|
||||
|
@ -151,14 +193,7 @@ export default class Picker extends React.PureComponent {
|
|||
this.setPreviewRef = this.setPreviewRef.bind(this)
|
||||
this.handleSkinChange = this.handleSkinChange.bind(this)
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this)
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
if (props.skin) {
|
||||
this.setState({ skin: props.skin })
|
||||
} else if (props.defaultSkin && !store.get('skin')) {
|
||||
this.setState({ skin: props.defaultSkin })
|
||||
}
|
||||
this.handleDarkMatchMediaChange = this.handleDarkMatchMediaChange.bind(this)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -180,6 +215,10 @@ export default class Picker extends React.PureComponent {
|
|||
|
||||
clearTimeout(this.leaveTimeout)
|
||||
clearTimeout(this.firstRenderTimeout)
|
||||
|
||||
if (this.darkMatchMedia) {
|
||||
this.darkMatchMedia.removeListener(this.handleDarkMatchMediaChange)
|
||||
}
|
||||
}
|
||||
|
||||
testStickyPosition() {
|
||||
|
@ -194,6 +233,24 @@ export default class Picker extends React.PureComponent {
|
|||
this.hasStickyPosition = !!stickyTestElement.style.position.length
|
||||
}
|
||||
|
||||
getPreferredTheme() {
|
||||
if (this.props.theme != 'auto') return this.props.theme
|
||||
if (this.state.theme) return this.state.theme
|
||||
if (typeof matchMedia !== 'function') return PickerDefaultProps.theme
|
||||
|
||||
if (!this.darkMatchMedia) {
|
||||
this.darkMatchMedia = matchMedia('(prefers-color-scheme: dark)')
|
||||
this.darkMatchMedia.addListener(this.handleDarkMatchMediaChange)
|
||||
}
|
||||
|
||||
if (this.darkMatchMedia.media.match(/^not/)) return PickerDefaultProps.theme
|
||||
return this.darkMatchMedia.matches ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
handleDarkMatchMediaChange() {
|
||||
this.setState({ theme: this.darkMatchMedia.matches ? 'dark' : 'light' })
|
||||
}
|
||||
|
||||
handleEmojiOver(emoji) {
|
||||
var { preview } = this
|
||||
if (!preview) {
|
||||
|
@ -201,7 +258,7 @@ export default class Picker extends React.PureComponent {
|
|||
}
|
||||
|
||||
// Use Array.prototype.find() when it is more widely supported.
|
||||
const emojiData = this.CUSTOM_CATEGORY.emojis.filter(
|
||||
const emojiData = this.CUSTOM.filter(
|
||||
(customEmoji) => customEmoji.id === emoji.id,
|
||||
)[0]
|
||||
for (let key in emojiData) {
|
||||
|
@ -237,9 +294,11 @@ export default class Picker extends React.PureComponent {
|
|||
var component = this.categoryRefs['category-1']
|
||||
if (component) {
|
||||
let maxMargin = component.maxMargin
|
||||
component.forceUpdate()
|
||||
if (this.props.enableFrequentEmojiSort) {
|
||||
component.forceUpdate()
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
if (!this.scroll) return
|
||||
component.memoizeSize()
|
||||
if (maxMargin == component.maxMargin) return
|
||||
|
@ -257,7 +316,7 @@ export default class Picker extends React.PureComponent {
|
|||
handleScroll() {
|
||||
if (!this.waitingForPaint) {
|
||||
this.waitingForPaint = true
|
||||
window.requestAnimationFrame(this.handleScrollPaint)
|
||||
requestAnimationFrame(this.handleScrollPaint)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,7 +391,9 @@ export default class Picker extends React.PureComponent {
|
|||
}
|
||||
|
||||
this.forceUpdate()
|
||||
this.scroll.scrollTop = 0
|
||||
if (this.scroll) {
|
||||
this.scroll.scrollTop = 0
|
||||
}
|
||||
this.handleScroll()
|
||||
}
|
||||
|
||||
|
@ -359,7 +420,7 @@ export default class Picker extends React.PureComponent {
|
|||
this.handleSearch(null)
|
||||
this.search.clear()
|
||||
|
||||
window.requestAnimationFrame(scrollToComponent)
|
||||
requestAnimationFrame(scrollToComponent)
|
||||
} else {
|
||||
scrollToComponent()
|
||||
}
|
||||
|
@ -384,12 +445,18 @@ export default class Picker extends React.PureComponent {
|
|||
|
||||
if (
|
||||
this.SEARCH_CATEGORY.emojis &&
|
||||
(emoji = this.SEARCH_CATEGORY.emojis[0])
|
||||
this.SEARCH_CATEGORY.emojis.length &&
|
||||
(emoji = getSanitizedData(
|
||||
this.SEARCH_CATEGORY.emojis[0],
|
||||
this.state.skin,
|
||||
this.props.set,
|
||||
this.props.data,
|
||||
))
|
||||
) {
|
||||
this.handleEmojiSelect(emoji)
|
||||
handled = true
|
||||
}
|
||||
|
||||
handled = true
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -443,53 +510,71 @@ export default class Picker extends React.PureComponent {
|
|||
|
||||
render() {
|
||||
var {
|
||||
perLine,
|
||||
emojiSize,
|
||||
set,
|
||||
sheetSize,
|
||||
style,
|
||||
title,
|
||||
emoji,
|
||||
color,
|
||||
native,
|
||||
backgroundImageFn,
|
||||
emojisToShowFilter,
|
||||
showPreview,
|
||||
showSkinTones,
|
||||
emojiTooltip,
|
||||
include,
|
||||
exclude,
|
||||
recent,
|
||||
autoFocus,
|
||||
} = this.props,
|
||||
{ skin } = this.state,
|
||||
width = perLine * (emojiSize + 12) + 12 + 2 + measureScrollbar()
|
||||
perLine,
|
||||
emojiSize,
|
||||
set,
|
||||
sheetSize,
|
||||
sheetColumns,
|
||||
sheetRows,
|
||||
style,
|
||||
title,
|
||||
emoji,
|
||||
color,
|
||||
native,
|
||||
backgroundImageFn,
|
||||
emojisToShowFilter,
|
||||
showPreview,
|
||||
showSkinTones,
|
||||
emojiTooltip,
|
||||
useButton,
|
||||
include,
|
||||
exclude,
|
||||
recent,
|
||||
autoFocus,
|
||||
skinEmoji,
|
||||
notFound,
|
||||
notFoundEmoji,
|
||||
maxResults,
|
||||
} = this.props
|
||||
|
||||
var width = perLine * (emojiSize + 12) + 12 + 2 + measureScrollbar()
|
||||
var theme = this.getPreferredTheme()
|
||||
var skin =
|
||||
this.props.skin ||
|
||||
this.state.skin ||
|
||||
store.get('skin') ||
|
||||
this.props.defaultSkin
|
||||
|
||||
return (
|
||||
<div
|
||||
<section
|
||||
style={{ width: width, ...style }}
|
||||
className="emoji-mart"
|
||||
className={`emoji-mart emoji-mart-${theme}`}
|
||||
aria-label={title}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
>
|
||||
<div className="emoji-mart-bar">
|
||||
<Anchors
|
||||
ref={this.setAnchorsRef}
|
||||
data={this.data}
|
||||
i18n={this.i18n}
|
||||
color={color}
|
||||
categories={this.categories}
|
||||
onAnchorClick={this.handleAnchorClick}
|
||||
icons={this.icons}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Search
|
||||
ref={this.setSearchRef}
|
||||
onSearch={this.handleSearch}
|
||||
data={this.data}
|
||||
i18n={this.i18n}
|
||||
emojisToShowFilter={emojisToShowFilter}
|
||||
include={include}
|
||||
exclude={exclude}
|
||||
custom={this.CUSTOM_CATEGORY.emojis}
|
||||
custom={this.CUSTOM}
|
||||
autoFocus={autoFocus}
|
||||
maxResults={maxResults}
|
||||
/>
|
||||
|
||||
<div
|
||||
|
@ -508,13 +593,14 @@ export default class Picker extends React.PureComponent {
|
|||
perLine={perLine}
|
||||
native={native}
|
||||
hasStickyPosition={this.hasStickyPosition}
|
||||
data={this.data}
|
||||
i18n={this.i18n}
|
||||
recent={
|
||||
category.id == this.RECENT_CATEGORY.id ? recent : undefined
|
||||
}
|
||||
custom={
|
||||
category.id == this.RECENT_CATEGORY.id
|
||||
? this.CUSTOM_CATEGORY.emojis
|
||||
? this.CUSTOM
|
||||
: undefined
|
||||
}
|
||||
emojiProps={{
|
||||
|
@ -523,101 +609,58 @@ export default class Picker extends React.PureComponent {
|
|||
size: emojiSize,
|
||||
set: set,
|
||||
sheetSize: sheetSize,
|
||||
sheetColumns: sheetColumns,
|
||||
sheetRows: sheetRows,
|
||||
forceSize: native,
|
||||
tooltip: emojiTooltip,
|
||||
backgroundImageFn: backgroundImageFn,
|
||||
useButton: useButton,
|
||||
onOver: this.handleEmojiOver,
|
||||
onLeave: this.handleEmojiLeave,
|
||||
onClick: this.handleEmojiClick,
|
||||
}}
|
||||
notFound={notFound}
|
||||
notFoundEmoji={notFoundEmoji}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{showPreview && (
|
||||
{(showPreview || showSkinTones) && (
|
||||
<div className="emoji-mart-bar">
|
||||
<Preview
|
||||
ref={this.setPreviewRef}
|
||||
data={this.data}
|
||||
title={title}
|
||||
emoji={emoji}
|
||||
showSkinTones={showSkinTones}
|
||||
showPreview={showPreview}
|
||||
emojiProps={{
|
||||
native: native,
|
||||
size: 38,
|
||||
skin: skin,
|
||||
set: set,
|
||||
sheetSize: sheetSize,
|
||||
sheetColumns: sheetColumns,
|
||||
sheetRows: sheetRows,
|
||||
backgroundImageFn: backgroundImageFn,
|
||||
}}
|
||||
skinsProps={{
|
||||
skin: skin,
|
||||
onChange: this.handleSkinChange,
|
||||
skinEmoji: skinEmoji,
|
||||
}}
|
||||
i18n={this.i18n}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Picker.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
onSelect: PropTypes.func,
|
||||
onSkinChange: PropTypes.func,
|
||||
perLine: PropTypes.number,
|
||||
emojiSize: PropTypes.number,
|
||||
i18n: PropTypes.object,
|
||||
style: PropTypes.object,
|
||||
title: PropTypes.string,
|
||||
emoji: PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
set: Emoji.propTypes.set,
|
||||
skin: Emoji.propTypes.skin,
|
||||
native: PropTypes.bool,
|
||||
backgroundImageFn: Emoji.propTypes.backgroundImageFn,
|
||||
sheetSize: Emoji.propTypes.sheetSize,
|
||||
emojisToShowFilter: PropTypes.func,
|
||||
showPreview: PropTypes.bool,
|
||||
showSkinTones: PropTypes.bool,
|
||||
emojiTooltip: Emoji.propTypes.tooltip,
|
||||
include: PropTypes.arrayOf(PropTypes.string),
|
||||
exclude: PropTypes.arrayOf(PropTypes.string),
|
||||
recent: PropTypes.arrayOf(PropTypes.string),
|
||||
autoFocus: PropTypes.bool,
|
||||
custom: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
short_names: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
emoticons: PropTypes.arrayOf(PropTypes.string),
|
||||
keywords: PropTypes.arrayOf(PropTypes.string),
|
||||
imageUrl: PropTypes.string.isRequired,
|
||||
}),
|
||||
),
|
||||
}
|
||||
|
||||
Picker.defaultProps = {
|
||||
onClick: () => {},
|
||||
onSelect: () => {},
|
||||
onSkinChange: () => {},
|
||||
emojiSize: 24,
|
||||
perLine: 9,
|
||||
i18n: {},
|
||||
style: {},
|
||||
title: 'Emoji Mart™',
|
||||
emoji: 'department_store',
|
||||
color: '#ae65c5',
|
||||
set: Emoji.defaultProps.set,
|
||||
skin: null,
|
||||
defaultSkin: Emoji.defaultProps.skin,
|
||||
native: Emoji.defaultProps.native,
|
||||
sheetSize: Emoji.defaultProps.sheetSize,
|
||||
backgroundImageFn: Emoji.defaultProps.backgroundImageFn,
|
||||
emojisToShowFilter: null,
|
||||
showPreview: true,
|
||||
showSkinTones: true,
|
||||
emojiTooltip: Emoji.defaultProps.tooltip,
|
||||
autoFocus: false,
|
||||
custom: [],
|
||||
NimblePicker.propTypes /* remove-proptypes */ = {
|
||||
...PickerPropTypes,
|
||||
data: PropTypes.object.isRequired,
|
||||
}
|
||||
NimblePicker.defaultProps = { ...PickerDefaultProps }
|
|
@ -0,0 +1,16 @@
|
|||
import React from 'react'
|
||||
|
||||
import data from '../../../data/all.json'
|
||||
import NimblePicker from './nimble-picker'
|
||||
|
||||
import { PickerPropTypes } from '../../utils/shared-props'
|
||||
import { PickerDefaultProps } from '../../utils/shared-default-props'
|
||||
|
||||
export default class Picker extends React.PureComponent {
|
||||
render() {
|
||||
return <NimblePicker {...this.props} {...this.state} />
|
||||
}
|
||||
}
|
||||
|
||||
Picker.propTypes /* remove-proptypes */ = PickerPropTypes
|
||||
Picker.defaultProps = { ...PickerDefaultProps, data }
|
|
@ -1,12 +1,16 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Emoji, Skins } from '.'
|
||||
import { getData } from '../utils'
|
||||
import NimbleEmoji from './emoji/nimble-emoji'
|
||||
import SkinsEmoji from './skins-emoji'
|
||||
import SkinsDot from './skins-dot'
|
||||
|
||||
export default class Preview extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.data = props.data
|
||||
this.state = { emoji: null }
|
||||
}
|
||||
|
||||
|
@ -18,10 +22,12 @@ export default class Preview extends React.PureComponent {
|
|||
showSkinTones,
|
||||
title,
|
||||
emoji: idleEmoji,
|
||||
i18n,
|
||||
showPreview,
|
||||
} = this.props
|
||||
|
||||
if (emoji) {
|
||||
var emojiData = getData(emoji),
|
||||
if (emoji && showPreview) {
|
||||
var emojiData = getData(emoji, null, null, this.data),
|
||||
{ emoticons = [] } = emojiData,
|
||||
knownEmoticons = [],
|
||||
listedEmoticons = []
|
||||
|
@ -37,11 +43,16 @@ export default class Preview extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<div className="emoji-mart-preview">
|
||||
<div className="emoji-mart-preview-emoji">
|
||||
{Emoji({ key: emoji.id, emoji: emoji, ...emojiProps })}
|
||||
<div className="emoji-mart-preview-emoji" aria-hidden="true">
|
||||
{NimbleEmoji({
|
||||
key: emoji.id,
|
||||
emoji: emoji,
|
||||
data: this.data,
|
||||
...emojiProps,
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="emoji-mart-preview-data">
|
||||
<div className="emoji-mart-preview-data" aria-hidden="true">
|
||||
<div className="emoji-mart-preview-name">{emoji.name}</div>
|
||||
<div className="emoji-mart-preview-shortnames">
|
||||
{emojiData.short_names.map((short_name) => (
|
||||
|
@ -63,19 +74,38 @@ export default class Preview extends React.PureComponent {
|
|||
} else {
|
||||
return (
|
||||
<div className="emoji-mart-preview">
|
||||
<div className="emoji-mart-preview-emoji">
|
||||
<div className="emoji-mart-preview-emoji" aria-hidden="true">
|
||||
{idleEmoji &&
|
||||
idleEmoji.length &&
|
||||
Emoji({ emoji: idleEmoji, ...emojiProps })}
|
||||
NimbleEmoji({ emoji: idleEmoji, data: this.data, ...emojiProps })}
|
||||
</div>
|
||||
|
||||
<div className="emoji-mart-preview-data">
|
||||
<div className="emoji-mart-preview-data" aria-hidden="true">
|
||||
<span className="emoji-mart-title-label">{title}</span>
|
||||
</div>
|
||||
|
||||
{showSkinTones && (
|
||||
<div className="emoji-mart-preview-skins">
|
||||
<Skins {...skinsProps} />
|
||||
<div
|
||||
className={`emoji-mart-preview-skins${
|
||||
skinsProps.skinEmoji ? ' custom' : ''
|
||||
}`}
|
||||
>
|
||||
{skinsProps.skinEmoji ? (
|
||||
<SkinsEmoji
|
||||
skin={skinsProps.skin}
|
||||
emojiProps={emojiProps}
|
||||
data={this.data}
|
||||
skinEmoji={skinsProps.skinEmoji}
|
||||
i18n={i18n}
|
||||
onChange={skinsProps.onChange}
|
||||
/>
|
||||
) : (
|
||||
<SkinsDot
|
||||
skin={skinsProps.skin}
|
||||
i18n={i18n}
|
||||
onChange={skinsProps.onChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -84,7 +114,7 @@ export default class Preview extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
Preview.propTypes = {
|
||||
Preview.propTypes /* remove-proptypes */ = {
|
||||
showSkinTones: PropTypes.bool,
|
||||
title: PropTypes.string.isRequired,
|
||||
emoji: PropTypes.string.isRequired,
|
||||
|
|
|
@ -1,20 +1,53 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import emojiIndex from '../utils/emoji-index'
|
||||
|
||||
import { search as icons } from '../svgs'
|
||||
import NimbleEmojiIndex from '../utils/emoji-index/nimble-emoji-index'
|
||||
import { throttleIdleTask } from '../utils/index'
|
||||
|
||||
let id = 0
|
||||
|
||||
export default class Search extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
icon: icons.search,
|
||||
isSearching: false,
|
||||
id: ++id,
|
||||
}
|
||||
|
||||
this.data = props.data
|
||||
this.emojiIndex = new NimbleEmojiIndex(this.data)
|
||||
this.setRef = this.setRef.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.clear = this.clear.bind(this)
|
||||
this.handleKeyUp = this.handleKeyUp.bind(this)
|
||||
|
||||
// throttle keyboard input so that typing isn't delayed
|
||||
this.handleChange = throttleIdleTask(this.handleChange.bind(this))
|
||||
}
|
||||
|
||||
handleChange() {
|
||||
var value = this.input.value
|
||||
componentDidMount() {
|
||||
// in some cases (e.g. preact) the input may already be pre-populated
|
||||
// this.input is undefined in Jest tests
|
||||
if (this.input && this.input.value) {
|
||||
this.search(this.input.value)
|
||||
}
|
||||
}
|
||||
|
||||
search(value) {
|
||||
if (value == '')
|
||||
this.setState({
|
||||
icon: icons.search,
|
||||
isSearching: false,
|
||||
})
|
||||
else
|
||||
this.setState({
|
||||
icon: icons.delete,
|
||||
isSearching: true,
|
||||
})
|
||||
|
||||
this.props.onSearch(
|
||||
emojiIndex.search(value, {
|
||||
this.emojiIndex.search(value, {
|
||||
emojisToShowFilter: this.props.emojisToShowFilter,
|
||||
maxResults: this.props.maxResults,
|
||||
include: this.props.include,
|
||||
|
@ -24,32 +57,66 @@ export default class Search extends React.PureComponent {
|
|||
)
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (this.input.value == '') return
|
||||
this.input.value = ''
|
||||
this.input.focus()
|
||||
this.search('')
|
||||
}
|
||||
|
||||
handleChange() {
|
||||
if (this.input) {
|
||||
this.search(this.input.value)
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyUp(e) {
|
||||
if (e.keyCode === 13) {
|
||||
this.clear()
|
||||
}
|
||||
}
|
||||
|
||||
setRef(c) {
|
||||
this.input = c
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.input.value = ''
|
||||
}
|
||||
|
||||
render() {
|
||||
var { i18n, autoFocus } = this.props
|
||||
const { i18n, autoFocus } = this.props
|
||||
const { icon, isSearching, id } = this.state
|
||||
const inputId = `emoji-mart-search-${id}`
|
||||
|
||||
return (
|
||||
<div className="emoji-mart-search">
|
||||
<section className="emoji-mart-search" aria-label={i18n.search}>
|
||||
<input
|
||||
id={inputId}
|
||||
ref={this.setRef}
|
||||
type="text"
|
||||
type="search"
|
||||
onChange={this.handleChange}
|
||||
placeholder={i18n.search}
|
||||
autoFocus={autoFocus}
|
||||
/>
|
||||
</div>
|
||||
{/*
|
||||
* Use a <label> in addition to the placeholder for accessibility, but place it off-screen
|
||||
* http://www.maxability.co.in/2016/01/placeholder-attribute-and-why-it-is-not-accessible/
|
||||
*/}
|
||||
<label className="emoji-mart-sr-only" htmlFor={inputId}>
|
||||
{i18n.search}
|
||||
</label>
|
||||
<button
|
||||
className="emoji-mart-search-icon"
|
||||
onClick={this.clear}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
aria-label={i18n.clear}
|
||||
disabled={!isSearching}
|
||||
>
|
||||
{icon()}
|
||||
</button>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Search.propTypes = {
|
||||
Search.propTypes /* remove-proptypes */ = {
|
||||
onSearch: PropTypes.func,
|
||||
maxResults: PropTypes.number,
|
||||
emojisToShowFilter: PropTypes.func,
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Skins from './skins'
|
||||
|
||||
export default class SkinsDot extends Skins {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this)
|
||||
}
|
||||
|
||||
handleKeyDown(event) {
|
||||
// if either enter or space is pressed, then execute
|
||||
if (event.keyCode === 13 || event.keyCode === 32) {
|
||||
event.preventDefault()
|
||||
this.handleClick(event)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { skin, i18n } = this.props
|
||||
const { opened } = this.state
|
||||
const skinToneNodes = []
|
||||
|
||||
for (let skinTone = 1; skinTone <= 6; skinTone++) {
|
||||
const selected = skinTone === skin
|
||||
const visible = opened || selected
|
||||
skinToneNodes.push(
|
||||
<span
|
||||
key={`skin-tone-${skinTone}`}
|
||||
className={`emoji-mart-skin-swatch${selected ? ' selected' : ''}`}
|
||||
aria-label={i18n.skintones[skinTone]}
|
||||
aria-hidden={!visible}
|
||||
{...(opened ? { role: 'menuitem' } : {})}
|
||||
>
|
||||
<span
|
||||
onClick={this.handleClick}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
role="button"
|
||||
{...(selected
|
||||
? {
|
||||
'aria-haspopup': true,
|
||||
'aria-expanded': !!opened,
|
||||
}
|
||||
: {})}
|
||||
{...(opened ? { 'aria-pressed': !!selected } : {})}
|
||||
tabIndex={visible ? '0' : ''}
|
||||
aria-label={i18n.skintones[skinTone]}
|
||||
title={i18n.skintones[skinTone]}
|
||||
data-skin={skinTone}
|
||||
className={`emoji-mart-skin emoji-mart-skin-tone-${skinTone}`}
|
||||
/>
|
||||
</span>,
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`emoji-mart-skin-swatches${opened ? ' opened' : ''}`}
|
||||
aria-label={i18n.skintext}
|
||||
>
|
||||
<div {...(opened ? { role: 'menubar' } : {})}>{skinToneNodes}</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SkinsDot.propTypes /* remove-proptypes */ = {
|
||||
onChange: PropTypes.func,
|
||||
skin: PropTypes.number.isRequired,
|
||||
i18n: PropTypes.object,
|
||||
}
|
||||
|
||||
SkinsDot.defaultProps = {
|
||||
onChange: () => {},
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import NimbleEmoji from './emoji/nimble-emoji'
|
||||
import Skins from './skins'
|
||||
|
||||
export default class SkinsEmoji extends Skins {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { skin, emojiProps, data, skinEmoji, i18n } = this.props
|
||||
const { opened } = this.state
|
||||
const skinToneNodes = []
|
||||
|
||||
for (let skinTone = 1; skinTone <= 6; skinTone++) {
|
||||
const selected = skinTone === skin
|
||||
skinToneNodes.push(
|
||||
<span
|
||||
key={`skin-tone-${skinTone}`}
|
||||
className={`emoji-mart-skin-swatch custom${
|
||||
selected ? ' selected' : ''
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
onClick={this.handleClick}
|
||||
data-skin={skinTone}
|
||||
className={`emoji-mart-skin-tone-${skinTone}`}
|
||||
>
|
||||
{NimbleEmoji({
|
||||
emoji: skinEmoji,
|
||||
data: data,
|
||||
skin: skinTone,
|
||||
backgroundImageFn: emojiProps.backgroundImageFn,
|
||||
native: emojiProps.native,
|
||||
set: emojiProps.set,
|
||||
sheetSize: emojiProps.sheetSize,
|
||||
size: 23,
|
||||
})}
|
||||
</span>
|
||||
</span>,
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`emoji-mart-skin-swatches custom${opened ? ' opened' : ''}`}
|
||||
>
|
||||
<div className={`emoji-mart-skin-text${opened ? ' opened' : ''}`}>
|
||||
{i18n.skintext}
|
||||
</div>
|
||||
{skinToneNodes}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SkinsEmoji.propTypes /* remove-proptypes */ = {
|
||||
onChange: PropTypes.func,
|
||||
skin: PropTypes.number.isRequired,
|
||||
emojiProps: PropTypes.object.isRequired,
|
||||
skinTone: PropTypes.number,
|
||||
skinEmoji: PropTypes.string.isRequired,
|
||||
i18n: PropTypes.object,
|
||||
}
|
||||
|
||||
SkinsEmoji.defaultProps = {
|
||||
onChange: () => {},
|
||||
skinTone: null,
|
||||
}
|
|
@ -4,12 +4,9 @@ import PropTypes from 'prop-types'
|
|||
export default class Skins extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
opened: false,
|
||||
}
|
||||
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
}
|
||||
|
||||
handleClick(e) {
|
||||
|
@ -27,46 +24,11 @@ export default class Skins extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { skin } = this.props
|
||||
const { opened } = this.state
|
||||
|
||||
const skinToneNodes = []
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const skinTone = i + 1
|
||||
const selected = skinTone == skin
|
||||
|
||||
skinToneNodes.push(
|
||||
<span
|
||||
key={`skin-tone-${skinTone}`}
|
||||
className={`emoji-mart-skin-swatch ${
|
||||
selected ? 'emoji-mart-skin-swatch-selected' : ''
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
onClick={this.handleClick}
|
||||
data-skin={skinTone}
|
||||
className={`emoji-mart-skin emoji-mart-skin-tone-${skinTone}`}
|
||||
/>
|
||||
</span>,
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className={`emoji-mart-skin-swatches ${
|
||||
opened ? 'emoji-mart-skin-swatches-opened' : ''
|
||||
}`}
|
||||
>
|
||||
{skinToneNodes}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Skins.propTypes = {
|
||||
Skins.propTypes /* remove-proptypes */ = {
|
||||
onChange: PropTypes.func,
|
||||
skin: PropTypes.number.isRequired,
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import buildSearch from '../utils/build-search'
|
||||
import data from './data'
|
||||
|
||||
function uncompress(list) {
|
||||
for (var short_name in list) {
|
||||
var datum = list[short_name]
|
||||
|
||||
if (!datum.short_names) datum.short_names = []
|
||||
datum.short_names.unshift(short_name)
|
||||
|
||||
datum.sheet_x = datum.sheet[0]
|
||||
datum.sheet_y = datum.sheet[1]
|
||||
delete datum.sheet
|
||||
|
||||
if (!datum.text) datum.text = ''
|
||||
if (datum.added_in !== null && !datum.added_in) datum.added_in = '6.0'
|
||||
|
||||
datum.search = buildSearch({
|
||||
short_names: datum.short_names,
|
||||
name: datum.name,
|
||||
keywords: datum.keywords,
|
||||
emoticons: datum.emoticons,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
uncompress(data.emojis)
|
||||
uncompress(data.skins)
|
||||
|
||||
export default data
|
17
src/index.js
17
src/index.js
|
@ -1,6 +1,13 @@
|
|||
import emojiIndex from './utils/emoji-index'
|
||||
import store from './utils/store'
|
||||
import frequently from './utils/frequently'
|
||||
export { default as emojiIndex } from './utils/emoji-index/emoji-index'
|
||||
export {
|
||||
default as NimbleEmojiIndex,
|
||||
} from './utils/emoji-index/nimble-emoji-index'
|
||||
export { default as store } from './utils/store'
|
||||
export { default as frequently } from './utils/frequently'
|
||||
export { getEmojiDataFromNative } from './utils'
|
||||
|
||||
export { Picker, Emoji, Category } from './components'
|
||||
export { emojiIndex, store, frequently }
|
||||
export { default as Picker } from './components/picker/picker'
|
||||
export { default as NimblePicker } from './components/picker/nimble-picker'
|
||||
export { default as Emoji } from './components/emoji/emoji'
|
||||
export { default as NimbleEmoji } from './components/emoji/nimble-emoji'
|
||||
export { default as Category } from './components/category'
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
const _Object = Object
|
||||
|
||||
export default (function createClass() {
|
||||
function defineProperties(target, props) {
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var descriptor = props[i]
|
||||
descriptor.enumerable = descriptor.enumerable || false
|
||||
descriptor.configurable = true
|
||||
if ('value' in descriptor) descriptor.writable = true
|
||||
_Object.defineProperty(target, descriptor.key, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
return function(Constructor, protoProps, staticProps) {
|
||||
if (protoProps) defineProperties(Constructor.prototype, protoProps)
|
||||
if (staticProps) defineProperties(Constructor, staticProps)
|
||||
return Constructor
|
||||
}
|
||||
})()
|
|
@ -1,16 +0,0 @@
|
|||
const _Object = Object
|
||||
|
||||
export default _Object.assign ||
|
||||
function(target) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var source = arguments[i]
|
||||
|
||||
for (var key in source) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
||||
target[key] = source[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
const _Object = Object
|
||||
|
||||
export default function inherits(subClass, superClass) {
|
||||
if (typeof superClass !== 'function' && superClass !== null) {
|
||||
throw new TypeError(
|
||||
'Super expression must either be null or a function, not ' +
|
||||
typeof superClass,
|
||||
)
|
||||
}
|
||||
|
||||
subClass.prototype = _Object.create(superClass && superClass.prototype, {
|
||||
constructor: {
|
||||
value: subClass,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
},
|
||||
})
|
||||
if (superClass) {
|
||||
_Object.setPrototypeOf
|
||||
? _Object.setPrototypeOf(subClass, superClass)
|
||||
: (subClass.__proto__ = superClass)
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
const _Object = Object
|
||||
|
||||
export default _Object.getPrototypeOf ||
|
||||
function(O) {
|
||||
O = Object(O)
|
||||
|
||||
if (typeof O.constructor === 'function' && O instanceof O.constructor) {
|
||||
return O.constructor.prototype
|
||||
}
|
||||
|
||||
return O instanceof Object ? Object.prototype : null
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
export default function possibleConstructorReturn(self, call) {
|
||||
if (!self) {
|
||||
throw new ReferenceError(
|
||||
"this hasn't been initialised - super() hasn't been called",
|
||||
)
|
||||
}
|
||||
|
||||
return call && (typeof call === 'object' || typeof call === 'function')
|
||||
? call
|
||||
: self
|
||||
}
|
|
@ -30,7 +30,7 @@ export default _String.fromCodePoint ||
|
|||
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
||||
codePoint -= 0x10000
|
||||
highSurrogate = (codePoint >> 10) + 0xd800
|
||||
lowSurrogate = codePoint % 0x400 + 0xdc00
|
||||
lowSurrogate = (codePoint % 0x400) + 0xdc00
|
||||
codeUnits.push(highSurrogate, lowSurrogate)
|
||||
}
|
||||
if (index + 1 === length || codeUnits.length > MAX_SIZE) {
|
||||
|
|
|
@ -1,23 +1,166 @@
|
|||
const SVGs = {
|
||||
activity: `<path d="M12 0C5.373 0 0 5.372 0 12c0 6.627 5.373 12 12 12 6.628 0 12-5.373 12-12 0-6.628-5.372-12-12-12m9.949 11H17.05c.224-2.527 1.232-4.773 1.968-6.113A9.966 9.966 0 0 1 21.949 11M13 11V2.051a9.945 9.945 0 0 1 4.432 1.564c-.858 1.491-2.156 4.22-2.392 7.385H13zm-2 0H8.961c-.238-3.165-1.536-5.894-2.393-7.385A9.95 9.95 0 0 1 11 2.051V11zm0 2v8.949a9.937 9.937 0 0 1-4.432-1.564c.857-1.492 2.155-4.221 2.393-7.385H11zm4.04 0c.236 3.164 1.534 5.893 2.392 7.385A9.92 9.92 0 0 1 13 21.949V13h2.04zM4.982 4.887C5.718 6.227 6.726 8.473 6.951 11h-4.9a9.977 9.977 0 0 1 2.931-6.113M2.051 13h4.9c-.226 2.527-1.233 4.771-1.969 6.113A9.972 9.972 0 0 1 2.051 13m16.967 6.113c-.735-1.342-1.744-3.586-1.968-6.113h4.899a9.961 9.961 0 0 1-2.931 6.113"/>`,
|
||||
import React from 'react'
|
||||
|
||||
custom: `<g transform="translate(2.000000, 1.000000)"><rect id="Rectangle" x="8" y="0" width="3" height="21" rx="1.5"></rect><rect id="Rectangle" transform="translate(9.843, 10.549) rotate(60) translate(-9.843, -10.549) " x="8.343" y="0.049" width="3" height="21" rx="1.5"></rect><rect id="Rectangle" transform="translate(9.843, 10.549) rotate(-60) translate(-9.843, -10.549) " x="8.343" y="0.049" width="3" height="21" rx="1.5"></rect></g>`,
|
||||
const categories = {
|
||||
activity: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M12 0C5.373 0 0 5.372 0 12c0 6.627 5.373 12 12 12 6.628 0 12-5.373 12-12 0-6.628-5.372-12-12-12m9.949 11H17.05c.224-2.527 1.232-4.773 1.968-6.113A9.966 9.966 0 0 1 21.949 11M13 11V2.051a9.945 9.945 0 0 1 4.432 1.564c-.858 1.491-2.156 4.22-2.392 7.385H13zm-2 0H8.961c-.238-3.165-1.536-5.894-2.393-7.385A9.95 9.95 0 0 1 11 2.051V11zm0 2v8.949a9.937 9.937 0 0 1-4.432-1.564c.857-1.492 2.155-4.221 2.393-7.385H11zm4.04 0c.236 3.164 1.534 5.893 2.392 7.385A9.92 9.92 0 0 1 13 21.949V13h2.04zM4.982 4.887C5.718 6.227 6.726 8.473 6.951 11h-4.9a9.977 9.977 0 0 1 2.931-6.113M2.051 13h4.9c-.226 2.527-1.233 4.771-1.969 6.113A9.972 9.972 0 0 1 2.051 13m16.967 6.113c-.735-1.342-1.744-3.586-1.968-6.113h4.899a9.961 9.961 0 0 1-2.931 6.113" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
flags: `<path d="M0 0l6.084 24H8L1.916 0zM21 5h-4l-1-4H4l3 12h3l1 4h13L21 5zM6.563 3h7.875l2 8H8.563l-2-8zm8.832 10l-2.856 1.904L12.063 13h3.332zM19 13l-1.5-6h1.938l2 8H16l3-2z"/>`,
|
||||
custom: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<g transform="translate(2.000000, 1.000000)">
|
||||
<rect id="Rectangle" x="8" y="0" width="3" height="21" rx="1.5" />
|
||||
<rect
|
||||
id="Rectangle"
|
||||
transform="translate(9.843, 10.549) rotate(60) translate(-9.843, -10.549) "
|
||||
x="8.343"
|
||||
y="0.049"
|
||||
width="3"
|
||||
height="21"
|
||||
rx="1.5"
|
||||
/>
|
||||
<rect
|
||||
id="Rectangle"
|
||||
transform="translate(9.843, 10.549) rotate(-60) translate(-9.843, -10.549) "
|
||||
x="8.343"
|
||||
y="0.049"
|
||||
width="3"
|
||||
height="21"
|
||||
rx="1.5"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
),
|
||||
|
||||
foods: `<path d="M17 4.978c-1.838 0-2.876.396-3.68.934.513-1.172 1.768-2.934 4.68-2.934a1 1 0 0 0 0-2c-2.921 0-4.629 1.365-5.547 2.512-.064.078-.119.162-.18.244C11.73 1.838 10.798.023 9.207.023 8.579.022 7.85.306 7 .978 5.027 2.54 5.329 3.902 6.492 4.999 3.609 5.222 0 7.352 0 12.969c0 4.582 4.961 11.009 9 11.009 1.975 0 2.371-.486 3-1 .629.514 1.025 1 3 1 4.039 0 9-6.418 9-11 0-5.953-4.055-8-7-8M8.242 2.546c.641-.508.943-.523.965-.523.426.169.975 1.405 1.357 3.055-1.527-.629-2.741-1.352-2.98-1.846.059-.112.241-.356.658-.686M15 21.978c-1.08 0-1.21-.109-1.559-.402l-.176-.146c-.367-.302-.816-.452-1.266-.452s-.898.15-1.266.452l-.176.146c-.347.292-.477.402-1.557.402-2.813 0-7-5.389-7-9.009 0-5.823 4.488-5.991 5-5.991 1.939 0 2.484.471 3.387 1.251l.323.276a1.995 1.995 0 0 0 2.58 0l.323-.276c.902-.78 1.447-1.251 3.387-1.251.512 0 5 .168 5 6 0 3.617-4.187 9-7 9"/>`,
|
||||
flags: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M0 0l6.084 24H8L1.916 0zM21 5h-4l-1-4H4l3 12h3l1 4h13L21 5zM6.563 3h7.875l2 8H8.563l-2-8zm8.832 10l-2.856 1.904L12.063 13h3.332zM19 13l-1.5-6h1.938l2 8H16l3-2z" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
nature: `<path d="M15.5 8a1.5 1.5 0 1 0 .001 3.001A1.5 1.5 0 0 0 15.5 8M8.5 8a1.5 1.5 0 1 0 .001 3.001A1.5 1.5 0 0 0 8.5 8"/><path d="M18.933 0h-.027c-.97 0-2.138.787-3.018 1.497-1.274-.374-2.612-.51-3.887-.51-1.285 0-2.616.133-3.874.517C7.245.79 6.069 0 5.093 0h-.027C3.352 0 .07 2.67.002 7.026c-.039 2.479.276 4.238 1.04 5.013.254.258.882.677 1.295.882.191 3.177.922 5.238 2.536 6.38.897.637 2.187.949 3.2 1.102C8.04 20.6 8 20.795 8 21c0 1.773 2.35 3 4 3 1.648 0 4-1.227 4-3 0-.201-.038-.393-.072-.586 2.573-.385 5.435-1.877 5.925-7.587.396-.22.887-.568 1.104-.788.763-.774 1.079-2.534 1.04-5.013C23.929 2.67 20.646 0 18.933 0M3.223 9.135c-.237.281-.837 1.155-.884 1.238-.15-.41-.368-1.349-.337-3.291.051-3.281 2.478-4.972 3.091-5.031.256.015.731.27 1.265.646-1.11 1.171-2.275 2.915-2.352 5.125-.133.546-.398.858-.783 1.313M12 22c-.901 0-1.954-.693-2-1 0-.654.475-1.236 1-1.602V20a1 1 0 1 0 2 0v-.602c.524.365 1 .947 1 1.602-.046.307-1.099 1-2 1m3-3.48v.02a4.752 4.752 0 0 0-1.262-1.02c1.092-.516 2.239-1.334 2.239-2.217 0-1.842-1.781-2.195-3.977-2.195-2.196 0-3.978.354-3.978 2.195 0 .883 1.148 1.701 2.238 2.217A4.8 4.8 0 0 0 9 18.539v-.025c-1-.076-2.182-.281-2.973-.842-1.301-.92-1.838-3.045-1.853-6.478l.023-.041c.496-.826 1.49-1.45 1.804-3.102 0-2.047 1.357-3.631 2.362-4.522C9.37 3.178 10.555 3 11.948 3c1.447 0 2.685.192 3.733.57 1 .9 2.316 2.465 2.316 4.48.313 1.651 1.307 2.275 1.803 3.102.035.058.068.117.102.178-.059 5.967-1.949 7.01-4.902 7.19m6.628-8.202c-.037-.065-.074-.13-.113-.195a7.587 7.587 0 0 0-.739-.987c-.385-.455-.648-.768-.782-1.313-.076-2.209-1.241-3.954-2.353-5.124.531-.376 1.004-.63 1.261-.647.636.071 3.044 1.764 3.096 5.031.027 1.81-.347 3.218-.37 3.235"/>`,
|
||||
foods: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M17 4.978c-1.838 0-2.876.396-3.68.934.513-1.172 1.768-2.934 4.68-2.934a1 1 0 0 0 0-2c-2.921 0-4.629 1.365-5.547 2.512-.064.078-.119.162-.18.244C11.73 1.838 10.798.023 9.207.023 8.579.022 7.85.306 7 .978 5.027 2.54 5.329 3.902 6.492 4.999 3.609 5.222 0 7.352 0 12.969c0 4.582 4.961 11.009 9 11.009 1.975 0 2.371-.486 3-1 .629.514 1.025 1 3 1 4.039 0 9-6.418 9-11 0-5.953-4.055-8-7-8M8.242 2.546c.641-.508.943-.523.965-.523.426.169.975 1.405 1.357 3.055-1.527-.629-2.741-1.352-2.98-1.846.059-.112.241-.356.658-.686M15 21.978c-1.08 0-1.21-.109-1.559-.402l-.176-.146c-.367-.302-.816-.452-1.266-.452s-.898.15-1.266.452l-.176.146c-.347.292-.477.402-1.557.402-2.813 0-7-5.389-7-9.009 0-5.823 4.488-5.991 5-5.991 1.939 0 2.484.471 3.387 1.251l.323.276a1.995 1.995 0 0 0 2.58 0l.323-.276c.902-.78 1.447-1.251 3.387-1.251.512 0 5 .168 5 6 0 3.617-4.187 9-7 9" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
objects: `<path d="M12 0a9 9 0 0 0-5 16.482V21s2.035 3 5 3 5-3 5-3v-4.518A9 9 0 0 0 12 0zm0 2c3.86 0 7 3.141 7 7s-3.14 7-7 7-7-3.141-7-7 3.14-7 7-7zM9 17.477c.94.332 1.946.523 3 .523s2.06-.19 3-.523v.834c-.91.436-1.925.689-3 .689a6.924 6.924 0 0 1-3-.69v-.833zm.236 3.07A8.854 8.854 0 0 0 12 21c.965 0 1.888-.167 2.758-.451C14.155 21.173 13.153 22 12 22c-1.102 0-2.117-.789-2.764-1.453z"/><path d="M14.745 12.449h-.004c-.852-.024-1.188-.858-1.577-1.824-.421-1.061-.703-1.561-1.182-1.566h-.009c-.481 0-.783.497-1.235 1.537-.436.982-.801 1.811-1.636 1.791l-.276-.043c-.565-.171-.853-.691-1.284-1.794-.125-.313-.202-.632-.27-.913-.051-.213-.127-.53-.195-.634C7.067 9.004 7.039 9 6.99 9A1 1 0 0 1 7 7h.01c1.662.017 2.015 1.373 2.198 2.134.486-.981 1.304-2.058 2.797-2.075 1.531.018 2.28 1.153 2.731 2.141l.002-.008C14.944 8.424 15.327 7 16.979 7h.032A1 1 0 1 1 17 9h-.011c-.149.076-.256.474-.319.709a6.484 6.484 0 0 1-.311.951c-.429.973-.79 1.789-1.614 1.789"/>`,
|
||||
nature: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M15.5 8a1.5 1.5 0 1 0 .001 3.001A1.5 1.5 0 0 0 15.5 8M8.5 8a1.5 1.5 0 1 0 .001 3.001A1.5 1.5 0 0 0 8.5 8" />
|
||||
<path d="M18.933 0h-.027c-.97 0-2.138.787-3.018 1.497-1.274-.374-2.612-.51-3.887-.51-1.285 0-2.616.133-3.874.517C7.245.79 6.069 0 5.093 0h-.027C3.352 0 .07 2.67.002 7.026c-.039 2.479.276 4.238 1.04 5.013.254.258.882.677 1.295.882.191 3.177.922 5.238 2.536 6.38.897.637 2.187.949 3.2 1.102C8.04 20.6 8 20.795 8 21c0 1.773 2.35 3 4 3 1.648 0 4-1.227 4-3 0-.201-.038-.393-.072-.586 2.573-.385 5.435-1.877 5.925-7.587.396-.22.887-.568 1.104-.788.763-.774 1.079-2.534 1.04-5.013C23.929 2.67 20.646 0 18.933 0M3.223 9.135c-.237.281-.837 1.155-.884 1.238-.15-.41-.368-1.349-.337-3.291.051-3.281 2.478-4.972 3.091-5.031.256.015.731.27 1.265.646-1.11 1.171-2.275 2.915-2.352 5.125-.133.546-.398.858-.783 1.313M12 22c-.901 0-1.954-.693-2-1 0-.654.475-1.236 1-1.602V20a1 1 0 1 0 2 0v-.602c.524.365 1 .947 1 1.602-.046.307-1.099 1-2 1m3-3.48v.02a4.752 4.752 0 0 0-1.262-1.02c1.092-.516 2.239-1.334 2.239-2.217 0-1.842-1.781-2.195-3.977-2.195-2.196 0-3.978.354-3.978 2.195 0 .883 1.148 1.701 2.238 2.217A4.8 4.8 0 0 0 9 18.539v-.025c-1-.076-2.182-.281-2.973-.842-1.301-.92-1.838-3.045-1.853-6.478l.023-.041c.496-.826 1.49-1.45 1.804-3.102 0-2.047 1.357-3.631 2.362-4.522C9.37 3.178 10.555 3 11.948 3c1.447 0 2.685.192 3.733.57 1 .9 2.316 2.465 2.316 4.48.313 1.651 1.307 2.275 1.803 3.102.035.058.068.117.102.178-.059 5.967-1.949 7.01-4.902 7.19m6.628-8.202c-.037-.065-.074-.13-.113-.195a7.587 7.587 0 0 0-.739-.987c-.385-.455-.648-.768-.782-1.313-.076-2.209-1.241-3.954-2.353-5.124.531-.376 1.004-.63 1.261-.647.636.071 3.044 1.764 3.096 5.031.027 1.81-.347 3.218-.37 3.235" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
people: `<path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0m0 22C6.486 22 2 17.514 2 12S6.486 2 12 2s10 4.486 10 10-4.486 10-10 10"/><path d="M8 7a2 2 0 1 0-.001 3.999A2 2 0 0 0 8 7M16 7a2 2 0 1 0-.001 3.999A2 2 0 0 0 16 7M15.232 15c-.693 1.195-1.87 2-3.349 2-1.477 0-2.655-.805-3.347-2H15m3-2H6a6 6 0 1 0 12 0"/>`,
|
||||
objects: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M12 0a9 9 0 0 0-5 16.482V21s2.035 3 5 3 5-3 5-3v-4.518A9 9 0 0 0 12 0zm0 2c3.86 0 7 3.141 7 7s-3.14 7-7 7-7-3.141-7-7 3.14-7 7-7zM9 17.477c.94.332 1.946.523 3 .523s2.06-.19 3-.523v.834c-.91.436-1.925.689-3 .689a6.924 6.924 0 0 1-3-.69v-.833zm.236 3.07A8.854 8.854 0 0 0 12 21c.965 0 1.888-.167 2.758-.451C14.155 21.173 13.153 22 12 22c-1.102 0-2.117-.789-2.764-1.453z" />
|
||||
<path d="M14.745 12.449h-.004c-.852-.024-1.188-.858-1.577-1.824-.421-1.061-.703-1.561-1.182-1.566h-.009c-.481 0-.783.497-1.235 1.537-.436.982-.801 1.811-1.636 1.791l-.276-.043c-.565-.171-.853-.691-1.284-1.794-.125-.313-.202-.632-.27-.913-.051-.213-.127-.53-.195-.634C7.067 9.004 7.039 9 6.99 9A1 1 0 0 1 7 7h.01c1.662.017 2.015 1.373 2.198 2.134.486-.981 1.304-2.058 2.797-2.075 1.531.018 2.28 1.153 2.731 2.141l.002-.008C14.944 8.424 15.327 7 16.979 7h.032A1 1 0 1 1 17 9h-.011c-.149.076-.256.474-.319.709a6.484 6.484 0 0 1-.311.951c-.429.973-.79 1.789-1.614 1.789" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
places: `<path d="M6.5 12C5.122 12 4 13.121 4 14.5S5.122 17 6.5 17 9 15.879 9 14.5 7.878 12 6.5 12m0 3c-.275 0-.5-.225-.5-.5s.225-.5.5-.5.5.225.5.5-.225.5-.5.5M17.5 12c-1.378 0-2.5 1.121-2.5 2.5s1.122 2.5 2.5 2.5 2.5-1.121 2.5-2.5-1.122-2.5-2.5-2.5m0 3c-.275 0-.5-.225-.5-.5s.225-.5.5-.5.5.225.5.5-.225.5-.5.5"/><path d="M22.482 9.494l-1.039-.346L21.4 9h.6c.552 0 1-.439 1-.992 0-.006-.003-.008-.003-.008H23c0-1-.889-2-1.984-2h-.642l-.731-1.717C19.262 3.012 18.091 2 16.764 2H7.236C5.909 2 4.738 3.012 4.357 4.283L3.626 6h-.642C1.889 6 1 7 1 8h.003S1 8.002 1 8.008C1 8.561 1.448 9 2 9h.6l-.043.148-1.039.346a2.001 2.001 0 0 0-1.359 2.097l.751 7.508a1 1 0 0 0 .994.901H3v1c0 1.103.896 2 2 2h2c1.104 0 2-.897 2-2v-1h6v1c0 1.103.896 2 2 2h2c1.104 0 2-.897 2-2v-1h1.096a.999.999 0 0 0 .994-.901l.751-7.508a2.001 2.001 0 0 0-1.359-2.097M6.273 4.857C6.402 4.43 6.788 4 7.236 4h9.527c.448 0 .834.43.963.857L19.313 9H4.688l1.585-4.143zM7 21H5v-1h2v1zm12 0h-2v-1h2v1zm2.189-3H2.811l-.662-6.607L3 11h18l.852.393L21.189 18z"/>`,
|
||||
people: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0m0 22C6.486 22 2 17.514 2 12S6.486 2 12 2s10 4.486 10 10-4.486 10-10 10" />
|
||||
<path d="M8 7a2 2 0 1 0-.001 3.999A2 2 0 0 0 8 7M16 7a2 2 0 1 0-.001 3.999A2 2 0 0 0 16 7M15.232 15c-.693 1.195-1.87 2-3.349 2-1.477 0-2.655-.805-3.347-2H15m3-2H6a6 6 0 1 0 12 0" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
recent: `<path d="M13 4h-2l-.001 7H9v2h2v2h2v-2h4v-2h-4z"/><path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0m0 22C6.486 22 2 17.514 2 12S6.486 2 12 2s10 4.486 10 10-4.486 10-10 10"/>`,
|
||||
places: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M6.5 12C5.122 12 4 13.121 4 14.5S5.122 17 6.5 17 9 15.879 9 14.5 7.878 12 6.5 12m0 3c-.275 0-.5-.225-.5-.5s.225-.5.5-.5.5.225.5.5-.225.5-.5.5M17.5 12c-1.378 0-2.5 1.121-2.5 2.5s1.122 2.5 2.5 2.5 2.5-1.121 2.5-2.5-1.122-2.5-2.5-2.5m0 3c-.275 0-.5-.225-.5-.5s.225-.5.5-.5.5.225.5.5-.225.5-.5.5" />
|
||||
<path d="M22.482 9.494l-1.039-.346L21.4 9h.6c.552 0 1-.439 1-.992 0-.006-.003-.008-.003-.008H23c0-1-.889-2-1.984-2h-.642l-.731-1.717C19.262 3.012 18.091 2 16.764 2H7.236C5.909 2 4.738 3.012 4.357 4.283L3.626 6h-.642C1.889 6 1 7 1 8h.003S1 8.002 1 8.008C1 8.561 1.448 9 2 9h.6l-.043.148-1.039.346a2.001 2.001 0 0 0-1.359 2.097l.751 7.508a1 1 0 0 0 .994.901H3v1c0 1.103.896 2 2 2h2c1.104 0 2-.897 2-2v-1h6v1c0 1.103.896 2 2 2h2c1.104 0 2-.897 2-2v-1h1.096a.999.999 0 0 0 .994-.901l.751-7.508a2.001 2.001 0 0 0-1.359-2.097M6.273 4.857C6.402 4.43 6.788 4 7.236 4h9.527c.448 0 .834.43.963.857L19.313 9H4.688l1.585-4.143zM7 21H5v-1h2v1zm12 0h-2v-1h2v1zm2.189-3H2.811l-.662-6.607L3 11h18l.852.393L21.189 18z" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
symbols: `<path d="M0 0h11v2H0zM4 11h3V6h4V4H0v2h4zM15.5 17c1.381 0 2.5-1.116 2.5-2.493s-1.119-2.493-2.5-2.493S13 13.13 13 14.507 14.119 17 15.5 17m0-2.986c.276 0 .5.222.5.493 0 .272-.224.493-.5.493s-.5-.221-.5-.493.224-.493.5-.493M21.5 19.014c-1.381 0-2.5 1.116-2.5 2.493S20.119 24 21.5 24s2.5-1.116 2.5-2.493-1.119-2.493-2.5-2.493m0 2.986a.497.497 0 0 1-.5-.493c0-.271.224-.493.5-.493s.5.222.5.493a.497.497 0 0 1-.5.493M22 13l-9 9 1.513 1.5 8.99-9.009zM17 11c2.209 0 4-1.119 4-2.5V2s.985-.161 1.498.949C23.01 4.055 23 6 23 6s1-1.119 1-3.135C24-.02 21 0 21 0h-2v6.347A5.853 5.853 0 0 0 17 6c-2.209 0-4 1.119-4 2.5s1.791 2.5 4 2.5M10.297 20.482l-1.475-1.585a47.54 47.54 0 0 1-1.442 1.129c-.307-.288-.989-1.016-2.045-2.183.902-.836 1.479-1.466 1.729-1.892s.376-.871.376-1.336c0-.592-.273-1.178-.818-1.759-.546-.581-1.329-.871-2.349-.871-1.008 0-1.79.293-2.344.879-.556.587-.832 1.181-.832 1.784 0 .813.419 1.748 1.256 2.805-.847.614-1.444 1.208-1.794 1.784a3.465 3.465 0 0 0-.523 1.833c0 .857.308 1.56.924 2.107.616.549 1.423.823 2.42.823 1.173 0 2.444-.379 3.813-1.137L8.235 24h2.819l-2.09-2.383 1.333-1.135zm-6.736-6.389a1.02 1.02 0 0 1 .73-.286c.31 0 .559.085.747.254a.849.849 0 0 1 .283.659c0 .518-.419 1.112-1.257 1.784-.536-.651-.805-1.231-.805-1.742a.901.901 0 0 1 .302-.669M3.74 22c-.427 0-.778-.116-1.057-.349-.279-.232-.418-.487-.418-.766 0-.594.509-1.288 1.527-2.083.968 1.134 1.717 1.946 2.248 2.438-.921.507-1.686.76-2.3.76"/>`,
|
||||
recent: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M13 4h-2l-.001 7H9v2h2v2h2v-2h4v-2h-4z" />
|
||||
<path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0m0 22C6.486 22 2 17.514 2 12S6.486 2 12 2s10 4.486 10 10-4.486 10-10 10" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
symbols: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path d="M0 0h11v2H0zM4 11h3V6h4V4H0v2h4zM15.5 17c1.381 0 2.5-1.116 2.5-2.493s-1.119-2.493-2.5-2.493S13 13.13 13 14.507 14.119 17 15.5 17m0-2.986c.276 0 .5.222.5.493 0 .272-.224.493-.5.493s-.5-.221-.5-.493.224-.493.5-.493M21.5 19.014c-1.381 0-2.5 1.116-2.5 2.493S20.119 24 21.5 24s2.5-1.116 2.5-2.493-1.119-2.493-2.5-2.493m0 2.986a.497.497 0 0 1-.5-.493c0-.271.224-.493.5-.493s.5.222.5.493a.497.497 0 0 1-.5.493M22 13l-9 9 1.513 1.5 8.99-9.009zM17 11c2.209 0 4-1.119 4-2.5V2s.985-.161 1.498.949C23.01 4.055 23 6 23 6s1-1.119 1-3.135C24-.02 21 0 21 0h-2v6.347A5.853 5.853 0 0 0 17 6c-2.209 0-4 1.119-4 2.5s1.791 2.5 4 2.5M10.297 20.482l-1.475-1.585a47.54 47.54 0 0 1-1.442 1.129c-.307-.288-.989-1.016-2.045-2.183.902-.836 1.479-1.466 1.729-1.892s.376-.871.376-1.336c0-.592-.273-1.178-.818-1.759-.546-.581-1.329-.871-2.349-.871-1.008 0-1.79.293-2.344.879-.556.587-.832 1.181-.832 1.784 0 .813.419 1.748 1.256 2.805-.847.614-1.444 1.208-1.794 1.784a3.465 3.465 0 0 0-.523 1.833c0 .857.308 1.56.924 2.107.616.549 1.423.823 2.42.823 1.173 0 2.444-.379 3.813-1.137L8.235 24h2.819l-2.09-2.383 1.333-1.135zm-6.736-6.389a1.02 1.02 0 0 1 .73-.286c.31 0 .559.085.747.254a.849.849 0 0 1 .283.659c0 .518-.419 1.112-1.257 1.784-.536-.651-.805-1.231-.805-1.742a.901.901 0 0 1 .302-.669M3.74 22c-.427 0-.778-.116-1.057-.349-.279-.232-.418-.487-.418-.766 0-.594.509-1.288 1.527-2.083.968 1.134 1.717 1.946 2.248 2.438-.921.507-1.686.76-2.3.76" />
|
||||
</svg>
|
||||
),
|
||||
}
|
||||
|
||||
export default SVGs
|
||||
const search = {
|
||||
search: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="13"
|
||||
height="13"
|
||||
viewBox="0 0 20 20"
|
||||
opacity="0.5"
|
||||
>
|
||||
<path d="M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z" />
|
||||
</svg>
|
||||
),
|
||||
|
||||
delete: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="13"
|
||||
height="13"
|
||||
viewBox="0 0 20 20"
|
||||
opacity="0.5"
|
||||
>
|
||||
<path d="M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z" />
|
||||
</svg>
|
||||
),
|
||||
}
|
||||
|
||||
export { categories, search }
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import React from 'react'
|
||||
import { getEmojiDataFromNative } from '..'
|
||||
|
||||
import data from '../../../data/apple'
|
||||
|
||||
test('will find man lifting weights with skin tone 6', () => {
|
||||
const emojiData = getEmojiDataFromNative('🏋🏿♂️', 'apple', data)
|
||||
expect(emojiData.id).toEqual('man-lifting-weights')
|
||||
expect(emojiData.skin).toEqual(6)
|
||||
})
|
||||
|
||||
test('will find woman swimming with skin tone 4', () => {
|
||||
const emojiData = getEmojiDataFromNative('🏊🏽♀️', 'apple', data)
|
||||
expect(emojiData.id).toEqual('woman-swimming')
|
||||
expect(emojiData.skin).toEqual(4)
|
||||
})
|
||||
|
||||
test('will find person in lotus positions', () => {
|
||||
const emojiData = getEmojiDataFromNative('🧘', 'apple', data)
|
||||
expect(emojiData.id).toEqual('person_in_lotus_position')
|
||||
expect(emojiData.skin).toEqual(1)
|
||||
})
|
||||
|
||||
test('returns null if no match', () => {
|
||||
const emojiData = getEmojiDataFromNative('', 'apple', data)
|
||||
expect(emojiData).toEqual(null)
|
||||
})
|
|
@ -1,26 +0,0 @@
|
|||
export default (data) => {
|
||||
const search = []
|
||||
|
||||
var addToSearch = (strings, split) => {
|
||||
if (!strings) {
|
||||
return
|
||||
}
|
||||
|
||||
;(Array.isArray(strings) ? strings : [strings]).forEach((string) => {
|
||||
;(split ? string.split(/[-|_|\s]+/) : [string]).forEach((s) => {
|
||||
s = s.toLowerCase()
|
||||
|
||||
if (search.indexOf(s) == -1) {
|
||||
search.push(s)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
addToSearch(data.short_names, true)
|
||||
addToSearch(data.name, true)
|
||||
addToSearch(data.keywords, false)
|
||||
addToSearch(data.emoticons, false)
|
||||
|
||||
return search.join(',')
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
const mapping = {
|
||||
name: 'a',
|
||||
unified: 'b',
|
||||
non_qualified: 'c',
|
||||
has_img_apple: 'd',
|
||||
has_img_google: 'e',
|
||||
has_img_twitter: 'f',
|
||||
has_img_facebook: 'h',
|
||||
keywords: 'j',
|
||||
sheet: 'k',
|
||||
emoticons: 'l',
|
||||
text: 'm',
|
||||
short_names: 'n',
|
||||
added_in: 'o',
|
||||
}
|
||||
|
||||
const buildSearch = (emoji) => {
|
||||
const search = []
|
||||
|
||||
var addToSearch = (strings, split) => {
|
||||
if (!strings) {
|
||||
return
|
||||
}
|
||||
|
||||
;(Array.isArray(strings) ? strings : [strings]).forEach((string) => {
|
||||
;(split ? string.split(/[-|_|\s]+/) : [string]).forEach((s) => {
|
||||
s = s.toLowerCase()
|
||||
|
||||
if (search.indexOf(s) == -1) {
|
||||
search.push(s)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
addToSearch(emoji.short_names, true)
|
||||
addToSearch(emoji.name, true)
|
||||
addToSearch(emoji.keywords, false)
|
||||
addToSearch(emoji.emoticons, false)
|
||||
|
||||
return search.join(',')
|
||||
}
|
||||
|
||||
const compress = (emoji) => {
|
||||
emoji.short_names = emoji.short_names.filter((short_name) => {
|
||||
return short_name !== emoji.short_name
|
||||
})
|
||||
delete emoji.short_name
|
||||
|
||||
emoji.sheet = [emoji.sheet_x, emoji.sheet_y]
|
||||
delete emoji.sheet_x
|
||||
delete emoji.sheet_y
|
||||
|
||||
emoji.added_in = parseInt(emoji.added_in)
|
||||
if (emoji.added_in === 6) {
|
||||
delete emoji.added_in
|
||||
}
|
||||
|
||||
for (let key in mapping) {
|
||||
emoji[mapping[key]] = emoji[key]
|
||||
delete emoji[key]
|
||||
}
|
||||
|
||||
for (let key in emoji) {
|
||||
let value = emoji[key]
|
||||
|
||||
if (Array.isArray(value) && !value.length) {
|
||||
delete emoji[key]
|
||||
} else if (typeof value === 'string' && !value.length) {
|
||||
delete emoji[key]
|
||||
} else if (value === null) {
|
||||
delete emoji[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uncompress = (data) => {
|
||||
data.compressed = false
|
||||
|
||||
for (let id in data.emojis) {
|
||||
let emoji = data.emojis[id]
|
||||
|
||||
for (let key in mapping) {
|
||||
emoji[key] = emoji[mapping[key]]
|
||||
delete emoji[mapping[key]]
|
||||
}
|
||||
|
||||
if (!emoji.short_names) emoji.short_names = []
|
||||
emoji.short_names.unshift(id)
|
||||
|
||||
emoji.sheet_x = emoji.sheet[0]
|
||||
emoji.sheet_y = emoji.sheet[1]
|
||||
delete emoji.sheet
|
||||
|
||||
if (!emoji.text) emoji.text = ''
|
||||
|
||||
if (!emoji.added_in) emoji.added_in = 6
|
||||
emoji.added_in = emoji.added_in.toFixed(1)
|
||||
|
||||
emoji.search = buildSearch(emoji)
|
||||
}
|
||||
}
|
||||
|
||||
export { buildSearch, compress, uncompress }
|
|
@ -1,180 +0,0 @@
|
|||
import data from '../data'
|
||||
import { getData, getSanitizedData, intersect } from '.'
|
||||
|
||||
var originalPool = {}
|
||||
var index = {}
|
||||
var emojisList = {}
|
||||
var emoticonsList = {}
|
||||
var customEmojisList = []
|
||||
|
||||
for (let emoji in data.emojis) {
|
||||
let emojiData = data.emojis[emoji],
|
||||
{ short_names, emoticons } = emojiData,
|
||||
id = short_names[0]
|
||||
|
||||
if (emoticons) {
|
||||
emoticons.forEach((emoticon) => {
|
||||
if (emoticonsList[emoticon]) {
|
||||
return
|
||||
}
|
||||
|
||||
emoticonsList[emoticon] = id
|
||||
})
|
||||
}
|
||||
|
||||
emojisList[id] = getSanitizedData(id)
|
||||
originalPool[id] = emojiData
|
||||
}
|
||||
|
||||
function clearCustomEmojis(pool) {
|
||||
customEmojisList.forEach((emoji) => {
|
||||
let emojiId = emoji.id || emoji.short_names[0]
|
||||
|
||||
delete pool[emojiId]
|
||||
delete emojisList[emojiId]
|
||||
})
|
||||
}
|
||||
|
||||
function addCustomToPool(custom, pool) {
|
||||
if (customEmojisList.length) clearCustomEmojis(pool)
|
||||
|
||||
custom.forEach((emoji) => {
|
||||
let emojiId = emoji.id || emoji.short_names[0]
|
||||
|
||||
if (emojiId && !pool[emojiId]) {
|
||||
pool[emojiId] = getData(emoji)
|
||||
emojisList[emojiId] = getSanitizedData(emoji)
|
||||
}
|
||||
})
|
||||
|
||||
customEmojisList = custom
|
||||
index = {}
|
||||
}
|
||||
|
||||
function search(
|
||||
value,
|
||||
{ emojisToShowFilter, maxResults, include, exclude, custom = [] } = {},
|
||||
) {
|
||||
if (customEmojisList != custom) addCustomToPool(custom, originalPool)
|
||||
|
||||
maxResults || (maxResults = 75)
|
||||
include || (include = [])
|
||||
exclude || (exclude = [])
|
||||
|
||||
var results = null,
|
||||
pool = originalPool
|
||||
|
||||
if (value.length) {
|
||||
if (value == '-' || value == '-1') {
|
||||
return [emojisList['-1']]
|
||||
}
|
||||
|
||||
var values = value.toLowerCase().split(/[\s|,|\-|_]+/),
|
||||
allResults = []
|
||||
|
||||
if (values.length > 2) {
|
||||
values = [values[0], values[1]]
|
||||
}
|
||||
|
||||
if (include.length || exclude.length) {
|
||||
pool = {}
|
||||
|
||||
data.categories.forEach((category) => {
|
||||
let isIncluded =
|
||||
include && include.length ? include.indexOf(category.id) > -1 : true
|
||||
let isExcluded =
|
||||
exclude && exclude.length ? exclude.indexOf(category.id) > -1 : false
|
||||
if (!isIncluded || isExcluded) {
|
||||
return
|
||||
}
|
||||
|
||||
category.emojis.forEach(
|
||||
(emojiId) => (pool[emojiId] = data.emojis[emojiId]),
|
||||
)
|
||||
})
|
||||
|
||||
if (custom.length) {
|
||||
let customIsIncluded =
|
||||
include && include.length ? include.indexOf('custom') > -1 : true
|
||||
let customIsExcluded =
|
||||
exclude && exclude.length ? exclude.indexOf('custom') > -1 : false
|
||||
if (customIsIncluded && !customIsExcluded) {
|
||||
addCustomToPool(custom, pool)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allResults = values
|
||||
.map((value) => {
|
||||
var aPool = pool,
|
||||
aIndex = index,
|
||||
length = 0
|
||||
|
||||
for (let charIndex = 0; charIndex < value.length; charIndex++) {
|
||||
const char = value[charIndex]
|
||||
length++
|
||||
|
||||
aIndex[char] || (aIndex[char] = {})
|
||||
aIndex = aIndex[char]
|
||||
|
||||
if (!aIndex.results) {
|
||||
let scores = {}
|
||||
|
||||
aIndex.results = []
|
||||
aIndex.pool = {}
|
||||
|
||||
for (let id in aPool) {
|
||||
let emoji = aPool[id],
|
||||
{ search } = emoji,
|
||||
sub = value.substr(0, length),
|
||||
subIndex = search.indexOf(sub)
|
||||
|
||||
if (subIndex != -1) {
|
||||
let score = subIndex + 1
|
||||
if (sub == id) score = 0
|
||||
|
||||
aIndex.results.push(emojisList[id])
|
||||
aIndex.pool[id] = emoji
|
||||
|
||||
scores[id] = score
|
||||
}
|
||||
}
|
||||
|
||||
aIndex.results.sort((a, b) => {
|
||||
var aScore = scores[a.id],
|
||||
bScore = scores[b.id]
|
||||
|
||||
return aScore - bScore
|
||||
})
|
||||
}
|
||||
|
||||
aPool = aIndex.pool
|
||||
}
|
||||
|
||||
return aIndex.results
|
||||
})
|
||||
.filter((a) => a)
|
||||
|
||||
if (allResults.length > 1) {
|
||||
results = intersect.apply(null, allResults)
|
||||
} else if (allResults.length) {
|
||||
results = allResults[0]
|
||||
} else {
|
||||
results = []
|
||||
}
|
||||
}
|
||||
|
||||
if (results) {
|
||||
if (emojisToShowFilter) {
|
||||
results = results.filter((result) => emojisToShowFilter(pool[result.id]))
|
||||
}
|
||||
|
||||
if (results && results.length > maxResults) {
|
||||
results = results.slice(0, maxResults)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
export default { search, emojis: emojisList, emoticons: emoticonsList }
|
|
@ -0,0 +1,51 @@
|
|||
import emojiIndex from '../emoji-index.js'
|
||||
|
||||
test('should work', () => {
|
||||
expect(emojiIndex.search('pineapple')).toEqual([
|
||||
{
|
||||
id: 'pineapple',
|
||||
name: 'Pineapple',
|
||||
short_names: ['pineapple'],
|
||||
colons: ':pineapple:',
|
||||
emoticons: [],
|
||||
unified: '1f34d',
|
||||
skin: null,
|
||||
native: '🍍',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('should filter only emojis we care about, exclude pineapple', () => {
|
||||
let emojisToShowFilter = (data) => {
|
||||
data.unified !== '1F34D'
|
||||
}
|
||||
expect(
|
||||
emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id),
|
||||
).not.toContain('pineapple')
|
||||
})
|
||||
|
||||
test('can include/exclude categories', () => {
|
||||
expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([])
|
||||
})
|
||||
|
||||
test('can search for thinking_face', () => {
|
||||
expect(emojiIndex.search('thinking_fac').map((x) => x.id)).toEqual([
|
||||
'thinking_face',
|
||||
])
|
||||
})
|
||||
|
||||
test('can search for woman-facepalming', () => {
|
||||
expect(emojiIndex.search('woman-facep').map((x) => x.id)).toEqual([
|
||||
'woman-facepalming',
|
||||
])
|
||||
})
|
||||
|
||||
test('emojiIndex exports emojis', () => {
|
||||
const emojis = emojiIndex.emojis
|
||||
expect(emojis['thinking_face'].native).toEqual('\ud83e\udd14')
|
||||
})
|
||||
|
||||
test('emojiIndex exports emoticons', () => {
|
||||
const emoticons = emojiIndex.emoticons
|
||||
expect(emoticons[':)']).toEqual('slightly_smiling_face')
|
||||
})
|
|
@ -0,0 +1,24 @@
|
|||
import NimbleEmojiIndex from '../nimble-emoji-index.js'
|
||||
import store from '../../store'
|
||||
|
||||
import data from '../../../../data/all'
|
||||
|
||||
const nimbleEmojiIndex = new NimbleEmojiIndex(data)
|
||||
|
||||
function getEmojiData(skinTone) {
|
||||
store.update({ skin: skinTone })
|
||||
|
||||
return nimbleEmojiIndex.search('thumbsup')[0]
|
||||
}
|
||||
|
||||
test('should return emojis with skin tone 1', () => {
|
||||
const skinTone = 1
|
||||
const emoji = getEmojiData(skinTone)
|
||||
expect(emoji.skin).toEqual(skinTone)
|
||||
})
|
||||
|
||||
test('should return emojis with skin tone 6', () => {
|
||||
const skinTone = 6
|
||||
const emoji = getEmojiData(skinTone)
|
||||
expect(emoji.skin).toEqual(skinTone)
|
||||
})
|
|
@ -0,0 +1,11 @@
|
|||
import data from '../../../data/all.json'
|
||||
import NimbleEmojiIndex from './nimble-emoji-index'
|
||||
|
||||
const emojiIndex = new NimbleEmojiIndex(data)
|
||||
const { emojis, emoticons } = emojiIndex
|
||||
|
||||
function search() {
|
||||
return emojiIndex.search(...arguments)
|
||||
}
|
||||
|
||||
export default { search, emojis, emoticons }
|
|
@ -0,0 +1,222 @@
|
|||
import { getData, getSanitizedData, intersect } from '..'
|
||||
import { uncompress } from '../data'
|
||||
import store from '../store'
|
||||
|
||||
export default class NimbleEmojiIndex {
|
||||
constructor(data, set) {
|
||||
if (data.compressed) {
|
||||
uncompress(data)
|
||||
}
|
||||
|
||||
this.data = data || {}
|
||||
this.set = set || null
|
||||
this.originalPool = {}
|
||||
this.index = {}
|
||||
this.emojis = {}
|
||||
this.emoticons = {}
|
||||
this.customEmojisList = []
|
||||
|
||||
this.buildIndex()
|
||||
}
|
||||
|
||||
buildIndex() {
|
||||
for (let emoji in this.data.emojis) {
|
||||
let emojiData = this.data.emojis[emoji],
|
||||
{ short_names, emoticons, skin_variations } = emojiData,
|
||||
id = short_names[0]
|
||||
|
||||
if (emoticons) {
|
||||
emoticons.forEach((emoticon) => {
|
||||
if (this.emoticons[emoticon]) {
|
||||
return
|
||||
}
|
||||
|
||||
this.emoticons[emoticon] = id
|
||||
})
|
||||
}
|
||||
|
||||
// If skin variations include them
|
||||
if (skin_variations) {
|
||||
this.emojis[id] = {}
|
||||
for (let skinTone = 1; skinTone <= 6; skinTone++) {
|
||||
this.emojis[id][skinTone] = getSanitizedData(
|
||||
{ id, skin: skinTone },
|
||||
skinTone,
|
||||
this.set,
|
||||
this.data,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
this.emojis[id] = getSanitizedData(id, null, this.set, this.data)
|
||||
}
|
||||
|
||||
this.originalPool[id] = emojiData
|
||||
}
|
||||
}
|
||||
|
||||
clearCustomEmojis(pool) {
|
||||
this.customEmojisList.forEach((emoji) => {
|
||||
let emojiId = emoji.id || emoji.short_names[0]
|
||||
|
||||
delete pool[emojiId]
|
||||
delete this.emojis[emojiId]
|
||||
})
|
||||
}
|
||||
|
||||
addCustomToPool(custom, pool) {
|
||||
if (this.customEmojisList.length) this.clearCustomEmojis(pool)
|
||||
|
||||
custom.forEach((emoji) => {
|
||||
let emojiId = emoji.id || emoji.short_names[0]
|
||||
|
||||
if (emojiId && !pool[emojiId]) {
|
||||
pool[emojiId] = getData(emoji, null, null, this.data)
|
||||
this.emojis[emojiId] = getSanitizedData(emoji, null, null, this.data)
|
||||
}
|
||||
})
|
||||
|
||||
this.customEmojisList = custom
|
||||
this.index = {}
|
||||
}
|
||||
|
||||
search(
|
||||
value,
|
||||
{ emojisToShowFilter, maxResults, include, exclude, custom = [] } = {},
|
||||
) {
|
||||
if (this.customEmojisList != custom)
|
||||
this.addCustomToPool(custom, this.originalPool)
|
||||
|
||||
const skinTone = store.get('skin') || 1
|
||||
|
||||
maxResults || (maxResults = 75)
|
||||
include || (include = [])
|
||||
exclude || (exclude = [])
|
||||
|
||||
var results = null,
|
||||
pool = this.originalPool
|
||||
|
||||
if (value.length) {
|
||||
if (value == '-' || value == '-1') {
|
||||
return [this.emojis['-1'][skinTone]]
|
||||
}
|
||||
|
||||
var values = value.toLowerCase().split(/[\s|,|\-|_]+/),
|
||||
allResults = []
|
||||
|
||||
if (values.length > 2) {
|
||||
values = [values[0], values[1]]
|
||||
}
|
||||
|
||||
if (include.length || exclude.length) {
|
||||
pool = {}
|
||||
|
||||
this.data.categories.forEach((category) => {
|
||||
let isIncluded =
|
||||
include && include.length ? include.indexOf(category.id) > -1 : true
|
||||
let isExcluded =
|
||||
exclude && exclude.length
|
||||
? exclude.indexOf(category.id) > -1
|
||||
: false
|
||||
if (!isIncluded || isExcluded) {
|
||||
return
|
||||
}
|
||||
|
||||
category.emojis.forEach(
|
||||
(emojiId) => (pool[emojiId] = this.data.emojis[emojiId]),
|
||||
)
|
||||
})
|
||||
|
||||
if (custom.length) {
|
||||
let customIsIncluded =
|
||||
include && include.length ? include.indexOf('custom') > -1 : true
|
||||
let customIsExcluded =
|
||||
exclude && exclude.length ? exclude.indexOf('custom') > -1 : false
|
||||
if (customIsIncluded && !customIsExcluded) {
|
||||
this.addCustomToPool(custom, pool)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allResults = values
|
||||
.map((value) => {
|
||||
var aPool = pool,
|
||||
aIndex = this.index,
|
||||
length = 0
|
||||
|
||||
for (let charIndex = 0; charIndex < value.length; charIndex++) {
|
||||
const char = value[charIndex]
|
||||
length++
|
||||
|
||||
aIndex[char] || (aIndex[char] = {})
|
||||
aIndex = aIndex[char]
|
||||
|
||||
if (!aIndex.results) {
|
||||
let scores = {}
|
||||
|
||||
aIndex.results = []
|
||||
aIndex.pool = {}
|
||||
|
||||
for (let id in aPool) {
|
||||
let emoji = aPool[id],
|
||||
{ search } = emoji,
|
||||
sub = value.substr(0, length),
|
||||
subIndex = search.indexOf(sub)
|
||||
|
||||
if (subIndex != -1) {
|
||||
let score = subIndex + 1
|
||||
if (sub == id) score = 0
|
||||
|
||||
if (this.emojis[id] && this.emojis[id][skinTone]) {
|
||||
aIndex.results.push(this.emojis[id][skinTone])
|
||||
} else {
|
||||
aIndex.results.push(this.emojis[id])
|
||||
}
|
||||
aIndex.pool[id] = emoji
|
||||
|
||||
scores[id] = score
|
||||
}
|
||||
}
|
||||
|
||||
aIndex.results.sort((a, b) => {
|
||||
var aScore = scores[a.id],
|
||||
bScore = scores[b.id]
|
||||
|
||||
if (aScore == bScore) {
|
||||
return a.id.localeCompare(b.id)
|
||||
} else {
|
||||
return aScore - bScore
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
aPool = aIndex.pool
|
||||
}
|
||||
|
||||
return aIndex.results
|
||||
})
|
||||
.filter((a) => a)
|
||||
|
||||
if (allResults.length > 1) {
|
||||
results = intersect.apply(null, allResults)
|
||||
} else if (allResults.length) {
|
||||
results = allResults[0]
|
||||
} else {
|
||||
results = []
|
||||
}
|
||||
}
|
||||
|
||||
if (results) {
|
||||
if (emojisToShowFilter) {
|
||||
results = results.filter((result) =>
|
||||
emojisToShowFilter(pool[result.id]),
|
||||
)
|
||||
}
|
||||
|
||||
if (results && results.length > maxResults) {
|
||||
results = results.slice(0, maxResults)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
import buildSearch from './build-search'
|
||||
import data from '../data'
|
||||
import { buildSearch } from './data'
|
||||
import stringFromCodePoint from '../polyfills/stringFromCodePoint'
|
||||
|
||||
const _JSON = JSON
|
||||
import { uncompress } from './data'
|
||||
|
||||
const COLONS_REGEX = /^(?:\:([^\:]+)\:)(?:\:skin-tone-(\d)\:)?$/
|
||||
const SKINS = ['1F3FA', '1F3FB', '1F3FC', '1F3FD', '1F3FE', '1F3FF']
|
||||
|
@ -23,6 +21,7 @@ function sanitize(emoji) {
|
|||
emoticons,
|
||||
unified,
|
||||
custom,
|
||||
customCategory,
|
||||
imageUrl,
|
||||
} = emoji,
|
||||
id = emoji.id || short_names[0],
|
||||
|
@ -32,9 +31,11 @@ function sanitize(emoji) {
|
|||
return {
|
||||
id,
|
||||
name,
|
||||
short_names,
|
||||
colons,
|
||||
emoticons,
|
||||
custom,
|
||||
customCategory,
|
||||
imageUrl,
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +47,7 @@ function sanitize(emoji) {
|
|||
return {
|
||||
id,
|
||||
name,
|
||||
short_names,
|
||||
colons,
|
||||
emoticons,
|
||||
unified: unified.toLowerCase(),
|
||||
|
@ -58,7 +60,7 @@ function getSanitizedData() {
|
|||
return sanitize(getData(...arguments))
|
||||
}
|
||||
|
||||
function getData(emoji, skin, set) {
|
||||
function getData(emoji, skin, set, data) {
|
||||
var emojiData = {}
|
||||
|
||||
if (typeof emoji == 'string') {
|
||||
|
@ -68,12 +70,12 @@ function getData(emoji, skin, set) {
|
|||
emoji = matches[1]
|
||||
|
||||
if (matches[2]) {
|
||||
skin = parseInt(matches[2])
|
||||
skin = parseInt(matches[2], 10)
|
||||
}
|
||||
}
|
||||
|
||||
if (data.short_names.hasOwnProperty(emoji)) {
|
||||
emoji = data.short_names[emoji]
|
||||
if (data.aliases.hasOwnProperty(emoji)) {
|
||||
emoji = data.aliases[emoji]
|
||||
}
|
||||
|
||||
if (data.emojis.hasOwnProperty(emoji)) {
|
||||
|
@ -82,8 +84,8 @@ function getData(emoji, skin, set) {
|
|||
return null
|
||||
}
|
||||
} else if (emoji.id) {
|
||||
if (data.short_names.hasOwnProperty(emoji.id)) {
|
||||
emoji.id = data.short_names[emoji.id]
|
||||
if (data.aliases.hasOwnProperty(emoji.id)) {
|
||||
emoji.id = data.aliases[emoji.id]
|
||||
}
|
||||
|
||||
if (data.emojis.hasOwnProperty(emoji.id)) {
|
||||
|
@ -104,34 +106,87 @@ function getData(emoji, skin, set) {
|
|||
emojiData.emoticons || (emojiData.emoticons = [])
|
||||
emojiData.variations || (emojiData.variations = [])
|
||||
|
||||
if (emojiData.skin_variations && skin > 1 && set) {
|
||||
emojiData = JSON.parse(_JSON.stringify(emojiData))
|
||||
if (emojiData.skin_variations && skin > 1) {
|
||||
emojiData = JSON.parse(JSON.stringify(emojiData))
|
||||
|
||||
var skinKey = SKINS[skin - 1],
|
||||
variationData = emojiData.skin_variations[skinKey]
|
||||
|
||||
if (!variationData.variations && emojiData.variations) {
|
||||
delete emojiData.variations
|
||||
}
|
||||
if (variationData) {
|
||||
if (!variationData.variations && emojiData.variations) {
|
||||
delete emojiData.variations
|
||||
}
|
||||
|
||||
if (variationData[`has_img_${set}`]) {
|
||||
emojiData.skin_tone = skin
|
||||
if (
|
||||
(set &&
|
||||
(variationData[`has_img_${set}`] == undefined ||
|
||||
variationData[`has_img_${set}`])) ||
|
||||
!set
|
||||
) {
|
||||
emojiData.skin_tone = skin
|
||||
|
||||
for (let k in variationData) {
|
||||
let v = variationData[k]
|
||||
emojiData[k] = v
|
||||
for (let k in variationData) {
|
||||
let v = variationData[k]
|
||||
emojiData[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (emojiData.variations && emojiData.variations.length) {
|
||||
emojiData = JSON.parse(_JSON.stringify(emojiData))
|
||||
emojiData = JSON.parse(JSON.stringify(emojiData))
|
||||
emojiData.unified = emojiData.variations.shift()
|
||||
}
|
||||
|
||||
return emojiData
|
||||
}
|
||||
|
||||
function getEmojiDataFromNative(nativeString, set, data) {
|
||||
if (data.compressed) {
|
||||
uncompress(data)
|
||||
}
|
||||
|
||||
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿']
|
||||
const skinCodes = ['1F3FB', '1F3FC', '1F3FD', '1F3FE', '1F3FF']
|
||||
|
||||
let skin
|
||||
let skinCode
|
||||
let baseNativeString = nativeString
|
||||
|
||||
skinTones.forEach((skinTone, skinToneIndex) => {
|
||||
if (nativeString.indexOf(skinTone) > 0) {
|
||||
skin = skinToneIndex + 2
|
||||
skinCode = skinCodes[skinToneIndex]
|
||||
}
|
||||
})
|
||||
|
||||
let emojiData
|
||||
|
||||
for (let id in data.emojis) {
|
||||
let emoji = data.emojis[id]
|
||||
|
||||
let emojiUnified = emoji.unified
|
||||
|
||||
if (emoji.variations && emoji.variations.length) {
|
||||
emojiUnified = emoji.variations.shift()
|
||||
}
|
||||
|
||||
if (skin && emoji.skin_variations && emoji.skin_variations[skinCode]) {
|
||||
emojiUnified = emoji.skin_variations[skinCode].unified
|
||||
}
|
||||
|
||||
if (unifiedToNative(emojiUnified) === baseNativeString) emojiData = emoji
|
||||
}
|
||||
|
||||
if (!emojiData) {
|
||||
return null
|
||||
}
|
||||
|
||||
emojiData.id = emojiData.short_names[0]
|
||||
|
||||
return getSanitizedData(emojiData, skin, set, data)
|
||||
}
|
||||
|
||||
function uniq(arr) {
|
||||
return arr.reduce((acc, item) => {
|
||||
if (acc.indexOf(item) === -1) {
|
||||
|
@ -187,12 +242,34 @@ function measureScrollbar() {
|
|||
return scrollbarWidth
|
||||
}
|
||||
|
||||
// Use requestIdleCallback() if available, else fall back to setTimeout().
|
||||
// Throttle so as not to run too frequently.
|
||||
function throttleIdleTask(func) {
|
||||
const doIdleTask =
|
||||
typeof requestIdleCallback === 'function' ? requestIdleCallback : setTimeout
|
||||
|
||||
let running = false
|
||||
|
||||
return function throttled() {
|
||||
if (running) {
|
||||
return
|
||||
}
|
||||
running = true
|
||||
doIdleTask(() => {
|
||||
running = false
|
||||
func()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
getData,
|
||||
getEmojiDataFromNative,
|
||||
getSanitizedData,
|
||||
uniq,
|
||||
intersect,
|
||||
deepMerge,
|
||||
unifiedToNative,
|
||||
measureScrollbar,
|
||||
throttleIdleTask,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
const EmojiDefaultProps = {
|
||||
skin: 1,
|
||||
set: 'apple',
|
||||
sheetSize: 64,
|
||||
sheetColumns: 57,
|
||||
sheetRows: 57,
|
||||
native: false,
|
||||
forceSize: false,
|
||||
tooltip: false,
|
||||
useButton: true,
|
||||
backgroundImageFn: (set, sheetSize) =>
|
||||
`https://unpkg.com/emoji-datasource-${set}@${EMOJI_DATASOURCE_VERSION}/img/${set}/sheets-256/${sheetSize}.png`,
|
||||
}
|
||||
|
||||
const PickerDefaultProps = {
|
||||
onClick: () => {},
|
||||
onSelect: () => {},
|
||||
onSkinChange: () => {},
|
||||
emojiSize: 24,
|
||||
perLine: 9,
|
||||
i18n: {},
|
||||
style: {},
|
||||
title: 'Emoji Mart™',
|
||||
emoji: 'department_store',
|
||||
color: '#ae65c5',
|
||||
set: EmojiDefaultProps.set,
|
||||
theme: 'light',
|
||||
skin: null,
|
||||
defaultSkin: EmojiDefaultProps.skin,
|
||||
native: EmojiDefaultProps.native,
|
||||
sheetSize: EmojiDefaultProps.sheetSize,
|
||||
backgroundImageFn: EmojiDefaultProps.backgroundImageFn,
|
||||
emojisToShowFilter: null,
|
||||
showPreview: true,
|
||||
showSkinTones: true,
|
||||
emojiTooltip: EmojiDefaultProps.tooltip,
|
||||
useButton: EmojiDefaultProps.useButton,
|
||||
autoFocus: false,
|
||||
enableFrequentEmojiSort: false,
|
||||
custom: [],
|
||||
skinEmoji: '',
|
||||
notFound: () => {},
|
||||
notFoundEmoji: 'sleuth_or_spy',
|
||||
icons: {},
|
||||
}
|
||||
|
||||
export { PickerDefaultProps, EmojiDefaultProps }
|
|
@ -0,0 +1,71 @@
|
|||
import PropTypes from 'prop-types'
|
||||
|
||||
const EmojiPropTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
onOver: PropTypes.func,
|
||||
onLeave: PropTypes.func,
|
||||
onClick: PropTypes.func,
|
||||
fallback: PropTypes.func,
|
||||
backgroundImageFn: PropTypes.func,
|
||||
native: PropTypes.bool,
|
||||
forceSize: PropTypes.bool,
|
||||
tooltip: PropTypes.bool,
|
||||
useButton: PropTypes.bool,
|
||||
skin: PropTypes.oneOf([1, 2, 3, 4, 5, 6]),
|
||||
sheetSize: PropTypes.oneOf([16, 20, 32, 64]),
|
||||
sheetColumns: PropTypes.number,
|
||||
sheetRows: PropTypes.number,
|
||||
set: PropTypes.oneOf(['apple', 'google', 'twitter', 'facebook']),
|
||||
size: PropTypes.number.isRequired,
|
||||
emoji: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
|
||||
}
|
||||
|
||||
const PickerPropTypes = {
|
||||
onClick: PropTypes.func,
|
||||
onSelect: PropTypes.func,
|
||||
onSkinChange: PropTypes.func,
|
||||
perLine: PropTypes.number,
|
||||
emojiSize: PropTypes.number,
|
||||
i18n: PropTypes.object,
|
||||
style: PropTypes.object,
|
||||
title: PropTypes.string,
|
||||
emoji: PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
set: EmojiPropTypes.set,
|
||||
skin: EmojiPropTypes.skin,
|
||||
native: PropTypes.bool,
|
||||
backgroundImageFn: EmojiPropTypes.backgroundImageFn,
|
||||
sheetSize: EmojiPropTypes.sheetSize,
|
||||
emojisToShowFilter: PropTypes.func,
|
||||
showPreview: PropTypes.bool,
|
||||
showSkinTones: PropTypes.bool,
|
||||
emojiTooltip: EmojiPropTypes.tooltip,
|
||||
useButton: EmojiPropTypes.useButton,
|
||||
theme: PropTypes.oneOf(['auto', 'light', 'dark']),
|
||||
include: PropTypes.arrayOf(PropTypes.string),
|
||||
exclude: PropTypes.arrayOf(PropTypes.string),
|
||||
recent: PropTypes.arrayOf(PropTypes.string),
|
||||
autoFocus: PropTypes.bool,
|
||||
enableFrequentEmojiSort: PropTypes.bool,
|
||||
custom: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
short_names: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
emoticons: PropTypes.arrayOf(PropTypes.string),
|
||||
keywords: PropTypes.arrayOf(PropTypes.string),
|
||||
imageUrl: PropTypes.string,
|
||||
spriteUrl: PropTypes.string,
|
||||
sheet_x: PropTypes.number,
|
||||
sheet_y: PropTypes.number,
|
||||
size: PropTypes.number,
|
||||
sheetColumns: PropTypes.number,
|
||||
sheetRows: PropTypes.number,
|
||||
}),
|
||||
),
|
||||
skinEmoji: PropTypes.string,
|
||||
notFound: PropTypes.func,
|
||||
notFoundEmoji: PropTypes.string,
|
||||
icons: PropTypes.object,
|
||||
}
|
||||
|
||||
export { EmojiPropTypes, PickerPropTypes }
|
|
@ -1,7 +1,5 @@
|
|||
var NAMESPACE = 'emoji-mart'
|
||||
|
||||
const _JSON = JSON
|
||||
|
||||
var isLocalStorageSupported =
|
||||
typeof window !== 'undefined' && 'localStorage' in window
|
||||
|
||||
|
@ -32,7 +30,7 @@ function set(key, value) {
|
|||
} else {
|
||||
if (!isLocalStorageSupported) return
|
||||
try {
|
||||
window.localStorage[`${NAMESPACE}.${key}`] = _JSON.stringify(value)
|
||||
window.localStorage[`${NAMESPACE}.${key}`] = JSON.stringify(value)
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
@ -44,13 +42,13 @@ function get(key) {
|
|||
if (!isLocalStorageSupported) return
|
||||
try {
|
||||
var value = window.localStorage[`${NAMESPACE}.${key}`]
|
||||
|
||||
if (value) {
|
||||
return JSON.parse(value)
|
||||
}
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
|
||||
if (value) {
|
||||
return JSON.parse(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
|
||||
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
|
||||
|
||||
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
|
||||
|
||||
// MIT license
|
||||
|
||||
var isWindowAvailable = typeof window !== 'undefined'
|
||||
|
||||
isWindowAvailable &&
|
||||
(function() {
|
||||
var lastTime = 0
|
||||
var vendors = ['ms', 'moz', 'webkit', 'o']
|
||||
|
||||
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame =
|
||||
window[vendors[x] + 'RequestAnimationFrame']
|
||||
window.cancelAnimationFrame =
|
||||
window[vendors[x] + 'CancelAnimationFrame'] ||
|
||||
window[vendors[x] + 'CancelRequestAnimationFrame']
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function(callback, element) {
|
||||
var currTime = new Date().getTime()
|
||||
var timeToCall = Math.max(0, 16 - (currTime - lastTime))
|
||||
var id = window.setTimeout(function() {
|
||||
callback(currTime + timeToCall)
|
||||
}, timeToCall)
|
||||
|
||||
lastTime = currTime + timeToCall
|
||||
return id
|
||||
}
|
||||
|
||||
if (!window.cancelAnimationFrame)
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id)
|
||||
}
|
||||
})()
|
283
stories/index.js
283
stories/index.js
|
@ -1,52 +1,216 @@
|
|||
import React from 'react';
|
||||
import React from 'react'
|
||||
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { withKnobs, text, boolean, number, select, color } from '@storybook/addon-knobs';
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import { action } from '@storybook/addon-actions'
|
||||
import {
|
||||
withKnobs,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
select,
|
||||
color,
|
||||
} from '@storybook/addon-knobs'
|
||||
|
||||
import { Picker, Emoji, emojiIndex } from '../dist';
|
||||
import '../css/emoji-mart.css';
|
||||
import {
|
||||
Picker,
|
||||
Emoji,
|
||||
emojiIndex,
|
||||
NimbleEmojiIndex,
|
||||
getEmojiDataFromNative,
|
||||
} from '../dist'
|
||||
import data from '../data/all.json'
|
||||
import '../css/emoji-mart.css'
|
||||
|
||||
const SETS = ['apple', 'google', 'twitter', 'emojione', 'messenger', 'facebook']
|
||||
const THEMES = ['auto', 'light', 'dark']
|
||||
const SETS = ['apple', 'google', 'twitter', 'facebook']
|
||||
const CUSTOM_EMOJIS = [
|
||||
{
|
||||
name: 'Octocat',
|
||||
short_names: ['octocat'],
|
||||
keywords: ['github'],
|
||||
imageUrl: 'https://assets-cdn.github.com/images/icons/emoji/octocat.png?v7'
|
||||
imageUrl: 'https://github.githubassets.com/images/icons/emoji/octocat.png',
|
||||
},
|
||||
{
|
||||
name: 'Squirrel',
|
||||
short_names: ['shipit', 'squirrel'],
|
||||
keywords: ['github'],
|
||||
imageUrl: 'https://assets-cdn.github.com/images/icons/emoji/shipit.png?v7'
|
||||
}
|
||||
imageUrl: 'https://github.githubassets.com/images/icons/emoji/shipit.png',
|
||||
},
|
||||
]
|
||||
|
||||
const CUSTOM_EMOJIS_WITH_CATEGORIES = CUSTOM_EMOJIS.map((emoji) => {
|
||||
return Object.assign({}, emoji, {
|
||||
customCategory: emoji.name === 'Squirrel' ? 'Mammals' : 'Mollusks',
|
||||
})
|
||||
})
|
||||
|
||||
storiesOf('Picker', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add('default', () => (
|
||||
.add('Default', () => (
|
||||
<Picker
|
||||
onClick={action('clicked')}
|
||||
onSelect={action('selected')}
|
||||
onSkinChange={action('skin changed')}
|
||||
native={boolean('Unicode', true)}
|
||||
theme={select('Theme', THEMES, THEMES[0])}
|
||||
set={select('Emoji pack', SETS, SETS[0])}
|
||||
emojiSize={number('Emoji size', 24)}
|
||||
perLine={number('Per line', 9)}
|
||||
perLine={number('Per line', 9, { min: 6 })}
|
||||
title={text('Idle text', 'Your Title Here')}
|
||||
emoji={text('Idle emoji', 'department_store')}
|
||||
defaultSkin={number('Default skin tone', 1)}
|
||||
notFoundEmoji={text('Not found emoji', 'sleuth_or_spy')}
|
||||
defaultSkin={number('Default skin tone', 1, { min: 1, max: 6 })}
|
||||
color={color('Highlight color', '#ae65c5')}
|
||||
showPreview={boolean('Show preview', true)}
|
||||
showSkinTones={boolean('Show skin tones', true)}
|
||||
enableFrequentEmojiSort={boolean('Enable frequent sort', false)}
|
||||
useButton={false}
|
||||
custom={CUSTOM_EMOJIS}
|
||||
/>
|
||||
));
|
||||
))
|
||||
|
||||
.add('Custom “Not found” component', () => (
|
||||
<Picker
|
||||
notFound={() => (
|
||||
<img src="https://github.githubassets.com/images/icons/emoji/octocat.png" />
|
||||
)}
|
||||
/>
|
||||
))
|
||||
|
||||
.add('Custom categories', () => (
|
||||
<Picker custom={CUSTOM_EMOJIS_WITH_CATEGORIES} />
|
||||
))
|
||||
|
||||
.add('Custom category icons', () => (
|
||||
<Picker
|
||||
custom={CUSTOM_EMOJIS}
|
||||
icons={{
|
||||
categories: {
|
||||
recent: () => (
|
||||
<img src="https://github.githubassets.com/images/icons/emoji/octocat.png" />
|
||||
),
|
||||
people: () => (
|
||||
<svg
|
||||
aria-labelledby="simpleicons-reddit-icon"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title id="simpleicons-reddit-icon">Reddit icon</title>
|
||||
<path d="M2.204 14.049c-.06.276-.091.56-.091.847 0 3.443 4.402 6.249 9.814 6.249 5.41 0 9.812-2.804 9.812-6.249 0-.274-.029-.546-.082-.809l-.015-.032c-.021-.055-.029-.11-.029-.165-.302-1.175-1.117-2.241-2.296-3.103-.045-.016-.088-.039-.126-.07-.026-.02-.045-.042-.067-.064-1.792-1.234-4.356-2.008-7.196-2.008-2.815 0-5.354.759-7.146 1.971-.014.018-.029.033-.049.049-.039.033-.084.06-.13.075-1.206.862-2.042 1.937-2.354 3.123 0 .058-.014.114-.037.171l-.008.015zm9.773 5.441c-1.794 0-3.057-.389-3.863-1.197-.173-.174-.173-.457 0-.632.176-.165.46-.165.635 0 .63.629 1.685.943 3.228.943 1.542 0 2.591-.3 3.219-.929.165-.164.45-.164.629 0 .165.18.165.465 0 .645-.809.808-2.065 1.198-3.862 1.198l.014-.028zm-3.606-7.573c-.914 0-1.677.765-1.677 1.677 0 .91.763 1.65 1.677 1.65s1.651-.74 1.651-1.65c0-.912-.739-1.677-1.651-1.677zm7.233 0c-.914 0-1.678.765-1.678 1.677 0 .91.764 1.65 1.678 1.65s1.651-.74 1.651-1.65c0-.912-.739-1.677-1.651-1.677zm4.548-1.595c1.037.833 1.8 1.821 2.189 2.904.45-.336.719-.864.719-1.449 0-1.002-.815-1.816-1.818-1.816-.399 0-.778.129-1.09.363v-.002zM2.711 9.963c-1.003 0-1.817.816-1.817 1.818 0 .543.239 1.048.644 1.389.401-1.079 1.172-2.053 2.213-2.876-.302-.21-.663-.329-1.039-.329v-.002zm9.217 12.079c-5.906 0-10.709-3.205-10.709-7.142 0-.275.023-.544.068-.809C.494 13.598 0 12.729 0 11.777c0-1.496 1.227-2.713 2.725-2.713.674 0 1.303.246 1.797.682 1.856-1.191 4.357-1.941 7.112-1.992l1.812-5.524.404.095s.016 0 .016.002l4.223.993c.344-.798 1.138-1.36 2.065-1.36 1.229 0 2.231 1.004 2.231 2.234 0 1.232-1.003 2.234-2.231 2.234s-2.23-1.004-2.23-2.23l-3.851-.912-1.467 4.477c2.65.105 5.047.854 6.844 2.021.494-.464 1.144-.719 1.833-.719 1.498 0 2.718 1.213 2.718 2.711 0 .987-.54 1.886-1.378 2.365.029.255.059.494.059.749-.015 3.938-4.806 7.143-10.72 7.143l-.034.009zm8.179-19.187c-.74 0-1.34.599-1.34 1.338 0 .738.6 1.34 1.34 1.34.732 0 1.33-.6 1.33-1.334 0-.733-.598-1.332-1.347-1.332l.017-.012z" />
|
||||
</svg>
|
||||
),
|
||||
people: () => (
|
||||
<svg
|
||||
aria-labelledby="simpleicons-reddit-icon"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title id="simpleicons-reddit-icon">Reddit icon</title>
|
||||
<path d="M2.204 14.049c-.06.276-.091.56-.091.847 0 3.443 4.402 6.249 9.814 6.249 5.41 0 9.812-2.804 9.812-6.249 0-.274-.029-.546-.082-.809l-.015-.032c-.021-.055-.029-.11-.029-.165-.302-1.175-1.117-2.241-2.296-3.103-.045-.016-.088-.039-.126-.07-.026-.02-.045-.042-.067-.064-1.792-1.234-4.356-2.008-7.196-2.008-2.815 0-5.354.759-7.146 1.971-.014.018-.029.033-.049.049-.039.033-.084.06-.13.075-1.206.862-2.042 1.937-2.354 3.123 0 .058-.014.114-.037.171l-.008.015zm9.773 5.441c-1.794 0-3.057-.389-3.863-1.197-.173-.174-.173-.457 0-.632.176-.165.46-.165.635 0 .63.629 1.685.943 3.228.943 1.542 0 2.591-.3 3.219-.929.165-.164.45-.164.629 0 .165.18.165.465 0 .645-.809.808-2.065 1.198-3.862 1.198l.014-.028zm-3.606-7.573c-.914 0-1.677.765-1.677 1.677 0 .91.763 1.65 1.677 1.65s1.651-.74 1.651-1.65c0-.912-.739-1.677-1.651-1.677zm7.233 0c-.914 0-1.678.765-1.678 1.677 0 .91.764 1.65 1.678 1.65s1.651-.74 1.651-1.65c0-.912-.739-1.677-1.651-1.677zm4.548-1.595c1.037.833 1.8 1.821 2.189 2.904.45-.336.719-.864.719-1.449 0-1.002-.815-1.816-1.818-1.816-.399 0-.778.129-1.09.363v-.002zM2.711 9.963c-1.003 0-1.817.816-1.817 1.818 0 .543.239 1.048.644 1.389.401-1.079 1.172-2.053 2.213-2.876-.302-.21-.663-.329-1.039-.329v-.002zm9.217 12.079c-5.906 0-10.709-3.205-10.709-7.142 0-.275.023-.544.068-.809C.494 13.598 0 12.729 0 11.777c0-1.496 1.227-2.713 2.725-2.713.674 0 1.303.246 1.797.682 1.856-1.191 4.357-1.941 7.112-1.992l1.812-5.524.404.095s.016 0 .016.002l4.223.993c.344-.798 1.138-1.36 2.065-1.36 1.229 0 2.231 1.004 2.231 2.234 0 1.232-1.003 2.234-2.231 2.234s-2.23-1.004-2.23-2.23l-3.851-.912-1.467 4.477c2.65.105 5.047.854 6.844 2.021.494-.464 1.144-.719 1.833-.719 1.498 0 2.718 1.213 2.718 2.711 0 .987-.54 1.886-1.378 2.365.029.255.059.494.059.749-.015 3.938-4.806 7.143-10.72 7.143l-.034.009zm8.179-19.187c-.74 0-1.34.599-1.34 1.338 0 .738.6 1.34 1.34 1.34.732 0 1.33-.6 1.33-1.334 0-.733-.598-1.332-1.347-1.332l.017-.012z" />
|
||||
</svg>
|
||||
),
|
||||
nature: () => (
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M8 16c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zM8 1.5c3.59 0 6.5 2.91 6.5 6.5s-2.91 6.5-6.5 6.5-6.5-2.91-6.5-6.5 2.91-6.5 6.5-6.5zM4 5c0-0.552 0.448-1 1-1s1 0.448 1 1-0.448 1-1 1-1-0.448-1-1zM10 5c0-0.552 0.448-1 1-1s1 0.448 1 1-0.448 1-1 1-1-0.448-1-1z" />
|
||||
<path d="M10.561 8.439c-0.586-0.586-1.536-0.586-2.121 0s-0.586 1.536 0 2.121c0.019 0.019 0.038 0.037 0.058 0.055 1.352 1.227 4.503-0.029 4.503-1.615-0.969 0.625-1.726 0.153-2.439-0.561z" />
|
||||
<path d="M5.439 8.439c0.586-0.586 1.536-0.586 2.121 0s0.586 1.536 0 2.121c-0.019 0.019-0.038 0.037-0.058 0.055-1.352 1.227-4.503-0.029-4.503-1.615 0.969 0.625 1.726 0.153 2.439-0.561z" />
|
||||
</svg>
|
||||
),
|
||||
foods: () => (
|
||||
<svg
|
||||
aria-labelledby="simpleicons-jira-icon"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title id="simpleicons-jira-icon">Jira icon</title>
|
||||
<path d="M23.323 11.33L13.001 1 12 0 4.225 7.775.67 11.33a.96.96 0 0 0 0 1.347l7.103 7.103L12 24l7.771-7.771.121-.121 3.431-3.431a.945.945 0 0 0 0-1.347zM12 15.551L8.449 12 12 8.453 15.548 12 12 15.551z" />
|
||||
</svg>
|
||||
),
|
||||
activity: () => (
|
||||
<img src="https://github.githubassets.com/images/icons/emoji/shipit.png" />
|
||||
),
|
||||
places: () => (
|
||||
<svg
|
||||
aria-labelledby="simpleicons-stackoverflow-icon"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title id="simpleicons-stackoverflow-icon">
|
||||
Stack Overflow icon
|
||||
</title>
|
||||
<path d="M18.986 21.865v-6.404h2.134V24H1.844v-8.539h2.13v6.404h15.012zM6.111 19.731H16.85v-2.137H6.111v2.137zm.259-4.852l10.48 2.189.451-2.07-10.478-2.187-.453 2.068zm1.359-5.056l9.705 4.53.903-1.95-9.706-4.53-.902 1.936v.014zm2.715-4.785l8.217 6.855 1.359-1.62-8.216-6.853-1.35 1.617-.01.001zM15.751 0l-1.746 1.294 6.405 8.604 1.746-1.294L15.749 0h.002z" />
|
||||
</svg>
|
||||
),
|
||||
objects: () => (
|
||||
<svg
|
||||
aria-labelledby="simpleicons-500px-icon"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<title id="simpleicons-500px-icon">Atlassian icon</title>
|
||||
<path d="M19.31 23.957H15.71a1.26 1.26 0 0 1-1.312-.792c-1.332-2.665-2.78-5.288-3.987-8.046a15.25 15.25 0 0 1 .885-14.47c.166-.281.52-.625.791-.625s.593.375.74.666q5.444 10.89 10.898 21.788c.542 1.041.292 1.468-.905 1.479zm-14.573 0H1.04c-1.041 0-1.27-.417-.812-1.333q2.8-5.538 5.549-11.055c.5-1.041.895-1.041 1.592-.177a12.221 12.221 0 0 1 2.51 11.17c-.344 1.322-.532 1.405-1.864 1.405z" />
|
||||
</svg>
|
||||
),
|
||||
symbols: () => (
|
||||
<svg
|
||||
aria-labelledby="simpleicons-hipchat-icon"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title id="simpleicons-hipchat-icon">HipChat icon</title>
|
||||
<path d="M19.736 19.056s.103-.073.267-.198C22.46 16.958 24 14.203 24 11.139 24 5.424 18.627.787 12.003.787 5.377.787 0 5.424 0 11.139c0 5.717 5.371 10.356 11.998 10.356.847 0 1.694-.073 2.524-.228l.262-.045c1.683 1.092 4.139 1.99 6.288 1.99.665 0 .978-.546.552-1.104-.648-.795-1.541-2.068-1.888-3.052zm-1.462-4.526c-.716 1.069-2.934 2.889-6.254 2.889h-.046c-3.328 0-5.543-1.831-6.254-2.889a1.137 1.137 0 0 1-.273-.574.49.49 0 0 1 .447-.526c.008-.003.014-.003.021-.003.117.006.23.043.328.111a9.137 9.137 0 0 0 5.754 2.056 8.805 8.805 0 0 0 5.76-2.059.461.461 0 0 1 .313-.122c.267 0 .478.213.483.475a1.321 1.321 0 0 1-.268.643h-.011z" />
|
||||
</svg>
|
||||
),
|
||||
flags: () => (
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M4.75 9.5c0 1.795 1.455 3.25 3.25 3.25s3.25-1.455 3.25-3.25-1.455-3.25-3.25-3.25-3.25 1.455-3.25 3.25zM15 4h-3.5c-0.25-1-0.5-2-1.5-2h-4c-1 0-1.25 1-1.5 2h-3.5c-0.55 0-1 0.45-1 1v9c0 0.55 0.45 1 1 1h14c0.55 0 1-0.45 1-1v-9c0-0.55-0.45-1-1-1zM8 13.938c-2.451 0-4.438-1.987-4.438-4.438s1.987-4.438 4.438-4.438c2.451 0 4.438 1.987 4.438 4.438s-1.987 4.438-4.438 4.438zM15 7h-2v-1h2v1z" />
|
||||
</svg>
|
||||
),
|
||||
custom: () => (
|
||||
<svg
|
||||
aria-labelledby="simpleicons-trello-icon"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title id="simpleicons-trello-icon">Trello icon</title>
|
||||
<path d="M21 0H3C1.343 0 0 1.343 0 3v18c0 1.656 1.343 3 3 3h18c1.656 0 3-1.344 3-3V3c0-1.657-1.344-3-3-3zM10.44 18.18c0 .795-.645 1.44-1.44 1.44H4.56c-.795 0-1.44-.646-1.44-1.44V4.56c0-.795.645-1.44 1.44-1.44H9c.795 0 1.44.645 1.44 1.44v13.62zm10.44-6c0 .794-.645 1.44-1.44 1.44H15c-.795 0-1.44-.646-1.44-1.44V4.56c0-.795.646-1.44 1.44-1.44h4.44c.795 0 1.44.645 1.44 1.44v7.62z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
))
|
||||
|
||||
.add('Custom skin emoji', () => (
|
||||
<Picker
|
||||
native={boolean('Unicode', true)}
|
||||
emojiSize={24}
|
||||
skinEmoji={text('Skin Preview Icon', 'v')}
|
||||
/>
|
||||
))
|
||||
|
||||
storiesOf('Emoji', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add('default', () => (
|
||||
.add('Default', () => (
|
||||
<Emoji
|
||||
native={boolean('Unicode', true)}
|
||||
set={select('Emoji pack', SETS, SETS[0])}
|
||||
|
@ -54,23 +218,84 @@ storiesOf('Emoji', module)
|
|||
size={number('Emoji size', 64)}
|
||||
skin={number('Skin tone', 1)}
|
||||
html={boolean('HTML', false)}
|
||||
fallback={(emoji) => {
|
||||
return `:${emoji.short_names[0]}:`
|
||||
fallback={(emoji, props) => {
|
||||
return emoji ? `:${emoji.short_names[0]}:` : props.emoji
|
||||
}}
|
||||
/>
|
||||
));
|
||||
))
|
||||
|
||||
storiesOf('Headless Search', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add('default', () => {
|
||||
let results = emojiIndex.search(text('Search', 'christmas'), { custom: CUSTOM_EMOJIS })
|
||||
if (!results) { return null }
|
||||
.add('Default', () => {
|
||||
let results = emojiIndex.search(text('Search', 'christmas'), {
|
||||
custom: CUSTOM_EMOJIS,
|
||||
})
|
||||
if (!results) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <div>
|
||||
{results.map((emoji) => {
|
||||
return <span key={emoji.id} style={{ marginLeft: '1.4em' }}>
|
||||
<Emoji native={true} emoji={emoji} size={48} />
|
||||
</span>
|
||||
})}
|
||||
</div>
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
{results.map((emoji) => {
|
||||
return (
|
||||
<span key={emoji.id} style={{ marginLeft: '1.4em' }}>
|
||||
<Emoji native={true} emoji={emoji} size={48} />
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
.add('With skin tone from store', () => {
|
||||
const nimbleEmojiIndex = new NimbleEmojiIndex(data)
|
||||
let results = nimbleEmojiIndex.search(text('Search', 'thumbs'), {
|
||||
custom: CUSTOM_EMOJIS,
|
||||
})
|
||||
if (!results) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{results.map((emoji) => {
|
||||
return (
|
||||
<span key={emoji.id} style={{ marginLeft: '1.4em' }}>
|
||||
<Emoji
|
||||
native={true}
|
||||
emoji={emoji}
|
||||
skin={emoji.skin || 1}
|
||||
size={48}
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
storiesOf('Get emoji data from Native', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add('Default', () => {
|
||||
const emojiData = getEmojiDataFromNative(
|
||||
text('Unicode', '🏋🏿♂️'),
|
||||
select('Emoji pack', SETS, SETS[0]),
|
||||
data,
|
||||
)
|
||||
if (!emojiData) {
|
||||
return <div>Couldn`t find any emoji data from native...</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Emoji
|
||||
emoji={emojiData}
|
||||
set={select('Emoji pack', SETS, SETS[0])}
|
||||
skin={emojiData.skin || 1}
|
||||
size={48}
|
||||
/>
|
||||
|
||||
<pre>emojiData: {JSON.stringify(emojiData, null, 2)}</pre>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// Simple smoke-test to make sure that SSR is working correctly
|
||||
const ReactDOMServer = require('react-dom/server')
|
||||
const React = require('react')
|
||||
const { Picker, NimblePicker } = require('../dist/index.js')
|
||||
const data = require('../data/all.json')
|
||||
|
||||
function testPicker() {
|
||||
const element = React.createElement(Picker)
|
||||
const string = ReactDOMServer.renderToString(element)
|
||||
|
||||
if (typeof string !== 'string') {
|
||||
throw new Error('expected a string')
|
||||
}
|
||||
}
|
||||
|
||||
function testNimblePicker() {
|
||||
const element = React.createElement(NimblePicker, { data })
|
||||
const string = ReactDOMServer.renderToString(element)
|
||||
|
||||
if (typeof string !== 'string') {
|
||||
throw new Error('expected a string')
|
||||
}
|
||||
}
|
||||
|
||||
testPicker()
|
||||
testNimblePicker()
|
Loading…
Reference in New Issue