Compare commits

...

338 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
Etienne Lemay ae24948861
Release v2.11.1 2019-05-09 11:59:46 -04:00
Etienne Lemay 75dfed01f5
Merge pull request #338 from The-Code-Monkey/patch-1
Added `type={"button"}` to anchors.js
2019-05-09 11:32:59 -04:00
The-Code-Monkey af37a7a20f
attempt 2 to fix prettier error 2019-05-01 15:41:07 +01:00
The-Code-Monkey 14c5d4f2b4
attempting to fix the prettier issue 2019-05-01 15:36:59 +01:00
The-Code-Monkey 0cfb0787ab
Added `type={"button"}` to anchors.js 2019-05-01 15:32:02 +01:00
Etienne Lemay f654ef4050 Update gh-pages 2019-03-28 09:47:48 -04:00
Etienne Lemay 1d09d3758e
Fix changelog link 2019-03-28 09:43:52 -04:00
Etienne Lemay 8d4d928973
Release v2.11.0 2019-03-28 09:41:13 -04:00
Etienne Lemay 5d1b84cf1d
Add CHANGELOG.md 2019-03-28 09:35:40 -04:00
Etienne Lemay 9b3a4487a1
Merge pull request #329 from missive/fix-emoji-button
fix: use span for non-clickable emojis
2019-03-28 09:27:43 -04:00
Etienne Lemay 7f05e22d12
Fix test 2019-03-28 09:16:43 -04:00
Etienne Lemay 32282a6dc7
Fix prettier 2019-03-28 09:14:25 -04:00
Etienne Lemay 4fda4dcc01 fix: use span for non-clickable emojis 2019-03-28 08:59:19 -04:00
Etienne Lemay abc2cdaf02 Revert "💄"
This reverts commit 1bcc52e587.
2019-03-28 08:56:50 -04:00
Etienne Lemay 1bcc52e587
💄 2019-03-28 08:22:30 -04:00
Etienne Lemay 5f065d4793
Merge pull request #316 from nolanlawson/nolan/fix-tests-ci
docs: fix travis CI badge
2019-03-28 07:38:55 -04:00
Etienne Lemay cbad12426c
Merge pull request #317 from nolanlawson/nolan/308-addendum
fix: consistently return short_names from sanitize
2019-03-28 07:37:39 -04:00
Nolan Lawson 7a94080f5f
Merge pull request #323 from missive/nolan/hinaloe-test
test: add test for short_names in custom emoji
2019-03-23 15:06:35 -07:00
Nolan Lawson 7039517939 remove code comment 2019-03-23 15:06:13 -07:00
Nolan Lawson 7d8e2458d9
Merge pull request #250 from pederjohnsen/get_emoji_data_from_native
Get emoji data from native
2019-03-23 15:04:59 -07:00
Peder Johnsen ab2f6004ac Add tests 2019-03-23 21:31:11 +00:00
Peder Johnsen d140dd8f04 typo 2019-03-23 21:22:14 +00:00
Peder Johnsen 5570a7ce1a Run prettier 2019-03-23 21:15:47 +00:00
Peder Johnsen 5c64cc6908 Use for loop and refactor lookup code 2019-03-23 21:14:52 +00:00
Peder Johnsen 90b36d829f Get skinToneIndex from forEach function 2019-03-23 21:13:02 +00:00
Peder Johnsen 0ab34e20a3 Remove empty strings from skinTones and skinCodes. 2019-03-23 21:12:40 +00:00
Peder Johnsen a8c491273c Merge remote-tracking branch 'emojimart/master' into get_emoji_data_from_native 2019-03-23 20:35:16 +00:00
Nolan Lawson d6598deb2e
Merge pull request #324 from pederjohnsen/fix_typo
Fix typo
2019-03-23 09:58:51 -07:00
Peder Johnsen dce30b3f09 Fix typo 2019-03-23 16:39:40 +00:00
Peder Johnsen 37340679ec Update story/readme 2019-03-23 16:29:17 +00:00
Hinaloe 39fc02bfe3 test: add test for short_names in custom emoji 2019-03-23 09:25:51 -07:00
Nolan Lawson 3c0c0caffc fix: fix prettier 2019-03-23 09:18:50 -07:00
Nolan Lawson d9eda6a7a5
Merge pull request #321 from pederjohnsen/return_skin_emoji_on_search
Return skin emoji on search
2019-03-23 09:18:26 -07:00
Nolan Lawson 43ddfa78ad
Merge pull request #322 from pederjohnsen/patch-1
Add ignore for package-lock.json
2019-03-23 09:14:15 -07:00
Nolan Lawson 5538272c94
Merge pull request #320 from pederjohnsen/editorconfig
Add .editorconfig
2019-03-23 09:13:09 -07:00
Peder Johnsen ed241d1d42 Revert skin tone emoji on search code 2019-03-23 15:34:46 +00:00
Peder Johnsen 236cd3d612
Add ignore for package-lock.json 2019-03-23 15:30:26 +00:00
Peder Johnsen aaa12fe918
Delete package-lock.json 2019-03-23 15:28:52 +00:00
Peder Johnsen 127dea28a5 Use `thumbs` over `christmas` for skin tone search story 2019-03-23 15:24:43 +00:00
Peder Johnsen 88310345d8 Revert 2019-03-23 15:24:22 +00:00
Peder Johnsen e00371c86e Keep new line 2019-03-23 15:20:21 +00:00
Peder Johnsen b76be74e96 Add test 2019-03-23 15:18:26 +00:00
Peder Johnsen ab2f17cfc1 Add story 2019-03-23 15:18:02 +00:00
Peder Johnsen 51a0879ec1 Return emojis with skin tone from store on nimble search 2019-03-23 15:17:37 +00:00
Peder Johnsen 9afc613fee Split out .editorconfig addition into separate PR 2019-03-23 12:00:55 +00:00
Peder Johnsen f1901ed94c Add .editorconfig 2019-03-23 12:00:14 +00:00
Nolan Lawson fa7141653d fix: consistently return short_names from sanitize 2019-03-22 15:59:55 -07:00
Nolan Lawson 6fb9c9afa7 docs: fix travis CI badge 2019-03-22 15:49:44 -07:00
Nolan Lawson 8bea0331ff
Merge pull request #306 from nolanlawson/nolan/ci-tests
chore: add Travis CI tests
2019-03-22 07:42:45 -07:00
Nolan Lawson 290f442daa
Merge pull request #308 from hinaloe/fix/crash-short_name
keep short_names on sanitize
2019-03-22 07:42:21 -07:00
Nolan Lawson e17b7b9fcd
Merge pull request #307 from nolanlawson/nolan/outside-react
docs: add example of how to use outside React
2019-03-22 07:40:04 -07:00
Peder Johnsen 51d59341c8
Remove duplicate `set` 2019-03-20 11:32:26 +00:00
Peder Johnsen f760c55440 Return skin emojis in search. Refactor getEmojiDataFromNative 2019-03-20 11:25:48 +00:00
Peder Johnsen 22a5ca587f Merge branch 'emojimart' into get_emoji_data_from_native 2019-03-20 09:08:32 +00:00
hina a1a12abcd5 keep short_names on sanitize 2019-03-19 05:10:40 +09:00
Nolan Lawson d53510bd4f docs: add example of how to use outside React
Fixes #305
2019-03-16 17:18:25 -07:00
Nolan Lawson 8cf6515298 chore: add Travis CI tests 2019-03-16 10:26:09 -07:00
Etienne Lemay d739f27714
Upgrade some dev dependencies
Fixes most `yarn audit` warnings
2019-03-14 21:06:39 -04:00
Etienne Lemay c80b9bfa02
Update gh-pages 2019-03-14 20:52:37 -04:00
Etienne Lemay dce1244b8a
Don’t set custom emojis `imageUrl` required
+ add missing prop types since #251
2019-03-14 20:47:38 -04:00
Etienne Lemay e3bb26b894
Fix remaining GitHub assets URLs 2019-03-14 20:39:38 -04:00
Etienne Lemay 20fc1366ef
Update gh-pages 2019-03-14 20:33:35 -04:00
Etienne Lemay e03fc9ac2e
Release v2.10.0 2019-03-14 20:25:22 -04:00
Nolan Lawson 3b4d5ee25a
Merge pull request #304 from nolanlawson/nolan/fix-prettier
chore: fix prettier linting
2019-03-14 08:36:39 -07:00
Nolan Lawson ca66d6c9af chore: fix prettier linting 2019-03-14 08:35:33 -07:00
Nolan Lawson 9b6676a25d
Merge pull request #302 from nolanlawson/nolan/jest-tests
test: replace karma with jest
2019-03-14 08:34:03 -07:00
Nolan Lawson a8ea3506a5
Merge pull request #301 from nolanlawson/nolan/dist-modern-clean
chore: `yarn clean` should remove dist-modern
2019-03-14 08:33:25 -07:00
Nolan Lawson 5dac39e179
Merge pull request #300 from nolanlawson/nolan/simplify-rIC
fix: improve requestIdleCallback usage
2019-03-14 08:33:17 -07:00
Nolan Lawson c6c302ecae
Merge pull request #299 from nolanlawson/nolan/emoji-list
fix: make each emoji category into a list
2019-03-14 08:33:08 -07:00
Nolan Lawson 7c6a28fb76
Merge pull request #298 from nolanlawson/nolan/storybook-urls
chore: fix custom emoji URLs in storybook
2019-03-14 08:32:57 -07:00
Nolan Lawson 165d1a9736
Merge pull request #297 from nolanlawson/nolan/improve-a11y-skin-dots
fix: improve a11y of skin tone picker
2019-03-14 08:32:49 -07:00
Nolan Lawson 8fd11b0e2a
Merge pull request #296 from nolanlawson/nolan/accessible-page-structure
fix: improve accessible page structure
2019-03-14 08:32:36 -07:00
Nolan Lawson 302663f8bf test: replace karma with jest 2019-03-13 20:04:52 -07:00
Nolan Lawson 5f0c868fd9 chore: `yarn clean` should remove dist-modern 2019-03-13 19:19:05 -07:00
Nolan Lawson d1978c096f fix: improve requestIdleCallback usage 2019-03-13 08:54:40 -07:00
Nolan Lawson f53d9b8c71 fix preact compat 2019-03-13 07:55:35 -07:00
Nolan Lawson 42447642c7 fix some more urls 2019-03-13 07:34:39 -07:00
Nolan Lawson f98526a7ed ensure every <li> has a key 2019-03-12 23:15:53 -07:00
Nolan Lawson e3c39bd2fa fix: make each emoji category into a list 2019-03-12 20:56:59 -07:00
Nolan Lawson 19bac54d8a chore: fix custom emoji URLs in storybook 2019-03-12 20:46:39 -07:00
Nolan Lawson 585b4b374f fix: improve a11y of skin tone picker 2019-03-12 20:37:45 -07:00
Nolan Lawson 058cdec053 fix: improve accessible page structure
Makes some progress on #294
2019-03-12 09:36:28 -07:00
Nolan Lawson af29bd19b0
Merge pull request #295 from nolanlawson/nolan/fix-tabindex
fix: use tabIndex, not tabindex
2019-03-12 08:40:47 -07:00
Nolan Lawson 94404ad339 fix: use tabIndex, not tabindex 2019-03-12 08:39:38 -07:00
Nolan Lawson 7e207ba851
Merge pull request #290 from nolanlawson/nolan/fix-prepopulated-search
fix: fix search input when value is prepopulated
2019-03-12 08:22:27 -07:00
Nolan Lawson 978e7b68a1 fix: fix search input when value is prepopulated 2019-03-12 08:21:25 -07:00
Nolan Lawson 5ef7a2a7da
Merge pull request #289 from nolanlawson/nolan/issue-201
fix: fix emoji.id undefined error
2019-03-12 08:20:55 -07:00
Nolan Lawson e3106ac637
Merge pull request #288 from nolanlawson/nolan/remove-notfound-string
fix: remove unused notFoundString prop
2019-03-12 08:20:47 -07:00
Nolan Lawson 27d6a383bd
Merge pull request #287 from nolanlawson/throttle-keyboard-input
perf: throttle keyboard input to improve responsiveness
2019-03-12 08:20:31 -07:00
Nolan Lawson e2694b544b
Merge pull request #285 from nolanlawson/fix-preact-compat-part-2
fix: fix preact compatibility
2019-03-12 08:20:17 -07:00
Nolan Lawson 92c5399ab5
Merge pull request #284 from nolanlawson/issue-218
fix: improve a11y of emoji list
2019-03-12 08:14:54 -07:00
Nolan Lawson 1347c1765a
Merge pull request #283 from nolanlawson/nolan/issue-220-take-two
fix: makes skin tone picker more accessible
2019-03-12 08:14:44 -07:00
Nolan Lawson 0f35206687 fix: improve a11y of emoji list
fixes #218
2019-03-12 08:14:29 -07:00
Nolan Lawson 740eccb6d0 fix: makes skin tone picker more accessible
fixes #220
2019-03-12 08:12:33 -07:00
Nolan Lawson c2c7092fc4
Merge pull request #282 from nolanlawson/nolan/issue-219
fix: make categories into accessible nav buttons
2019-03-12 08:08:46 -07:00
Nolan Lawson 445d2d4656
Merge pull request #281 from nolanlawson/nolan/issue-221
fix: improve search/clear a11y
2019-03-12 08:08:32 -07:00
Nolan Lawson 646ad7f7c7
Merge pull request #280 from nolanlawson/prop-types-dep
fix: add prop-types to dependencies
2019-03-12 08:08:24 -07:00
Nolan Lawson 558de6a994
Merge pull request #260 from nolanlawson/add-slim-build
feat: add slim builds for modern browsers
2019-03-12 08:08:05 -07:00
Nolan Lawson 2fc7816116 fix nav button bg color 2019-03-11 18:55:58 -07:00
Nolan Lawson 27f1b8cd63 improve webkit search input CSS 2019-03-10 11:24:28 -07:00
Nolan Lawson f3cff33eda refactor, add code comment 2019-03-10 10:57:43 -07:00
Nolan Lawson 12c2abba9d fix: fix emoji.id undefined error
fixes #201
2019-03-10 10:47:28 -07:00
Nolan Lawson 13e1dd2e82 fix: remove unused notFoundString prop 2019-03-10 10:40:55 -07:00
Nolan Lawson bd172943d2 fix webkit CSS, fix clear button 2019-03-10 10:35:07 -07:00
Nolan Lawson ef71101cd6 fix prettier 2019-03-10 09:54:12 -07:00
Nolan Lawson 8f6145e383 perf: throttle keyboard input to improve responsiveness 2019-03-10 09:51:47 -07:00
Nolan Lawson 59c4d87839 fix: fix preact compatibility
fixes #254
2019-03-10 09:14:47 -07:00
Nolan Lawson e77c63bc9a fix: make categories into accessible nav buttons
fixes #219
2019-03-09 13:59:09 -08:00
Nolan Lawson b0fee348c0 s/let/const/ 2019-03-09 13:35:48 -08:00
Nolan Lawson 5052ecd399 fix: improve search/clear a11y
fixes #221
2019-03-09 13:03:00 -08:00
Nolan Lawson d20f60cba1 fix: add prop-types to dependencies 2019-03-09 09:21:03 -08:00
Nolan Lawson c13b730dbe tweak babelrc to use runtime helpers for Object.assign 2019-03-09 09:16:23 -08:00
Nolan Lawson b1be155787 feat: add slim builds for modern browsers
fixes #259
2019-03-09 09:00:04 -08:00
Nolan Lawson 8c80e7d4e5
Merge pull request #278 from nolanlawson/nolan/babel-runtime
fix: fix babel-runtime not found
2019-03-09 08:54:38 -08:00
Nolan Lawson 28c05b2861 fix: fix babel-runtime not found
fixes #228
2019-03-08 09:00:10 -08:00
Nolan Lawson a871cacbf2
Merge pull request #277 from kayleemann/master
Support case where showPreview is false but showSkinTones is true. Also add prepare script.
2019-03-08 07:32:23 -08:00
Kaylee Mann 22aa42acf4 Add "prepare" script so that emoji-mart can be installed from git. 2019-03-08 14:13:17 +09:00
Kaylee Mann caba7d0b34 Show preview panel when showPreview is false but showSkinTones is true.
This is necessary in order to be able to show skin tone picker even when
one desires for the mouseover preview to be invisible. This is an
important case because mouseover displays must be disabled in order to
enable single click emoji typing on iOS without disabling the skin tone
picker.
2019-03-08 14:00:50 +09:00
Nolan Lawson ce777216cd
Merge pull request #276 from nolanlawson/nolan/add-dev-docs
docs: add more explicit dev docs
2019-03-07 20:12:20 -08:00
Nolan Lawson e8b4cfd4a8 docs: add more explicit dev docs
fixes #227
2019-03-07 18:47:45 -08:00
Nolan Lawson c27e62456f
Merge pull request #258 from nolanlawson/remove-proptypes
fix: allow prop-types to be removed in production
2019-03-07 18:18:53 -08:00
Nolan Lawson f60220870e fix: allow prop-types to be removed in production
fixes #257
2019-03-07 18:12:37 -08:00
Nolan Lawson 420e2c7e86
Merge pull request #270 from dwijesingheWR/master
Fixed bug where selecting the first emoji search result with the ENTER KEY ignores skin tone selection
2019-03-07 17:35:22 -08:00
Nolan Lawson bae7afb282
Merge pull request #261 from vs-ryann/line-break
fix: forces emoji's not to break line
2019-03-07 17:19:55 -08:00
Nolan Lawson 10bfbd0594
Merge pull request #256 from nolanlawson/fix-linux-emoji
fix: fix native emoji on Linux
2019-03-07 17:19:17 -08:00
Dimitri Wijesinghe 17db4cc913 Fixed bug where selecting the first emoji search result with the ENTER key ignores skin-tone selection. 2019-02-13 14:56:42 -05:00
Ryann 9b9410e70c forces emoji's not to break line
closes issue #252
2019-01-17 09:25:22 -06:00
Nolan Lawson e975284b29 fix: fix native emoji on Linux
fixes #255
2018-12-18 10:13:20 -08:00
Etienne Lemay 7c2e2a840b
Release v2.9.2 2018-12-03 17:15:08 -05:00
Etienne Lemay 993074fd03
Merge pull request #251 from Kennybll/master
Adds Spritesheets for Custom Emojis
2018-12-03 17:08:19 -05:00
kennybll 2ff225b131 Add to README.md for support of spritesheets 2018-11-30 09:27:55 -05:00
kennybll 94baec171d Add sprite support 2018-11-30 09:17:45 -05:00
Peder Johnsen 682d8d8be4 Remove whitespace 2018-11-29 16:39:36 +00:00
Peder Johnsen f0b5e1eeae Add example of `emojiData` object 2018-11-29 16:35:57 +00:00
Peder Johnsen bbbdcc512d Use same emoji in readme as in story 2018-11-29 16:27:44 +00:00
Peder Johnsen fe17925fac Fix story/readme skin prop typo 2018-11-29 16:19:55 +00:00
Peder Johnsen fd4056025a Add section to readme for `getEmojiDataFromNative` util function 2018-11-29 16:09:52 +00:00
Peder Johnsen f90defbed7 Add `Get emoji data from Native` story 2018-11-29 16:09:28 +00:00
Peder Johnsen 1c7a5d6ec6 Add `getEmojiDataFromNative` util function to get emoji data from native 2018-11-29 16:08:30 +00:00
Peder Johnsen 54f6893c98 Add .editorconfig file with indent_size = 2 2018-11-29 15:50:03 +00:00
Etienne Lemay 3482a56d60
Update gh-pages 2018-11-14 08:58:53 -05:00
Etienne Lemay aaa91c949e
Release v2.9.1 2018-11-14 08:56:48 -05:00
Etienne Lemay 7186a10d4f Revert "fix(a11y): ability to tab through different categories"
This reverts commit 937e33534d.
2018-11-14 08:54:13 -05:00
Etienne Lemay 08eb6db270
Update gh-pages 2018-11-13 10:07:26 -05:00
Etienne Lemay 1c05b38a9e
Release v2.9.0 2018-11-13 09:43:02 -05:00
Etienne Lemay 21b3e92bb2
Get rid of components index
Import all components directly, similar to #245
2018-11-13 09:41:57 -05:00
Etienne Lemay 9196a87769
Update yarn.lock 2018-11-13 09:23:49 -05:00
Etienne Lemay a09730d6a8
Merge pull request #226 from hozefaj/master [Close #219]
fix(a11y): ability to tab through different categories
2018-11-13 08:48:59 -05:00
Etienne Lemay e4d4226045
Merge pull request #231 from adambowles/patch-1
Add trailing colon to :octocat
2018-11-13 08:47:34 -05:00
Etienne Lemay d54b7f2171
Merge pull request #245 from rtkhanas/master
Import compoments directly to avoid components/picker/index.js and have smaller bundle
2018-11-13 08:47:18 -05:00
Ross Khanas c0a418fa57
Update category.js 2018-11-13 19:21:37 +09:00
Ross Khanas be27ba5779
Update preview.js 2018-11-13 19:21:07 +09:00
Ross Khanas 9cad93d015
Update nimble-picker.js 2018-11-13 19:19:16 +09:00
Adam Bowles 745cd2a9b5
Add trailing colon to :octocat 2018-09-27 11:25:27 +01:00
hozefaj 937e33534d fix(a11y): ability to tab through different categories 2018-08-25 21:00:48 -07:00
Etienne Lemay 016ef7ccce Update gh-pages 2018-08-15 22:34:32 -04:00
Etienne Lemay 1c14c868b1
Release v2.8.1 2018-08-15 22:30:54 -04:00
Etienne Lemay 7c090c99d1
Merge pull request #215 from jdecked/sheet-columns-preview-props
Fixes display of non-52x52 sprite sheets in the preview bar
2018-08-15 22:29:43 -04:00
Justine De Caires c6b36947d3 Fixes display of non-52x52 sheets in the preview bar 2018-08-14 22:29:20 -07:00
Etienne Lemay 8ee9858aa0
Release v2.8.0 2018-08-10 14:18:19 -04:00
Etienne Lemay 5e15356379 Update gh-pages 2018-08-10 14:17:22 -04:00
Etienne Lemay f5a4a488f8
Merge pull request #209 from Rena-Ryumae/rena/customskin
Custom emoji for skin tone selector
2018-08-10 14:15:31 -04:00
Etienne Lemay 94e7b2d878
💄 2018-08-10 14:14:18 -04:00
Etienne Lemay 2c060c56bc
Rename “skinIcon” => “skinEmoji”
More consistent with other props
2018-08-10 14:11:28 -04:00
Etienne Lemay 83bd22dffd
Update README 2018-08-10 14:10:55 -04:00
Etienne Lemay 757f1b023c
Merge branch 'master' into rena/customskin 2018-08-10 14:06:41 -04:00
Etienne Lemay 9b523425c6
💄 2018-08-10 14:02:33 -04:00
Etienne Lemay 175d08a612
Set `.emoji-mart-skin-text` width in px
So that it doesn’t change width while transitioning.
2018-08-10 14:01:52 -04:00
Etienne Lemay 0c508deee8
Merge pull request #212 from jdecked/sheet-columns-props
Add sheetColumns and sheetRows props for non-square sprite sheets
2018-08-08 16:39:16 -04:00
Etienne Lemay 7c55c05935
Merge pull request #213 from tkbremnes/tkbremnes/fix-size-typo-in-readme
fix typo in README.md
2018-08-08 09:33:05 -04:00
Trond Kjetil Bremnes 57a548b199 fix typo in README.md
The sheet size for messenger says that the emoji download size is 449
_megabytes_ for a sheetSize of 32.
449 _kilobytes_ is the correct value.
2018-08-08 12:22:28 +02:00
Justine De Caires 385cb8f8c2 Add sheetColumns and sheetRows props for non-square sprite sheets 2018-08-06 14:31:02 -07:00
Rena Ryumae f1d5bc0095 Custom emoji for skin tone selector
Currently, the skin tone selector
is a row of colored dots

We propose creating a skinIcon field
that uses the emoji-mart dots on
default but otherwise uses the emoji
passed in by the user
2018-08-02 10:42:46 -04:00
Etienne Lemay 1588712ca0
Release v2.7.0 2018-07-31 15:39:26 -04:00
Etienne Lemay 34ba02fc4b Update gh-pages 2018-07-31 15:32:30 -04:00
Etienne Lemay c236437f91
Ignore .DS_Store 2018-07-31 15:31:39 -04:00
Etienne Lemay 58ceb30d3d
Use ES6 export everywhere in /src 2018-07-31 15:29:11 -04:00
Etienne Lemay a0075d7054
Update README 2018-07-31 15:12:58 -04:00
Etienne Lemay 60d3b9767b
Update search input default border radius 2018-07-31 15:11:22 -04:00
Etienne Lemay 7915d5472f
Merge pull request #208 from Rena-Ryumae/rena/categoryiconprops
Customizable Category Icons
2018-07-31 15:03:03 -04:00
Etienne Lemay 0021d6ff38
Merge branch 'master' into rena/categoryiconprops 2018-07-31 15:01:34 -04:00
Etienne Lemay 2cea3df86a
Call fallback when emoji name isn’t recognized [Fix #199] 2018-07-31 14:05:25 -04:00
Rena Ryumae 31cc0ab215 Customizable Category Icons
Currently, the default emoji-mart
category icons cannot be changed.

We propose creating a categories
object that uses the emoji-mart
category icons on default but
otherwise uses custom imgs/svgs
passed in by the user
2018-07-31 11:09:38 -04:00
Etienne Lemay 767b2fdcc6
Merge pull request #206 from Rena-Ryumae/rena/customnotfound
Not Found Component for emoji search
2018-07-30 17:11:44 -04:00
Etienne Lemay 4bb41b9796
Add notFoundEmoji props to Picker 2018-07-30 17:06:23 -04:00
Etienne Lemay 8ddd8725e8
Update README 2018-07-30 16:52:41 -04:00
Etienne Lemay 3dc3e2fd95
Don’t apply `emoji-mart-no-results` class when using custom notFound component 2018-07-30 16:52:15 -04:00
Etienne Lemay a7e37edcde
Merge pull request #205 from Rena-Ryumae/rena/updatesearchfield
Adding search icon in search input field
2018-07-30 16:21:25 -04:00
Etienne Lemay 98af838d60
Update search input & icon 2018-07-30 16:17:22 -04:00
Etienne Lemay 6fac845580
Merge pull request #203 from luisbelloch/master
Added font stack to support native emojis in IE11/Edge
2018-07-30 16:01:24 -04:00
Rena Ryumae 8e6d363d8b Not Found Component for emoji search
If a user's search returns no results,
the sleuth_or_spy emoji appears. We would
instead like for a custom image to appear.

We propose creating a NotFound component
that uses the the sleuth_or_spy emoji
on default when a user's search returns
no results but otherwise uses what the
user passes through
2018-07-13 13:58:17 -04:00
Rena Ryumae 5e03ee3e16 Adding search icon in search input field
Currently, there is no visual indication
for when the user is searching for an
emoji nor is there an easy way to clear
the input field after the user's search

Our change proposes to add a small magnifying
glass icon to the right hand side of the
search input bar which becomes an x delete
icon when the user types in the search input
bar.

The x delete icon is tabbable and will clear
the search input field with the return (enter)
key, spacebar, and mouse click. The
magnifying glass icon is not tabbable.
2018-07-13 13:18:06 -04:00
Luis Belloch 086ed6991e Added font stack to support native emojis in IE11/Edge 2018-07-10 21:53:24 +02:00
Etienne Lemay b1c499fc8d
Release v2.6.1 2018-05-11 13:19:10 -04:00
Etienne Lemay 9cda3c974c Update gh-pages 2018-05-11 13:19:08 -04:00
Etienne Lemay f9d47e9b13
Merge pull request #183 from savardc/missing-on-select-prop
Add missing onSelect to shared props
2018-05-08 08:25:25 -04:00
Etienne Lemay f2b5035f12
Merge pull request #187 from Kovensky/patch-1
Correct NimbleEmojiIndex reexport
2018-05-08 08:25:04 -04:00
Etienne Lemay 2428f3c1ba
Merge pull request #185 from savardc/fix-nimble-comp-with-customs
Fix crash in NimbleEmojiIndex when using custom emojis
2018-05-08 08:24:39 -04:00
Diogo Franco c2f11adec3
Correct NimbleEmojiIndex reexport 2018-05-08 10:59:21 +09:00
Christian Savard 8df31b1c42 Fix typo 2018-05-03 12:40:14 -04:00
Christian Savard 0fff524ed7 Add missing proptype and default value 2018-04-30 10:41:31 -04:00
Etienne Lemay 4715fe8f48
Update README 2018-04-29 23:05:55 -04:00
Etienne Lemay aa42453a0e
Release v2.6.0 2018-04-29 22:53:34 -04:00
Etienne Lemay 59601a08cf
Update gh-pages 2018-04-29 22:46:31 -04:00
Etienne Lemay c6b86b25b9
Update emoji-datasource
Updates to Emojione 3
2018-04-29 22:40:42 -04:00
Etienne Lemay 1edf3eaa96
Merge pull request #178 from davidcilley/less-destructive-add-data-prop
Add parent components and data property for components that reference data.js Issue#86
2018-04-29 22:18:27 -04:00
Etienne Lemay 57662665d3
Update gh-pages 2018-04-29 21:58:51 -04:00
Etienne Lemay 22b37b6e36
Fix specs 2018-04-29 21:57:52 -04:00
Etienne Lemay 2e97b1faa6
Restructure data and components 2018-04-29 21:06:32 -04:00
Etienne Lemay 2f5fe6164e
Export NimblePicker, NimbleEmoji and NimbleCategory 2018-04-29 11:41:06 -04:00
Etienne Lemay 0f37b428f6
Rename data.short_names => data.aliases 2018-04-26 16:31:16 -04:00
Etienne Lemay 253ef4de89
💄 Prettier 2018-04-26 16:07:22 -04:00
Etienne Lemay 446fdf9544
Export NimbleEmojiIndex 2018-04-26 15:34:03 -04:00
Etienne Lemay a8b81f1858
Restructure components 2018-04-26 12:10:52 -04:00
Etienne Lemay d17594315c
Make parent Emoji component a functional component
Just like NimbleEmoji.

Read more: https://medium.com/missive-app/45-faster-react-functional-components-now-3509a668e69f
2018-04-26 11:16:21 -04:00
Etienne Lemay 8660a146e2
💄 Prettier 2018-04-26 10:36:54 -04:00
Dave Cilley 892096ea27 Add data property to any components that import data.js, and use that under the hood 2018-03-28 17:30:47 -04:00
Etienne Lemay 19d875e88b
Release v2.5.1 2018-03-27 14:55:30 -04:00
Etienne Lemay 6d557a5bee
Update gh-pages 2018-03-27 14:54:15 -04:00
Etienne Lemay c113dc5e3b
💄 Add prettier.config.js 2018-03-27 14:52:31 -04:00
Etienne Lemay a71280f14e
Merge pull request #175 from savardc/keyboardSelect
Select first emoji in list with `enter`
2018-03-27 14:45:03 -04:00
Etienne Lemay 4467fbd021
Fix pressing enter when no search results 2018-03-27 14:43:02 -04:00
Etienne Lemay f879348e2e
Fix undefined SEARCH_CATEGORY 2018-03-27 14:41:45 -04:00
Etienne Lemay 933ea29070
Merge pull request #172 from vcervellera-turbulent/bf/custom-emojis-contamination
Clearing custom emojis from index and pool when necessary
2018-03-27 14:28:08 -04:00
Christian Savard 0765bf56f7 Add keyboard selection with enter 2018-03-15 18:42:16 -04:00
Etienne Lemay 6bd17d3eb5
Merge pull request #174 from Hongbo-Miao/patch-1
doc: add css in readme
2018-03-13 09:04:48 -04:00
Hongbo Miao a5b2d5f1a0
doc: add css in readme 2018-03-12 23:21:55 -07:00
vcervellera bf8ffe5413 Clearing custom emojis from index and pool when necessary 2018-03-12 13:35:38 -04:00
Etienne Lemay 1ea0048d3e
Release v2.5.0 2018-03-02 15:11:45 -05:00
Etienne Lemay 23f94c678c
Update gh-pages 2018-03-02 15:10:50 -05:00
Etienne Lemay 88b1045ff7
💄 Prettier 2018-03-02 15:10:04 -05:00
Etienne Lemay c010035015
Add `showSkinTones` prop to Picker [Ref #165] 2018-03-02 15:08:52 -05:00
Etienne Lemay a7cd5e5d96 Update gh-pages 2018-03-02 14:22:41 -05:00
Etienne Lemay 31246e41ef
Add `contentEditable` guide to README [Close #169] 2018-03-02 14:15:49 -05:00
Etienne Lemay af2fdc71a1
Add `defaultSkin` prop to Picker and allow forcing skin tone with `skin` prop [Ref #165] 2018-03-02 13:45:33 -05:00
Etienne Lemay b0753769fb
Add `onSkinChange` prop to Picker [Close #165] 2018-03-02 13:33:14 -05:00
Etienne Lemay fed9a89c78
Set RECENT_CATEGORY, CUSTOM_CATEGORY and SEARCH_CATEGORY on Picker instances [Fix #166] 2018-03-02 13:25:39 -05:00
Etienne Lemay 90ce594b11
Merge pull request #167 from vcervellera-turbulent/bf/frequently-used-with-custom-emojis
Custom Emojis as a changing prop
2018-03-02 13:10:03 -05:00
vcervellera 88d7e2f506 Emptying custom category when custom prop is cleared 2018-02-22 09:58:10 -05:00
Etienne Lemay 1c1fe761b6
Merge pull request #164 from syokenz/fix-categories-sort-compare-function
fix Categories sort compareFunction return to -1 from 0 in Picker component
2018-02-15 10:05:31 -06:00
syokenz 6e4dd6765c change to return -1 in Categories sort compareFunction 2018-02-15 22:39:17 +09:00
Etienne Lemay 46416a7504
Update gh-pages 2018-01-23 20:56:29 -05:00
Etienne Lemay 9d8924b469
Update gh-pages 2018-01-23 20:48:05 -05:00
Etienne Lemay b1ba2b777a
Release v2.4.2 2018-01-23 20:41:45 -05:00
Etienne Lemay e5441d637e
Merge pull request #159 from scttcper/master
remove unused name
2018-01-15 17:03:42 -05:00
Etienne Lemay 1f8254de5e
Merge pull request #158 from ajbeaven/master
Emoji fallback shouldn't apply styling #157
2018-01-15 17:03:27 -05:00
Scott Cooper 8e83059f58 remove unused name 2018-01-10 22:41:50 -08:00
Andrew Beaven 238b2d2ff2 Remove Emoji fallback defaultProp 2018-01-11 10:45:02 +13:00
Andrew Beaven 4008363e73 Don't render fallback inside an emoji `<span>` 2018-01-10 11:38:30 +13:00
Andrew Beaven 818b4a1600 Emoji fallback shouldn't apply styling #157 2018-01-10 11:24:51 +13:00
Etienne Lemay cab9f143f4 Release v2.4.1 2018-01-09 15:32:50 -05:00
Etienne Lemay e698358ea7 Update gh-pages 2018-01-09 15:32:10 -05:00
Etienne Lemay 68a4711658 💄 2018-01-09 15:20:18 -05:00
Etienne Lemay 94fc19491a Fix anchor 2018-01-09 15:18:08 -05:00
Etienne Lemay 6d095a072c Add `html` props to Emoji component [Ref #79] 2018-01-09 15:16:59 -05:00
Etienne Lemay 3fa0331d60 Support providing a fallback to unsupported emojis [Fix #157] 2018-01-09 15:16:59 -05:00
Etienne Lemay d17c8a5c4b
Merge pull request #153 from savardc/fix-search-with-custom
Fix search with custom data and filter
2018-01-09 15:16:26 -05:00
Etienne Lemay 9675658e92
Merge pull request #154 from mwadden/master
Bug Fix: Ensure category ids are not dropped after emojisToShowFilter call
2017-12-28 10:04:49 -05:00
Etienne Lemay 048838cb2e
Merge pull request #155 from veob/patch-1
add required props in <Emoji /> example
2017-12-28 10:03:40 -05:00
veob 67ac4a26df
add required props in <Emoji /> example
Without `size` <Emoji /> doesn't render correctly.
2017-12-28 12:39:15 +03:00
Mark Wadden 3c924a1619 Bug fix to ensure that the category ids are not dropped aftering being filtered. 2017-12-21 22:24:36 -05:00
Christian Savard b644e3d2d3 Use pool to lookup emoji data 2017-12-20 11:33:15 -05:00
72 changed files with 18629 additions and 10800 deletions

View File

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

2
.editorconfig Normal file
View File

@ -0,0 +1,2 @@
[*]
indent_size = 2

4
.gitignore vendored
View File

@ -1,6 +1,8 @@
.DS_Store
node_modules/
dist/
dist-es/
dist-modern/
stats.json
report.html
/src/data/data.js
package-lock.json

View File

@ -4,7 +4,6 @@ scripts/
src/
docs/
spec/
example/
karma.conf.js
yarn.lock

2
.prettierignore Normal file
View File

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

12
.travis.yml Normal file
View File

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

647
CHANGELOG.md Normal file
View File

@ -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 isnt 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)
- Dont 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 isnt 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 Babels 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)
- Dont 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)
- Dont 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 pickers 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)

326
README.md
View File

@ -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>
@ -13,10 +14,11 @@
## Components
### Picker
```jsx
import 'emoji-mart/css/emoji-mart.css'
import { Picker } from 'emoji-mart'
<Picker set='emojione' />
<Picker onClick={this.addEmoji} />
<Picker set='apple' />
<Picker onSelect={this.addEmoji} />
<Picker title='Pick your emoji…' emoji='point_up' />
<Picker style={{ position: 'absolute', bottom: '20px', right: '20px' }} />
<Picker i18n={{ search: 'Recherche', categories: { search: 'Résultats de recherche', recent: 'Récents' } }} />
@ -31,29 +33,43 @@ 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) => {}` |
| **onClick** | | | Params: `(emoji, event) => {}`. Not called when emoji is selected with `enter` |
| **onSelect** | | | Params: `(emoji) => {}` |
| **onSkinChange** | | | Params: `(skin) => {}` |
| **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. Disable both this and `showPreview` to remove the footer entirely. |
| **emojiTooltip** | | `false` | Show emojis short name when hovering (title) |
| **skin** | | `1` | Default skin color: `1, 2, 3, 4, 5, 6` |
| **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',
@ -62,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
@ -123,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'
}
```
@ -136,9 +163,9 @@ Sheets are served from [unpkg](https://unpkg.com), a global CDN that serves file
```jsx
import { Emoji } from 'emoji-mart'
<Emoji emoji={{ id: 'santa', skin: 3 }} />
<Emoji emoji=':santa::skin-tone-3:' />
<Emoji emoji='santa' set='emojione' />
<Emoji emoji={{ id: 'santa', skin: 3 }} size={16} />
<Emoji emoji=':santa::skin-tone-3:' size={16} />
<Emoji emoji='santa' set='apple' size={16} />
```
| Prop | Required | Default | Description |
@ -149,14 +176,64 @@ import { Emoji } from 'emoji-mart'
| **onClick** | | | Params: `(emoji, event) => {}` |
| **onLeave** | | | Params: `(emoji, event) => {}` |
| **onOver** | | | Params: `(emoji, event) => {}` |
| **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` |
| **tooltip** | | `false` | Show emoji short name when hovering (title) |
| [**html**](#using-with-dangerouslysetinnerhtml) | | `false` | Returns an HTML string to use with `dangerouslySetInnerHTML` |
#### Unsupported emojis fallback
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={'apple'}
emoji={'shrug'}
size={24}
fallback={(emoji, props) => {
return emoji ? `:${emoji.short_names[0]}:` : props.emoji
}}
/>
```
#### Using with `dangerouslySetInnerHTML`
The Emoji component being a [functional component](https://medium.com/missive-app/45-faster-react-functional-components-now-3509a668e69f), you can call it as you would call any function instead of using JSX. Make sure you pass `html: true` for it to return an HTML string.
```js
<span dangerouslySetInnerHTML={{
__html: Emoji({
html: true
set: 'apple'
emoji: '+1'
size: 24
})
}}></span>
```
#### Using with `contentEditable`
Following the `dangerouslySetInnerHTML` example above, make sure the wrapping `span` sets `contenteditable="false"`.
```js
<div contentEditable={true}>
Looks good to me
<span contentEditable={false} dangerouslySetInnerHTML={{
__html: Emoji({
html: true
set: 'apple'
emoji: '+1'
size: 24
})
}}></span>
</div>
```
## 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'
@ -168,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` doesnt have to be mounted for you to take advantage of the advanced search results.
@ -185,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.
@ -244,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** doesnt automatically insert anything into a text input, nor does it show or hide itself. It simply returns an `emoji` object. Its up to the developer to mount/unmount (its 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>

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,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;
}

1
data/all.json Normal file

File diff suppressed because one or more lines are too long

1
data/apple.json Normal file

File diff suppressed because one or more lines are too long

1
data/facebook.json Normal file

File diff suppressed because one or more lines are too long

1
data/google.json Normal file

File diff suppressed because one or more lines are too long

1
data/twitter.json Normal file

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,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;
}

BIN
docs/images/parrot.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

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

View File

@ -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: 'http://cultofthepartyparrot.com/parrots/hd/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}
onClick={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'))

View File

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

View File

@ -1,88 +1,89 @@
{
"name": "emoji-mart",
"version": "2.4.0",
"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.7.4",
"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 --no-semi --single-quote --trailing-comma es5 --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"
}
]
}

6
prettier.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
semi: false,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'always',
}

View File

@ -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 + '” doesnt 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 + '” doesnt 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
})

137
scripts/build.js Normal file
View File

@ -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 + '” doesnt 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 + '” doesnt 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
})
}

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

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

View File

@ -1,37 +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)
})
})
})

View File

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

View File

@ -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>
`;

View File

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

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

@ -1,13 +1,13 @@
import React from 'react'
import PropTypes from 'prop-types'
import SVGs from '../svgs'
export default class Anchors extends React.PureComponent {
constructor(props) {
super(props)
let defaultCategory = props.categories.filter(category => category.first)[0]
let defaultCategory = props.categories.filter(
(category) => category.first,
)[0]
this.state = {
selected: defaultCategory.name,
@ -16,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
@ -39,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
@ -52,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'
: ''}`}
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: {},
}

View File

@ -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
var { name } = this.props
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,
}

View File

@ -1,171 +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 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) {
return null
}
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),
}
}
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,
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,27 +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 '.'
const RECENT_CATEGORY = { id: 'recent', name: 'Recent', emojis: null }
const SEARCH_CATEGORY = {
id: 'search',
name: 'Search',
emojis: null,
anchor: false,
}
const CUSTOM_CATEGORY = { id: 'custom', name: 'Custom', emojis: [] }
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',
@ -35,32 +32,77 @@ 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.i18n = deepMerge(I18N, props.i18n)
this.state = {
skin: store.get('skin') || props.skin,
firstRender: true,
this.CUSTOM = []
this.RECENT_CATEGORY = { id: 'recent', name: 'Recent', emojis: null }
this.SEARCH_CATEGORY = {
id: 'search',
name: 'Search',
emojis: null,
anchor: false,
}
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) {
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(CUSTOM_CATEGORY)
allCategories = allCategories.concat(
Object.keys(customCategories).map((key) => customCategories[key]),
)
}
this.hideRecent = true
@ -71,7 +113,7 @@ export default class Picker extends React.PureComponent {
return 1
}
return 0
return -1
})
}
@ -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)
}
}
@ -108,6 +150,7 @@ export default class Picker extends React.PureComponent {
let newCategory = {
emojis: newEmojis,
name: category.name,
id: category.id,
}
this.categories.push(newCategory)
@ -119,22 +162,22 @@ export default class Picker extends React.PureComponent {
let includeRecent =
props.include && props.include.length
? props.include.indexOf(RECENT_CATEGORY.id) > -1
? props.include.indexOf(this.RECENT_CATEGORY.id) > -1
: true
let excludeRecent =
props.exclude && props.exclude.length
? props.exclude.indexOf(RECENT_CATEGORY.id) > -1
? props.exclude.indexOf(this.RECENT_CATEGORY.id) > -1
: false
if (includeRecent && !excludeRecent) {
this.hideRecent = false
this.categories.unshift(RECENT_CATEGORY)
this.categories.unshift(this.RECENT_CATEGORY)
}
if (this.categories[0]) {
this.categories[0].first = true
}
this.categories.unshift(SEARCH_CATEGORY)
this.categories.unshift(this.SEARCH_CATEGORY)
this.setAnchorsRef = this.setAnchorsRef.bind(this)
this.handleAnchorClick = this.handleAnchorClick.bind(this)
@ -146,14 +189,11 @@ export default class Picker extends React.PureComponent {
this.handleEmojiOver = this.handleEmojiOver.bind(this)
this.handleEmojiLeave = this.handleEmojiLeave.bind(this)
this.handleEmojiClick = this.handleEmojiClick.bind(this)
this.handleEmojiSelect = this.handleEmojiSelect.bind(this)
this.setPreviewRef = this.setPreviewRef.bind(this)
this.handleSkinChange = this.handleSkinChange.bind(this)
}
componentWillReceiveProps(props) {
if (props.skin && !store.get('skin')) {
this.setState({ skin: props.skin })
}
this.handleKeyDown = this.handleKeyDown.bind(this)
this.handleDarkMatchMediaChange = this.handleDarkMatchMediaChange.bind(this)
}
componentDidMount() {
@ -171,10 +211,14 @@ export default class Picker extends React.PureComponent {
}
componentWillUnmount() {
SEARCH_CATEGORY.emojis = null
this.SEARCH_CATEGORY.emojis = null
clearTimeout(this.leaveTimeout)
clearTimeout(this.firstRenderTimeout)
if (this.darkMatchMedia) {
this.darkMatchMedia.removeListener(this.handleDarkMatchMediaChange)
}
}
testStickyPosition() {
@ -183,12 +227,30 @@ export default class Picker extends React.PureComponent {
const prefixes = ['', '-webkit-', '-ms-', '-moz-', '-o-']
prefixes.forEach(
prefix => (stickyTestElement.style.position = `${prefix}sticky`)
(prefix) => (stickyTestElement.style.position = `${prefix}sticky`),
)
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) {
@ -196,8 +258,8 @@ export default class Picker extends React.PureComponent {
}
// Use Array.prototype.find() when it is more widely supported.
const emojiData = CUSTOM_CATEGORY.emojis.filter(
customEmoji => customEmoji.id === emoji.id
const emojiData = this.CUSTOM.filter(
(customEmoji) => customEmoji.id === emoji.id,
)[0]
for (let key in emojiData) {
if (emojiData.hasOwnProperty(key)) {
@ -222,14 +284,21 @@ export default class Picker extends React.PureComponent {
handleEmojiClick(emoji, e) {
this.props.onClick(emoji, e)
this.handleEmojiSelect(emoji)
}
handleEmojiSelect(emoji) {
this.props.onSelect(emoji)
if (!this.hideRecent && !this.props.recent) frequently.add(emoji)
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
@ -237,7 +306,7 @@ export default class Picker extends React.PureComponent {
this.updateCategoriesSize()
this.handleScrollPaint()
if (SEARCH_CATEGORY.emojis) {
if (this.SEARCH_CATEGORY.emojis) {
component.updateDisplay('none')
}
})
@ -247,7 +316,7 @@ export default class Picker extends React.PureComponent {
handleScroll() {
if (!this.waitingForPaint) {
this.waitingForPaint = true
window.requestAnimationFrame(this.handleScrollPaint)
requestAnimationFrame(this.handleScrollPaint)
}
}
@ -260,8 +329,8 @@ export default class Picker extends React.PureComponent {
let activeCategory = null
if (SEARCH_CATEGORY.emojis) {
activeCategory = SEARCH_CATEGORY
if (this.SEARCH_CATEGORY.emojis) {
activeCategory = this.SEARCH_CATEGORY
} else {
var target = this.scroll,
scrollTop = target.scrollTop,
@ -290,7 +359,7 @@ export default class Picker extends React.PureComponent {
if (scrollTop < minTop) {
activeCategory = this.categories.filter(
category => !(category.anchor === false)
(category) => !(category.anchor === false),
)[0]
} else if (scrollTop + this.clientHeight >= this.scrollHeight) {
activeCategory = this.categories[this.categories.length - 1]
@ -310,7 +379,7 @@ export default class Picker extends React.PureComponent {
}
handleSearch(emojis) {
SEARCH_CATEGORY.emojis = emojis
this.SEARCH_CATEGORY.emojis = emojis
for (let i = 0, l = this.categories.length; i < l; i++) {
let component = this.categoryRefs[`category-${i}`]
@ -322,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()
}
@ -345,21 +416,53 @@ export default class Picker extends React.PureComponent {
}
}
if (SEARCH_CATEGORY.emojis) {
if (this.SEARCH_CATEGORY.emojis) {
this.handleSearch(null)
this.search.clear()
window.requestAnimationFrame(scrollToComponent)
requestAnimationFrame(scrollToComponent)
} else {
scrollToComponent()
}
}
handleSkinChange(skin) {
var newState = { skin: skin }
var newState = { skin: skin },
{ onSkinChange } = this.props
this.setState(newState)
store.update(newState)
onSkinChange(skin)
}
handleKeyDown(e) {
let handled = false
switch (e.keyCode) {
case 13:
let emoji
if (
this.SEARCH_CATEGORY.emojis &&
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
}
break
}
if (handled) {
e.preventDefault()
}
}
updateCategoriesSize() {
@ -407,48 +510,71 @@ export default class Picker extends React.PureComponent {
render() {
var {
perLine,
emojiSize,
set,
sheetSize,
style,
title,
emoji,
color,
native,
backgroundImageFn,
emojisToShowFilter,
showPreview,
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 style={{ width: width, ...style }} className="emoji-mart">
<section
style={{ width: width, ...style }}
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={CUSTOM_CATEGORY.emojis}
custom={this.CUSTOM}
autoFocus={autoFocus}
maxResults={maxResults}
/>
<div
@ -467,11 +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 == RECENT_CATEGORY.id ? recent : undefined}
recent={
category.id == this.RECENT_CATEGORY.id ? recent : undefined
}
custom={
category.id == RECENT_CATEGORY.id
? CUSTOM_CATEGORY.emojis
category.id == this.RECENT_CATEGORY.id
? this.CUSTOM
: undefined
}
emojiProps={{
@ -480,93 +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,
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,
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: () => {},
emojiSize: 24,
perLine: 9,
i18n: {},
style: {},
title: 'Emoji Mart™',
emoji: 'department_store',
color: '#ae65c5',
set: Emoji.defaultProps.set,
skin: Emoji.defaultProps.skin,
native: Emoji.defaultProps.native,
sheetSize: Emoji.defaultProps.sheetSize,
backgroundImageFn: Emoji.defaultProps.backgroundImageFn,
emojisToShowFilter: null,
showPreview: true,
emojiTooltip: Emoji.defaultProps.tooltip,
autoFocus: false,
custom: [],
NimblePicker.propTypes /* remove-proptypes */ = {
...PickerPropTypes,
data: PropTypes.object.isRequired,
}
NimblePicker.defaultProps = { ...PickerDefaultProps }

View File

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

View File

@ -1,26 +1,38 @@
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 }
}
render() {
var { emoji } = this.state,
{ emojiProps, skinsProps, title, emoji: idleEmoji } = this.props
{
emojiProps,
skinsProps,
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 = []
emoticons.forEach(emoticon => {
emoticons.forEach((emoticon) => {
if (knownEmoticons.indexOf(emoticon.toLowerCase()) >= 0) {
return
}
@ -31,21 +43,26 @@ 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 => (
{emojiData.short_names.map((short_name) => (
<span key={short_name} className="emoji-mart-preview-shortname">
:{short_name}:
</span>
))}
</div>
<div className="emoji-mart-preview-emoticons">
{listedEmoticons.map(emoticon => (
{listedEmoticons.map((emoticon) => (
<span key={emoticon} className="emoji-mart-preview-emoticon">
{emoticon}
</span>
@ -57,28 +74,55 @@ 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>
<div className="emoji-mart-preview-skins">
<Skins {...skinsProps} />
</div>
{showSkinTones && (
<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>
)
}
}
}
Preview.propTypes = {
Preview.propTypes /* remove-proptypes */ = {
showSkinTones: PropTypes.bool,
title: PropTypes.string.isRequired,
emoji: PropTypes.string.isRequired,
emojiProps: PropTypes.object.isRequired,
skinsProps: PropTypes.object.isRequired,
}
Preview.defaultProps = {
showSkinTones: true,
onChange: () => {},
}

View File

@ -1,55 +1,122 @@
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,
exclude: this.props.exclude,
custom: this.props.custom,
})
}),
)
}
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,

View File

@ -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: () => {},
}

View File

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

View File

@ -4,16 +4,13 @@ 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) {
var skin = e.currentTarget.getAttribute('data-skin')
var skin = parseInt(e.currentTarget.getAttribute('data-skin'))
var { onChange } = this.props
if (!this.state.opened) {
@ -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,
}

View File

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

View File

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

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,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

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

View File

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

View File

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

View File

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

104
src/utils/data.js Normal file
View File

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

View File

@ -1,167 +0,0 @@
import data from '../data'
import { getData, getSanitizedData, intersect } from '.'
var originalPool = {}
var index = {}
var emojisList = {}
var emoticonsList = {}
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 addCustomToPool(custom, pool) {
custom.forEach(emoji => {
let emojiId = emoji.id || emoji.short_names[0]
if (emojiId && !pool[emojiId]) {
pool[emojiId] = getData(emoji)
emojisList[emojiId] = getSanitizedData(emoji)
}
})
}
function search(
value,
{ emojisToShowFilter, maxResults, include, exclude, 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(data.emojis[result.id])
)
}
if (results && results.length > maxResults) {
results = results.slice(0, maxResults)
}
}
return results
}
export default { search, emojis: emojisList, emoticons: emoticonsList }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,13 @@
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']
function unifiedToNative(unified) {
var unicodes = unified.split('-'),
codePoints = unicodes.map(u => `0x${u}`)
codePoints = unicodes.map((u) => `0x${u}`)
return stringFromCodePoint.apply(null, codePoints)
}
@ -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) {
@ -145,7 +200,7 @@ function intersect(a, b) {
const uniqA = uniq(a)
const uniqB = uniq(b)
return uniqA.filter(item => uniqB.indexOf(item) >= 0)
return uniqA.filter((item) => uniqB.indexOf(item) >= 0)
}
function deepMerge(a, b) {
@ -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,
}

View File

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

71
src/utils/shared-props.js Normal file
View File

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

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

@ -1,69 +1,301 @@
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')}
skin={number('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])}
emoji={text('Emoji', '+1')}
size={number('Emoji size', 64)}
skin={number('Skin tone', 1)}
html={boolean('HTML', false)}
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>
)
})

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

17148
yarn.lock

File diff suppressed because it is too large Load Diff