Compare commits

...

76 Commits

Author SHA1 Message Date
mashirozx d496014be7 Release 3.0.1-k 2021-11-29 15:57:01 +08:00
mashirozx dac9386e73 Disable img context menu... 2021-10-26 15:30:41 +08:00
mashirozx 818aba94a0 Disable ContextMenu 2021-10-26 14:40:45 +08:00
mashirozx 7edf171664 Add custom emoji lazyload 2021-10-26 12:28:34 +08:00
Ross Gardiner fe28ab637b Correct date of v3.0.1 in CHANGELOG 2021-10-26 11:18:10 +08:00
Etienne Lemay 5912b6b902 Release v3.0.1 2021-10-26 11:18:10 +08:00
Etienne Lemay 37c3c6267c Keep using unique key for custom category buttons 2021-10-26 11:18:09 +08:00
Erin Hinson ca6a7fd74b fix aria-label for custom button 2021-10-26 11:18:09 +08:00
Matt Krick 612dae7b08 safely access this.input.value 2021-10-26 11:18:09 +08:00
Sagar Jain 3a97898c5b
Update package.json 2021-01-12 21:32:26 +05:30
Sagar Jain 4f8ef7255a
Update package.json 2021-01-12 21:31:25 +05:30
Etienne Lemay ca3d4e5f0e
Release v3.0.0 2020-03-16 16:14:39 -04:00
Etienne Lemay cd29d5b9f6
preventDefault when handling keyboard event in SkinsDot 2020-03-16 15:16:37 -04:00
Etienne Lemay 3b6fd1516f
Update gh-pages 2020-03-16 14:48:40 -04:00
Etienne Lemay 2dacd30dc8
Don’t use `getDerivedStateFromProps`
This is pretty much considered an anti-pattern (https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html), especially for a PureComponent.
2020-03-16 14:41:30 -04:00
Etienne Lemay b548c38624
Add min values in stories 2020-03-16 14:30:53 -04:00
Etienne Lemay d1138c00e8
Update theme handling [Fix #404]
- Defaults to “light”
- “auto” picks light/dark based on `prefers-color-scheme: dark` media query (and actually updates automatically)
2020-03-16 14:09:14 -04:00
Etienne Lemay c41fc5ec7a
Add `enableFrequentEmojiSort` to README 2020-03-16 11:49:14 -04:00
Etienne Lemay 0e299ff4dd
Update gh-pages 2020-03-16 11:46:55 -04:00
Etienne Lemay 17cf50f7ba
Add an option to disable use of <button>
i.e. Latest version of Chrome (~v80) can’t render Pirate Flag (🏴‍☠️) on a <button>
2020-03-16 11:44:02 -04:00
Etienne Lemay 22ffd5b85e
Include stories/ in prettier script 2020-03-16 11:14:08 -04:00
Etienne Lemay b8fad36c6d
Merge pull request #417 from SaraRandolph/sara.randolph/enhancement/disable_frequent_emoji_sort
enhancement: functionality to disable the frequent emoji sorting
2020-03-16 11:11:54 -04:00
Etienne Lemay 56ae7b49c5
Don’t sort frequent emojis by default 2020-03-16 11:08:13 -04:00
SaraRandolph 6ca158bb36 forgot to run prettier, now I did 2020-03-16 11:03:31 -04:00
SaraRandolph cdb6c26a08 adds functionality to disable the frequent emoji sorting, updates storybook for visibility 2020-03-16 11:03:31 -04:00
Etienne Lemay 769b55c875 Update gh-pages 2020-03-16 10:32:38 -04:00
Etienne Lemay dc4ca683d2 Add .prettierignore 2020-03-16 10:06:09 -04:00
Etienne Lemay 16ca493f3c [cleanup] 2020-03-16 10:06:09 -04:00
Etienne Lemay cf4a1043f7
Merge pull request #410 from rugk/fixWindowsWitdh
Fix x overflow on Windows with native emojis
2020-03-16 09:15:32 -04:00
Etienne Lemay 5c083a8026 Merge branch 'feature-unicode-12' 2020-03-16 09:12:25 -04:00
Etienne Lemay f8ce5a6814 [cleanup] 2020-03-16 09:09:23 -04:00
Etienne Lemay fcae7a913b Merge the 2 new categories into a single one 2020-03-16 09:09:23 -04:00
Thomas Piard 57cabf6f75 size limit 2020-03-16 09:09:23 -04:00
Thomas Piard 9bab24f3c6 prettier 2020-03-16 09:09:23 -04:00
Thomas Piard 4404e71264 restore change 2020-03-16 09:09:23 -04:00
Thomas Piard 3941549f6a fix test 2020-03-16 09:09:23 -04:00
Thomas Piard a253148b86 Update data and docs 2020-03-16 09:09:22 -04:00
Thomas Piard cdb74f28c7 Bump emoji-datasource to 5.*, remove emojione and messenger support 2020-03-16 09:09:22 -04:00
Etienne Lemay 113b07abcf
Merge pull request #402 from missive/nolan/fix-json
refactor: remove _JSON
2020-03-13 08:11:01 -04:00
Etienne Lemay bfada8f5c1
Merge pull request #401 from missive/nolan/test-ssr
fix: remove rAF polyfill, add SSR test
2020-03-13 08:10:41 -04:00
Etienne Lemay 39c2c9d6ee
Merge pull request #397 from missive/nolan/update-babel-squashed
chore: upgrade to babel v7
2020-03-13 08:10:17 -04:00
rugk e57118c6f3 Fix x overflow on Windows with native emojis
Fixes https://github.com/missive/emoji-mart/issues/409
2020-01-23 10:25:01 +01:00
Nolan Lawson 835c2e9c36 fix: remove rAF polyfill, add SSR test 2020-01-12 09:59:07 -08:00
Nolan Lawson c8305f6013 test: test bundle size in CI 2020-01-12 09:57:33 -08:00
Nolan Lawson 97f6ffde2d refactor: remove _JSON 2019-12-30 09:07:54 -08:00
Nolan Lawson 0bd369144b chore: upgrade to babel v7 2019-12-29 13:39:57 -08:00
Nolan Lawson 99eae3605d test: add test for emoji-index.js 2019-12-29 11:52:24 -08:00
Nolan Lawson 6bb1932db8 fix: remove core-js dependency 2019-12-29 11:52:13 -08:00
Etienne Lemay 85577c0b58
Release v2.11.2 2019-12-23 09:40:28 -05:00
Etienne Lemay 7b2f760df2
Update README 2019-12-23 09:33:00 -05:00
Etienne Lemay 3440a74328
Update gh-pages 2019-12-23 09:12:55 -05:00
Etienne Lemay f1a988ca4b
Improve anchors :focus state 2019-12-23 09:09:00 -05:00
Etienne Lemay 2860851c0b
Fix :hover state on anchors 2019-12-23 09:04:27 -05:00
Etienne Lemay e66be9dc4e
Add theme selection to gh-pages 2019-12-23 08:51:53 -05:00
Etienne Lemay e39c1e53d8
Improve dark theme UI 2019-12-23 08:50:49 -05:00
Etienne Lemay c778bc6084
Run prettier on docs/index.js 2019-12-23 08:06:53 -05:00
Etienne Lemay ff9d416300 Update gh-pages 2019-12-23 08:04:11 -05:00
Nolan Lawson 61c0bd4e4e fix: remove _JSON 2019-12-21 11:18:30 -08:00
Nolan Lawson 7a025243b4 test: add docs and test for customCategory 2019-12-21 10:24:49 -08:00
Eugen Rochko 1a9d5f97b6 Add support for more than one custom category
Fix #224
2019-12-21 10:24:49 -08:00
Nolan Lawson 8cff39f6fd fix: dark mode CSS tweaks, add storybook/matchMedia/docs 2019-12-21 09:49:29 -08:00
Mohan Raj 848fc76396 feat: Add Dark Mode 2019-12-21 09:49:29 -08:00
dependabot[bot] 830c69a4e1 chore(deps): bump lodash from 4.17.11 to 4.17.15 (#390)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.15.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.15)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-21 09:18:25 -08:00
dependabot[bot] 1b69530f53 chore(deps): bump handlebars from 4.1.0 to 4.5.3 (#389)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.0 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.0...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-21 09:18:16 -08:00
dependabot[bot] 6c60ac1242 chore(deps): bump lodash-es from 4.17.11 to 4.17.15 (#388)
Bumps [lodash-es](https://github.com/lodash/lodash) from 4.17.11 to 4.17.15.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.15)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-21 09:18:06 -08:00
dependabot[bot] 364ae72ba3 chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 (#387)
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-21 09:17:53 -08:00
Carl Tessier f3387cdce2 fix: gracefully ignore bad JSON in localstorage (#385)
Don't crash (catch the exception) if the localstorage value does not contain valid JSON.
2019-12-21 09:17:41 -08:00
Peder Johnsen edcd64b101 docs: Move `With custom data` to correct position (#377)
Looks like the `With custom data` section of `Headless search` got pushed down by the `Get emoji data from Native` stuff.
2019-12-21 09:13:20 -08:00
Hiro-Aki Hotta 208099c2dc fix: Use getDerivedStateFromProps instead of componentWillReceiveProps (#372)
* use getDerivedStateFromProps instead of componentWillReceiveProps

* code formatting
2019-12-21 08:43:35 -08:00
Ryan McCue f10510b262 fix: Ensure emoji backgrounds do not tile (#362) 2019-12-21 08:41:24 -08:00
Alex Brioux 76ac008169 Fix: Allowing emoji selection on enter (#386) 2019-12-21 08:38:25 -08:00
Nolan Lawson 3576091fc0
fix: ensure unique keys for React list (#352)
fixes #327
2019-07-03 08:00:02 -07:00
Xavier Shay 956aaa91f3 fix: Deterministic sorting of search results. (#343)
* Deterministic sorting of search results.

This is important for reliable tests, e.g. if you are snapshotting views
and comparing to reference images.

* fix prettier
2019-06-29 07:53:46 -07:00
Nolan Lawson a0ce9d8122
docs: document how to remove the footer (#330)
fixes #325
2019-06-29 07:49:01 -07:00
Nolan Lawson cdd3229de6
test: add basic skins test (#315) 2019-06-29 07:48:50 -07:00
rugk f8322a8c5d docs: Add tip for l10n to use CLDR (#344)
* Add tip for l10n to use CLDR

This prevents unnecessary work and prevents some translation errors that can easily occur, otherwise. (e.g. it's not that easy to translate the skin tones correctly)

* remove smart quotes
2019-06-29 07:47:40 -07:00
48 changed files with 15082 additions and 12556 deletions

View File

@ -1,66 +0,0 @@
{
"presets": ["react"],
"plugins": [
"check-es2015-constants",
"transform-object-rest-spread",
"transform-runtime",
[
"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",
"babel-runtime/helpers/classCallCheck": "./src/polyfills/classCallCheck",
"babel-runtime/core-js/object/keys": "./src/polyfills/keys"
}
}
],
[
"transform-define", "scripts/define.js"
]
],
"env": {
"legacy-es": {
"plugins": [
"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"
]
},
"legacy-cjs": {
"plugins": [
"transform-es2015-modules-commonjs"
]
},
"test": {
"presets": [
[
"env",
{
"targets": {
"node": "current"
}
}
]
]
}
}
}

2
.prettierignore Normal file
View File

@ -0,0 +1,2 @@
*.md
*.css

View File

@ -5,6 +5,8 @@ sudo: false
script: yarn test
before_script:
- yarn prettier:check
- yarn test:size
- yarn test:ssr
branches:
only:
- master

View File

@ -1,8 +1,63 @@
### Changelog
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
All notable changes to this project will be documented in this file.
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [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)
@ -10,8 +65,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
- 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)
- attempting to fix the prettier issue [`14c5d4f`](https://github.com/missive/emoji-mart/commit/14c5d4f2b42fc2749de7f670133a160cbfb537fd)
#### [v2.11.0](https://github.com/missive/emoji-mart/compare/v2.10.0...v2.11.0)

View File

@ -2,7 +2,7 @@
<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/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="338" alt="picker" src="https://user-images.githubusercontent.com/436043/43481399-d9b60acc-94d3-11e8-9b3b-e5f2db8f0bd1.png">
<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>
@ -17,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' }} />
@ -33,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) => {}` |
@ -40,13 +41,15 @@ import { Picker } from 'emoji-mart'
| **perLine** | | `9` | Number of emojis per line. While theres no minimum or maximum, this will affect the pickers 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 |
@ -65,7 +68,8 @@ 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',
@ -86,38 +90,36 @@ skintones: {
},
```
**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 | Size (`sheetSize: 16`) | Size (`sheetSize: 20`) | Size (`sheetSize: 32`) | Size (`sheetSize: 64`) |
| --------- | ---------------------- | ---------------------- | ---------------------- | ---------------------- |
| apple | 334 KB | 459 KB | 1.08 MB | 2.94 MB |
| emojione | 315 KB | 435 KB | 1020 KB | 2.33 MB |
| facebook | 322 KB | 439 KB | 1020 KB | 2.50 MB |
| google | 301 KB | 409 KB | 907 KB | 2.17 MB |
| messenger | 325 KB | 449 KB | 1.05 MB | 2.69 MB |
| twitter | 288 KB | 389 KB | 839 KB | 1.82 MB |
| 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 | 570 KB |
| apple | 484 KB |
| emojione | 485 KB |
| facebook | 421 KB |
| google | 483 KB |
| messenger | 197 KB |
| twitter | 484 KB |
| 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/messenger.json'
import data from 'emoji-mart/data/google.json'
import { NimblePicker } from 'emoji-mart'
<NimblePicker set='messenger' data={data} />
<NimblePicker set='google' data={data} />
```
#### Examples of `emoji` object:
@ -163,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 |
@ -175,7 +177,7 @@ import { Emoji } from 'emoji-mart'
| **onLeave** | | | Params: `(emoji, event) => {}` |
| **onOver** | | | Params: `(emoji, event) => {}` |
| [**fallback**](#unsupported-emojis-fallback) | | | Params: `(emoji, props) => {}` |
| **set** | | `apple` | The emoji set: `'apple', 'google', 'twitter', 'emojione'` |
| **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` |
@ -183,13 +185,13 @@ import { Emoji } from 'emoji-mart'
| [**html**](#using-with-dangerouslysetinnerhtml) | | `false` | Returns an HTML string to use with `dangerouslySetInnerHTML` |
#### Unsupported emojis fallback
Certain sets dont support all emojis (i.e. Messenger & Facebook dont support `:shrug:`). By default the Emoji component will not render anything so that the emojis dont 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 dont support all emojis. By default the Emoji component will not render anything so that the emojis dont 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, props) => {
@ -243,7 +245,8 @@ const customEmojis = [
text: '',
emoticons: [],
keywords: ['github'],
imageUrl: 'https://github.githubassets.com/images/icons/emoji/octocat.png'
imageUrl: 'https://github.githubassets.com/images/icons/emoji/octocat.png',
customCategory: 'GitHub'
},
{
name: 'Test Flag',
@ -263,6 +266,9 @@ const customEmojis = [
<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.
@ -301,6 +307,15 @@ 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.
@ -331,15 +346,6 @@ emojiData: {
}
```
### With custom data
```js
import data from 'emoji-mart/datasets/messenger'
import { NimbleEmojiIndex } from 'emoji-mart'
let emojiIndex = new NimbleEmojiIndex(data)
emojiIndex.search('christmas')
```
## 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.
@ -399,7 +405,7 @@ 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">

65
babel.config.js Normal file
View File

@ -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',
}
},
],
],
},
},
}

View File

@ -37,7 +37,6 @@
flex-direction: row;
justify-content: space-between;
padding: 0 6px;
color: #858585;
line-height: 0;
}
@ -45,6 +44,7 @@
position: relative;
display: block;
flex: 1 1 auto;
color: #858585;
text-align: center;
padding: 12px 4px;
overflow: hidden;
@ -54,7 +54,9 @@
background: none;
border: none;
}
.emoji-mart-anchor:focus { outline: 0 }
.emoji-mart-anchor:hover,
.emoji-mart-anchor:focus,
.emoji-mart-anchor-selected {
color: #464646;
}
@ -78,13 +80,14 @@
.emoji-mart-anchors svg,
.emoji-mart-anchors img {
fill: #858585;
fill: currentColor;
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 */
@ -134,7 +137,7 @@
}
.emoji-mart-category .emoji-mart-emoji:hover:before {
z-index: 0;
z-index: -1;
content: "";
position: absolute;
top: 0; left: 0;
@ -184,7 +187,7 @@
}
.emoji-mart-emoji-native {
font-family: "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "EmojiOne Color", "Android Emoji";
font-family: "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "Android Emoji";
}
.emoji-mart-no-results {
@ -413,4 +416,46 @@
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

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

View File

@ -37,7 +37,6 @@
flex-direction: row;
justify-content: space-between;
padding: 0 6px;
color: #858585;
line-height: 0;
}
@ -45,6 +44,7 @@
position: relative;
display: block;
flex: 1 1 auto;
color: #858585;
text-align: center;
padding: 12px 4px;
overflow: hidden;
@ -54,7 +54,9 @@
background: none;
border: none;
}
.emoji-mart-anchor:focus { outline: 0 }
.emoji-mart-anchor:hover,
.emoji-mart-anchor:focus,
.emoji-mart-anchor-selected {
color: #464646;
}
@ -78,13 +80,14 @@
.emoji-mart-anchors svg,
.emoji-mart-anchors img {
fill: #858585;
fill: currentColor;
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 */
@ -184,7 +187,7 @@
}
.emoji-mart-emoji-native {
font-family: "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "EmojiOne Color", "Android Emoji";
font-family: "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "Android Emoji";
}
.emoji-mart-no-results {
@ -413,4 +416,46 @@
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;
}

View File

@ -1,37 +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://github.githubassets.com/images/icons/emoji/octocat.png'
imageUrl: 'https://github.githubassets.com/images/icons/emoji/octocat.png',
},
{
name: 'Squirrel',
short_names: ['shipit', 'squirrel'],
keywords: ['github'],
imageUrl: 'https://github.githubassets.com/images/icons/emoji/shipit.png'
},
{
name: 'Test Flag',
short_names: ['test'],
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,
imageUrl: 'https://github.githubassets.com/images/icons/emoji/shipit.png',
},
]
@ -41,49 +30,73 @@ 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 sets">
{['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>
)
}
}

View File

@ -1,90 +1,89 @@
{
"name": "emoji-mart",
"version": "2.11.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": {
"prop-types": "^15.6.0"
},
"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",
"auto-changelog": "1.12.0",
"babel-cli": "^6.0.0",
"babel-core": "^6.0.0",
"babel-jest": "^23.6.0",
"babel-loader": "^7.0.0",
"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-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "6.6.0",
"babel-preset-react": "6.5.0",
"babel-runtime": "^6.26.0",
"emoji-datasource": "4.0.4",
"emojilib": "^2.2.1",
"inflection": "1.10.0",
"jest": "^23.0.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": {
"changelog": "auto-changelog",
"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 --copy-files --ignore '**/*.test.js'",
"build:es": "BABEL_ENV=legacy-es babel src --out-dir dist-es --copy-files --ignore '**/*.test.js'",
"build:modern": "babel src --out-dir dist-modern --copy-files --ignore '**/*.test.js'",
"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=cjs babel src --watch --out-dir dist --copy-files --ignore '**/*.test.js'",
"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",
"prepublishOnly": "npm run build",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"prettier": "prettier --write \"{src,scripts}/**/*.js\"",
"prettier:check": "prettier --check \"{src,scripts}/**/*.js\"",
"prepare": "npm run build:dist"
},
"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"
}
]
}

View File

@ -1,5 +1,5 @@
const build = require('./build')
const sets = ['apple', 'emojione', 'facebook', 'google', 'messenger', 'twitter']
const sets = ['apple', 'facebook', 'google', 'twitter']
build({ output: 'data/all.json' })

View File

@ -6,7 +6,8 @@ var fs = require('fs'),
var { compress } = require('../dist/utils/data')
var categories = [
['Smileys & People', 'people'],
['Smileys & Emotion', 'smileys'],
['People & Body', 'people'],
['Animals & Nature', 'nature'],
['Food & Drink', 'foods'],
['Activities', 'activity'],
@ -16,7 +17,7 @@ var categories = [
['Flags', 'flags'],
]
var sets = ['apple', 'emojione', 'facebook', 'google', 'messenger', 'twitter']
var sets = ['apple', 'facebook', 'google', 'twitter']
module.exports = (options) => {
delete require.cache[require.resolve('emoji-datasource')]
@ -118,6 +119,18 @@ module.exports = (options) => {
})
.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
})

View File

@ -1,6 +0,0 @@
var pack = require('../package.json')
module.exports = {
'process.env.NODE_ENV': 'production',
EMOJI_DATASOURCE_VERSION: pack.devDependencies['emoji-datasource'],
}

View File

@ -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)
})

View File

@ -37,11 +37,13 @@ export default class Anchors extends React.PureComponent {
return null
}
const iconId = id.startsWith('custom-') ? 'custom' : id
return (
<button
key={id}
aria-label={i18n.categories[id]}
title={i18n.categories[id]}
aria-label={i18n.categories[iconId]}
title={i18n.categories[iconId]}
data-index={i}
type={'button'}
onClick={this.handleClick}
@ -51,7 +53,7 @@ export default class Anchors extends React.PureComponent {
style={{ color: isSelected ? color : null }}
>
<div className="emoji-mart-anchor-icon">
{icons.categories[id]()}
{icons.categories[iconId]()}
</div>
<span
className="emoji-mart-anchor-bar"

View File

@ -1,242 +1,291 @@
import React from 'react'
import PropTypes from 'prop-types'
import frequently from '../utils/frequently'
import { getData } from '../utils'
import NimbleEmoji from './emoji/nimble-emoji'
import NotFound from './not-found'
export default class Category extends React.Component {
constructor(props) {
super(props)
this.data = props.data
this.setContainerRef = this.setContainerRef.bind(this)
this.setLabelRef = this.setLabelRef.bind(this)
}
componentDidMount() {
this.margin = 0
this.minMargin = 0
this.memoizeSize()
}
shouldComponentUpdate(nextProps, nextState) {
var {
name,
perLine,
native,
hasStickyPosition,
emojis,
emojiProps,
} = this.props,
{ skin, size, set } = emojiProps,
{
perLine: nextPerLine,
native: nextNative,
hasStickyPosition: nextHasStickyPosition,
emojis: nextEmojis,
emojiProps: nextEmojiProps,
} = nextProps,
{ skin: nextSkin, size: nextSize, set: nextSet } = nextEmojiProps,
shouldUpdate = false
if (name == 'Recent' && perLine != nextPerLine) {
shouldUpdate = true
}
if (name == 'Search') {
shouldUpdate = !(emojis == nextEmojis)
}
if (
skin != nextSkin ||
size != nextSize ||
native != nextNative ||
set != nextSet ||
hasStickyPosition != nextHasStickyPosition
) {
shouldUpdate = true
}
return shouldUpdate
}
memoizeSize() {
if (!this.container) {
// probably this is a test environment, e.g. jest
this.top = 0
this.maxMargin = 0
return
}
var parent = this.container.parentElement
var { top, height } = this.container.getBoundingClientRect()
var { top: parentTop } = parent.getBoundingClientRect()
var { height: labelHeight } = this.label.getBoundingClientRect()
this.top = top - parentTop + parent.scrollTop
if (height == 0) {
this.maxMargin = 0
} else {
this.maxMargin = height - labelHeight
}
}
handleScroll(scrollTop) {
var margin = scrollTop - this.top
margin = margin < this.minMargin ? this.minMargin : margin
margin = margin > this.maxMargin ? this.maxMargin : margin
if (margin == this.margin) return
if (!this.props.hasStickyPosition) {
this.label.style.top = `${margin}px`
}
this.margin = margin
return true
}
getEmojis() {
var { name, emojis, recent, perLine } = this.props
if (name == 'Recent') {
let { custom } = this.props
let frequentlyUsed = recent || frequently.get(perLine)
if (frequentlyUsed.length) {
emojis = frequentlyUsed
.map((id) => {
const emoji = custom.filter((e) => e.id === id)[0]
if (emoji) {
return emoji
}
return id
})
.filter((id) => !!getData(id, null, null, this.data))
}
if (emojis.length === 0 && frequentlyUsed.length > 0) {
return null
}
}
if (emojis) {
emojis = emojis.slice(0)
}
return emojis
}
updateDisplay(display) {
var emojis = this.getEmojis()
if (!emojis || !this.container) {
return
}
this.container.style.display = display
}
setContainerRef(c) {
this.container = c
}
setLabelRef(c) {
this.label = c
}
render() {
var {
id,
name,
hasStickyPosition,
emojiProps,
i18n,
notFound,
notFoundEmoji,
} = this.props,
emojis = this.getEmojis(),
labelStyles = {},
labelSpanStyles = {},
containerStyles = {}
if (!emojis) {
containerStyles = {
display: 'none',
}
}
if (!hasStickyPosition) {
labelStyles = {
height: 28,
}
labelSpanStyles = {
position: 'absolute',
}
}
return (
<section
ref={this.setContainerRef}
className="emoji-mart-category"
aria-label={i18n.categories[id]}
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 */}
>
{i18n.categories[id]}
</span>
</div>
<ul className="emoji-mart-category-list">
{emojis &&
emojis.map((emoji) => (
<li key={emoji.id || emoji}>
{NimbleEmoji({ emoji: emoji, data: this.data, ...emojiProps })}
</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,
}
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,
}

View File

@ -1,220 +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',
}
}
} 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) {
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)}
aria-label={label}
title={title}
className={className}
{...Tag.props}
>
<span style={style}>{children}</span>
</Tag.name>
)
}
}
NimbleEmoji.propTypes /* remove-proptypes */ = {
...EmojiPropTypes,
data: PropTypes.object.isRequired,
}
NimbleEmoji.defaultProps = EmojiDefaultProps
export default NimbleEmoji
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

View File

@ -57,7 +57,40 @@ test('with custom emoji and tooltip', () => {
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')
})

View File

@ -1,5 +1,3 @@
import '../../vendor/raf-polyfill'
import React from 'react'
import PropTypes from 'prop-types'
@ -49,8 +47,9 @@ 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',
@ -65,25 +64,45 @@ export default class NimblePicker extends React.PureComponent {
this.data = props.data
this.i18n = deepMerge(I18N, props.i18n)
this.icons = deepMerge(icons, props.icons)
this.state = {
skin: props.skin || store.get('skin') || props.defaultSkin,
firstRender: true,
}
this.state = { firstRender: true }
this.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
@ -174,14 +193,7 @@ export default class NimblePicker 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() {
@ -203,6 +215,10 @@ export default class NimblePicker extends React.PureComponent {
clearTimeout(this.leaveTimeout)
clearTimeout(this.firstRenderTimeout)
if (this.darkMatchMedia) {
this.darkMatchMedia.removeListener(this.handleDarkMatchMediaChange)
}
}
testStickyPosition() {
@ -217,6 +233,24 @@ export default class NimblePicker 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) {
@ -224,7 +258,7 @@ export default class NimblePicker 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) {
@ -260,9 +294,11 @@ export default class NimblePicker 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
@ -280,7 +316,7 @@ export default class NimblePicker extends React.PureComponent {
handleScroll() {
if (!this.waitingForPaint) {
this.waitingForPaint = true
window.requestAnimationFrame(this.handleScrollPaint)
requestAnimationFrame(this.handleScrollPaint)
}
}
@ -384,7 +420,7 @@ export default class NimblePicker extends React.PureComponent {
this.handleSearch(null)
this.search.clear()
window.requestAnimationFrame(scrollToComponent)
requestAnimationFrame(scrollToComponent)
} else {
scrollToComponent()
}
@ -418,9 +454,9 @@ export default class NimblePicker extends React.PureComponent {
))
) {
this.handleEmojiSelect(emoji)
handled = true
}
handled = true
break
}
@ -474,37 +510,45 @@ export default class NimblePicker extends React.PureComponent {
render() {
var {
perLine,
emojiSize,
set,
sheetSize,
sheetColumns,
sheetRows,
style,
title,
emoji,
color,
native,
backgroundImageFn,
emojisToShowFilter,
showPreview,
showSkinTones,
emojiTooltip,
include,
exclude,
recent,
autoFocus,
skinEmoji,
notFound,
notFoundEmoji,
} = 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 (
<section
style={{ width: width, ...style }}
className="emoji-mart"
className={`emoji-mart emoji-mart-${theme}`}
aria-label={title}
onKeyDown={this.handleKeyDown}
>
@ -528,8 +572,9 @@ export default class NimblePicker extends React.PureComponent {
emojisToShowFilter={emojisToShowFilter}
include={include}
exclude={exclude}
custom={this.CUSTOM_CATEGORY.emojis}
custom={this.CUSTOM}
autoFocus={autoFocus}
maxResults={maxResults}
/>
<div
@ -555,7 +600,7 @@ export default class NimblePicker extends React.PureComponent {
}
custom={
category.id == this.RECENT_CATEGORY.id
? this.CUSTOM_CATEGORY.emojis
? this.CUSTOM
: undefined
}
emojiProps={{
@ -569,6 +614,7 @@ export default class NimblePicker extends React.PureComponent {
forceSize: native,
tooltip: emojiTooltip,
backgroundImageFn: backgroundImageFn,
useButton: useButton,
onOver: this.handleEmojiOver,
onLeave: this.handleEmojiLeave,
onClick: this.handleEmojiClick,

View File

@ -65,7 +65,9 @@ export default class Search extends React.PureComponent {
}
handleChange() {
this.search(this.input.value)
if (this.input) {
this.search(this.input.value)
}
}
handleKeyUp(e) {

View File

@ -14,6 +14,7 @@ export default class SkinsDot extends Skins {
handleKeyDown(event) {
// if either enter or space is pressed, then execute
if (event.keyCode === 13 || event.keyCode === 32) {
event.preventDefault()
this.handleClick(event)
}
}

View File

@ -1,8 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import NimbleEmoji from './emoji/nimble-emoji'
export default class Skins extends React.PureComponent {
constructor(props) {
super(props)

View File

@ -1,5 +0,0 @@
export default function(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function')
}
}

View File

@ -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
}
})()

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -1,38 +0,0 @@
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !{ toString: null }.propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor',
],
dontEnumsLength = dontEnums.length
export default function(obj) {
if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) {
throw new TypeError('Object.keys called on non-object')
}
var result = [],
prop,
i
for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop)
}
}
if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i])
}
}
}
return result
}

View File

@ -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
}

View File

@ -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
}

View File

@ -5,9 +5,7 @@ const mapping = {
has_img_apple: 'd',
has_img_google: 'e',
has_img_twitter: 'f',
has_img_emojione: 'g',
has_img_facebook: 'h',
has_img_messenger: 'i',
keywords: 'j',
sheet: 'k',
emoticons: 'l',

View File

@ -39,3 +39,13 @@ test('can search for woman-facepalming', () => {
'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')
})

View File

@ -181,7 +181,11 @@ export default class NimbleEmojiIndex {
var aScore = scores[a.id],
bScore = scores[b.id]
return aScore - bScore
if (aScore == bScore) {
return a.id.localeCompare(b.id)
} else {
return aScore - bScore
}
})
}

View File

@ -2,8 +2,6 @@ import { buildSearch } from './data'
import stringFromCodePoint from '../polyfills/stringFromCodePoint'
import { uncompress } from './data'
const _JSON = JSON
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],
@ -36,6 +35,7 @@ function sanitize(emoji) {
colons,
emoticons,
custom,
customCategory,
imageUrl,
}
}
@ -107,32 +107,34 @@ function getData(emoji, skin, set, data) {
emojiData.variations || (emojiData.variations = [])
if (emojiData.skin_variations && skin > 1) {
emojiData = JSON.parse(_JSON.stringify(emojiData))
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 (
(set &&
(variationData[`has_img_${set}`] == undefined ||
variationData[`has_img_${set}`])) ||
!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()
}

View File

@ -2,11 +2,12 @@ const EmojiDefaultProps = {
skin: 1,
set: 'apple',
sheetSize: 64,
sheetColumns: 52,
sheetRows: 52,
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`,
}
@ -23,6 +24,7 @@ const PickerDefaultProps = {
emoji: 'department_store',
color: '#ae65c5',
set: EmojiDefaultProps.set,
theme: 'light',
skin: null,
defaultSkin: EmojiDefaultProps.skin,
native: EmojiDefaultProps.native,
@ -32,7 +34,9 @@ const PickerDefaultProps = {
showPreview: true,
showSkinTones: true,
emojiTooltip: EmojiDefaultProps.tooltip,
useButton: EmojiDefaultProps.useButton,
autoFocus: false,
enableFrequentEmojiSort: false,
custom: [],
skinEmoji: '',
notFound: () => {},

View File

@ -10,18 +10,12 @@ const EmojiPropTypes = {
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',
'emojione',
'messenger',
'facebook',
]),
set: PropTypes.oneOf(['apple', 'google', 'twitter', 'facebook']),
size: PropTypes.number.isRequired,
emoji: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
}
@ -46,10 +40,13 @@ const PickerPropTypes = {
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,

View File

@ -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)
}
}
}

View File

@ -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)
}
})()

View File

@ -11,11 +11,18 @@ import {
color,
} from '@storybook/addon-knobs'
import { Picker, Emoji, emojiIndex, NimbleEmojiIndex, getEmojiDataFromNative } from '../dist'
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',
@ -31,6 +38,12 @@ const CUSTOM_EMOJIS = [
},
]
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', () => (
@ -39,16 +52,19 @@ storiesOf('Picker', module)
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')}
notFoundEmoji={text('Not found emoji', 'sleuth_or_spy')}
defaultSkin={number('Default skin tone', 1)}
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}
/>
))
@ -61,6 +77,10 @@ storiesOf('Picker', module)
/>
))
.add('Custom categories', () => (
<Picker custom={CUSTOM_EMOJIS_WITH_CATEGORIES} />
))
.add('Custom category icons', () => (
<Picker
custom={CUSTOM_EMOJIS}
@ -80,6 +100,17 @@ storiesOf('Picker', module)
<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"
@ -249,14 +280,10 @@ storiesOf('Get emoji data from Native', module)
const emojiData = getEmojiDataFromNative(
text('Unicode', '🏋🏿‍♂️'),
select('Emoji pack', SETS, SETS[0]),
data
data,
)
if (!emojiData) {
return (
<div>
Couldn`t find any emoji data from native...
</div>
)
return <div>Couldn`t find any emoji data from native...</div>
}
return (
@ -268,9 +295,7 @@ storiesOf('Get emoji data from Native', module)
size={48}
/>
<pre>
emojiData: {JSON.stringify(emojiData, null, 2)}
</pre>
<pre>emojiData: {JSON.stringify(emojiData, null, 2)}</pre>
</div>
)
})

26
test/ssr.js Normal file
View File

@ -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()

20076
yarn.lock

File diff suppressed because it is too large Load Diff