emoji-picker-react 3.6.1 → 4.0.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/LICENSE +17 -20
  2. package/README.md +129 -168
  3. package/dist/DomUtils/categoryNameFromDom.d.ts +1 -0
  4. package/dist/DomUtils/scrollCategoryIntoView.d.ts +1 -0
  5. package/dist/DomUtils/scrollTo.d.ts +1 -0
  6. package/dist/DomUtils/selectors.d.ts +12 -0
  7. package/dist/components/Layout/Flex.d.ts +14 -0
  8. package/dist/components/Layout/Relative.d.ts +7 -0
  9. package/dist/components/body/Body.d.ts +3 -0
  10. package/dist/components/body/EmojiCategory.d.ts +10 -0
  11. package/dist/components/body/EmojiList.d.ts +3 -0
  12. package/dist/components/body/EmojiVariationPicker.d.ts +3 -0
  13. package/dist/components/body/RecentlyUsed.d.ts +7 -0
  14. package/dist/components/context/ElementRefContext.d.ts +17 -0
  15. package/dist/components/context/PickerConfigContext.d.ts +8 -0
  16. package/dist/components/context/PickerContext.d.ts +21 -0
  17. package/dist/components/emoji/Emoji.d.ts +14 -0
  18. package/dist/components/footer/Preview.d.ts +7 -0
  19. package/dist/components/header/Header.d.ts +3 -0
  20. package/dist/components/header/Search.d.ts +3 -0
  21. package/dist/components/header/SkinTonePicker.d.ts +3 -0
  22. package/dist/components/main/PickerMain.d.ts +7 -0
  23. package/dist/components/navigation/CategoryNavigation.d.ts +3 -0
  24. package/dist/config/categoryConfig.d.ts +21 -0
  25. package/dist/config/cdnUrls.d.ts +2 -0
  26. package/dist/config/config.d.ts +26 -0
  27. package/dist/config/useConfig.d.ts +11 -0
  28. package/dist/data/emojis.d.ts +40 -0
  29. package/dist/data/groups.d.ts +2 -0
  30. package/dist/data/skinToneVariations.d.ts +3 -0
  31. package/dist/dataUtils/DataTypes.d.ts +8 -0
  32. package/dist/dataUtils/alphaNumericEmojiIndex.d.ts +4 -0
  33. package/dist/dataUtils/asEmoji.d.ts +2 -0
  34. package/dist/dataUtils/emojiSelectors.d.ts +15 -0
  35. package/dist/dataUtils/parseNativeEmoji.d.ts +1 -0
  36. package/dist/dataUtils/recentlyUsed.d.ts +11 -0
  37. package/dist/emoji-picker-react.cjs.development.css +13 -0
  38. package/dist/emoji-picker-react.cjs.development.js +7419 -0
  39. package/dist/emoji-picker-react.cjs.development.js.map +1 -0
  40. package/dist/emoji-picker-react.cjs.production.min.js +2 -0
  41. package/dist/emoji-picker-react.cjs.production.min.js.map +1 -0
  42. package/dist/emoji-picker-react.esm.js +7485 -0
  43. package/dist/emoji-picker-react.esm.js.map +1 -0
  44. package/dist/hooks/preloadEmoji.d.ts +4 -0
  45. package/dist/hooks/useActiveCategoryScrollDetection.d.ts +2 -0
  46. package/dist/hooks/useCloseAllOpenToggles.d.ts +4 -0
  47. package/dist/hooks/useEmojiElements.d.ts +1 -0
  48. package/dist/hooks/useEmojiMouseEnter.d.ts +3 -0
  49. package/dist/hooks/useFilter.d.ts +8 -0
  50. package/dist/hooks/useInitialLoad.d.ts +2 -0
  51. package/dist/hooks/useIsEmojiHidden.d.ts +2 -0
  52. package/dist/hooks/useIsSearchMode.d.ts +1 -0
  53. package/dist/hooks/useMouseDownHandlers.d.ts +2 -0
  54. package/dist/hooks/useOnScroll.d.ts +2 -0
  55. package/dist/index.d.ts +7 -0
  56. package/dist/index.js +8 -3
  57. package/dist/types/exposedTypes.d.ts +28 -0
  58. package/package.json +72 -52
  59. package/src/DomUtils/categoryNameFromDom.ts +3 -0
  60. package/src/DomUtils/scrollCategoryIntoView.ts +18 -0
  61. package/src/DomUtils/scrollTo.ts +11 -0
  62. package/src/DomUtils/selectors.ts +93 -0
  63. package/src/EmojiPickerReact.css +85 -0
  64. package/src/components/Layout/Flex.css +11 -0
  65. package/src/components/Layout/Flex.tsx +28 -0
  66. package/src/components/Layout/Relative.tsx +14 -0
  67. package/src/components/body/Body.css +6 -0
  68. package/src/components/body/Body.tsx +24 -0
  69. package/src/components/body/EmojiCategory.css +38 -0
  70. package/src/components/body/EmojiCategory.tsx +27 -0
  71. package/src/components/body/EmojiList.css +5 -0
  72. package/src/components/body/EmojiList.tsx +101 -0
  73. package/src/components/body/EmojiVariationPicker.css +65 -0
  74. package/src/components/body/EmojiVariationPicker.tsx +154 -0
  75. package/src/components/body/RecentlyUsed.tsx +50 -0
  76. package/src/components/body/svg/triangle.svg +11 -0
  77. package/src/components/context/ElementRefContext.tsx +61 -0
  78. package/src/components/context/PickerConfigContext.tsx +29 -0
  79. package/src/components/context/PickerContext.tsx +139 -0
  80. package/src/components/emoji/Emoji.css +44 -0
  81. package/src/components/emoji/Emoji.tsx +104 -0
  82. package/src/components/footer/Preview.css +14 -0
  83. package/src/components/footer/Preview.tsx +80 -0
  84. package/src/components/header/Header.css +4 -0
  85. package/src/components/header/Header.tsx +21 -0
  86. package/src/components/header/Search.css +72 -0
  87. package/src/components/header/Search.tsx +36 -0
  88. package/src/components/header/SkinTonePicker.css +86 -0
  89. package/src/components/header/SkinTonePicker.tsx +55 -0
  90. package/src/components/header/svg/magnifier.svg +13 -0
  91. package/src/components/header/svg/times.svg +33 -0
  92. package/src/components/main/PickerMain.css +11 -0
  93. package/src/components/main/PickerMain.tsx +42 -0
  94. package/src/components/navigation/CategoryNavigation.css +82 -0
  95. package/src/components/navigation/CategoryNavigation.tsx +32 -0
  96. package/src/components/navigation/svg/CategoryNav.svg +508 -0
  97. package/src/config/categoryConfig.ts +107 -0
  98. package/src/config/cdnUrls.ts +24 -0
  99. package/src/config/config.ts +50 -0
  100. package/src/config/useConfig.ts +52 -0
  101. package/src/data/emojis.ts +5350 -0
  102. package/src/data/groups.ts +12 -0
  103. package/src/data/skinToneVariations.ts +12 -0
  104. package/src/dataUtils/DataTypes.ts +10 -0
  105. package/src/dataUtils/alphaNumericEmojiIndex.ts +23 -0
  106. package/src/dataUtils/asEmoji.ts +5 -0
  107. package/src/dataUtils/emojiSelectors.ts +94 -0
  108. package/src/dataUtils/parseNativeEmoji.ts +6 -0
  109. package/src/dataUtils/recentlyUsed.ts +61 -0
  110. package/src/hooks/preloadEmoji.ts +29 -0
  111. package/src/hooks/useActiveCategoryScrollDetection.ts +46 -0
  112. package/src/hooks/useCloseAllOpenToggles.ts +26 -0
  113. package/src/hooks/useEmojiElements.ts +7 -0
  114. package/src/hooks/useEmojiMouseEnter.ts +59 -0
  115. package/src/hooks/useFilter.ts +142 -0
  116. package/src/hooks/useInitialLoad.ts +9 -0
  117. package/src/hooks/useIsEmojiHidden.ts +16 -0
  118. package/src/hooks/useIsSearchMode.ts +7 -0
  119. package/src/hooks/useMouseDownHandlers.ts +160 -0
  120. package/src/hooks/useOnScroll.ts +28 -0
  121. package/src/index.tsx +27 -0
  122. package/src/types/exposedTypes.ts +31 -0
  123. package/.babelrc +0 -30
  124. package/.eslintrc.js +0 -37
  125. package/.github/workflows/npmpublish.yml +0 -30
  126. package/.prettierignore +0 -2
  127. package/.storybook/addons.js +0 -2
  128. package/.storybook/config.js +0 -9
  129. package/assets/captured.gif +0 -0
  130. package/dist/index.js.LICENSE.txt +0 -5
  131. package/dist/index.js.map +0 -1
  132. package/dist/main.css +0 -206
  133. package/dist/main.css.map +0 -1
  134. package/emoji-picker-react.d.ts +0 -45
  135. package/webpack.config.js +0 -52
@@ -0,0 +1,28 @@
1
+ export declare type EmojiClickData = {
2
+ activeSkinTone: SkinTones;
3
+ unified: string;
4
+ unifiedWithoutSkinTone: string;
5
+ emoji: string;
6
+ names: string[];
7
+ getImageUrl: (emojiStyle: EmojiStyle) => string;
8
+ };
9
+ export declare enum EmojiStyle {
10
+ NATIVE = "native",
11
+ APPLE = "apple",
12
+ TWITTER = "twitter",
13
+ GOOGLE = "google",
14
+ FACEBOOK = "facebook"
15
+ }
16
+ export declare enum Theme {
17
+ DARK = "dark",
18
+ LIGHT = "light",
19
+ AUTO = "auto"
20
+ }
21
+ export declare enum SkinTones {
22
+ NEUTRAL = "neutral",
23
+ LIGHT = "1f3fb",
24
+ MEDIUM_LIGHT = "1f3fc",
25
+ MEDIUM = "1f3fd",
26
+ MEDIUM_DARK = "1f3fe",
27
+ DARK = "1f3ff"
28
+ }
package/package.json CHANGED
@@ -1,68 +1,88 @@
1
1
  {
2
- "name": "emoji-picker-react",
3
- "version": "3.6.1",
4
- "description": "Emoji picker component for react applications",
2
+ "version": "4.0.0-rc.3",
3
+ "license": "MIT",
5
4
  "main": "dist/index.js",
6
- "typings": "emoji-picker-react.d.ts",
5
+ "typings": "dist/index.d.ts",
6
+ "files": [
7
+ "dist",
8
+ "src"
9
+ ],
10
+ "engines": {
11
+ "node": ">=10"
12
+ },
7
13
  "scripts": {
14
+ "start": "tsdx watch",
15
+ "build": "tsdx build",
16
+ "test": "tsdx test --passWithNoTests",
17
+ "lint": "tsdx lint",
18
+ "prepare": "tsdx build",
19
+ "size": "size-limit",
20
+ "analyze": "size-limit --why",
8
21
  "storybook": "start-storybook -p 6006",
9
- "build": "webpack --config ./webpack.config.js",
10
- "build-storybook": "build-storybook",
11
- "lint": "eslint ."
22
+ "build-storybook": "build-storybook"
12
23
  },
13
- "repository": {
14
- "type": "git",
15
- "url": "git+https://github.com/ealush/emoji-picker-react.git"
16
- },
17
- "keywords": [
18
- "emoji-picker",
19
- "react"
20
- ],
21
- "author": "ealush",
22
- "license": "unlicense",
23
- "bugs": {
24
- "url": "https://github.com/ealush/emoji-picker-react/issues"
24
+ "peerDependencies": {
25
+ "react": ">=16"
25
26
  },
26
27
  "husky": {
27
28
  "hooks": {
28
- "pre-commit": "pretty-quick --staged"
29
+ "pre-commit": "tsdx lint"
29
30
  }
30
31
  },
31
32
  "prettier": {
32
- "arrowParens": "avoid",
33
+ "printWidth": 80,
34
+ "semi": true,
33
35
  "singleQuote": true
34
36
  },
35
- "homepage": "https://github.com/ealush/emoji-picker-react#readme",
37
+ "name": "emoji-picker-react",
38
+ "author": "ealush",
39
+ "module": "dist/emoji-picker-react.esm.js",
40
+ "size-limit": [
41
+ {
42
+ "path": "dist/emoji-picker-react.cjs.production.min.js",
43
+ "limit": "10 KB"
44
+ },
45
+ {
46
+ "path": "dist/emoji-picker-react.esm.js",
47
+ "limit": "10 KB"
48
+ }
49
+ ],
36
50
  "devDependencies": {
37
- "@babel/core": "^7.6.0",
38
- "@babel/plugin-transform-runtime": "^7.6.0",
39
- "@babel/preset-env": "^7.6.0",
40
- "@babel/preset-react": "^7.0.0",
41
- "@storybook/addon-actions": "^6.4.18",
42
- "@storybook/addon-links": "^6.4.18",
43
- "@storybook/addons": "^6.4.18",
44
- "@storybook/react": "^6.4.18",
45
- "babel-loader": "^8.0.6",
46
- "classnames": "^2.2.6",
47
- "css-loader": "^3.2.0",
48
- "emoji-datasource": "^7.0.2",
49
- "eslint": "^7.5.0",
50
- "eslint-plugin-import": "^2.18.2",
51
- "eslint-plugin-react": "^7.14.3",
52
- "eslint-plugin-react-hooks": "^2.0.1",
53
- "husky": "^4.2.5",
54
- "lodash": "^4.17.15",
55
- "mini-css-extract-plugin": "^0.8.0",
56
- "prettier": "2.0.5",
57
- "pretty-quick": "^2.0.1",
58
- "prop-types": "^15.7.2",
59
- "react": "^16.9.0",
60
- "react-dom": "^16.9.0",
61
- "style-loader": "^1.0.0",
62
- "svg-url-loader": "^3.0.2",
63
- "terser-webpack-plugin": "^2.1.0",
64
- "webpack": "^4.40.2",
65
- "webpack-cli": "^3.3.9",
66
- "tinykeys": "^1.3.0"
51
+ "eslint-import-resolver-typescript": "^3.3.0",
52
+ "eslint-plugin-import": "^2.26.0",
53
+ "@babel/core": "^7.18.10",
54
+ "@size-limit/preset-small-lib": "^8.0.1",
55
+ "@storybook/addon-essentials": "^6.5.10",
56
+ "@storybook/addon-info": "^5.3.21",
57
+ "@storybook/addon-links": "^6.5.10",
58
+ "@storybook/addon-postcss": "^2.0.0",
59
+ "@storybook/addons": "^6.5.10",
60
+ "@storybook/react": "^6.5.10",
61
+ "@types/react": "^18.0.17",
62
+ "@types/react-dom": "^18.0.6",
63
+ "autoprefixer": "^10.4.8",
64
+ "babel-loader": "^8.2.5",
65
+ "cssnano": "^5.1.13",
66
+ "emoji-datasource": "^14.0.0",
67
+ "fs-extra": "^10.1.0",
68
+ "glob": "^8.0.3",
69
+ "husky": "^8.0.1",
70
+ "lodash": "^4.17.21",
71
+ "postcss": "^8.4.16",
72
+ "react": "^18.2.0",
73
+ "react-dom": "^18.2.0",
74
+ "react-is": "^18.2.0",
75
+ "rollup-plugin-postcss": "^4.0.2",
76
+ "size-limit": "^8.0.1",
77
+ "tiny-invariant": "^1.2.0",
78
+ "tinykeys": "^1.4.0",
79
+ "tsdx": "^0.14.1",
80
+ "tslib": "^2.4.0",
81
+ "typescript": "^4.7.4",
82
+ "postcss-inline-svg": "^5.0.0",
83
+ "postcss-svgo": "^5.1.0"
84
+ },
85
+ "dependencies": {
86
+ "clsx": "^1.2.1"
67
87
  }
68
88
  }
@@ -0,0 +1,3 @@
1
+ export function categoryNameFromDom($category: Element | null): string | null {
2
+ return $category?.getAttribute('data-name') ?? null;
3
+ }
@@ -0,0 +1,18 @@
1
+ import { scrollTo } from './scrollTo';
2
+
3
+ export function scrollCategoryIntoView(
4
+ root: HTMLElement | null,
5
+ category: string
6
+ ) {
7
+ const $category = root?.querySelector(
8
+ `[data-name="${category}"]`
9
+ ) as HTMLElement;
10
+
11
+ if (!$category) {
12
+ return;
13
+ }
14
+
15
+ const offsetTop = $category.offsetTop || 0;
16
+
17
+ scrollTo(root, offsetTop);
18
+ }
@@ -0,0 +1,11 @@
1
+ export function scrollTo(root: HTMLElement | null, top: number = 0) {
2
+ const $eprBody = root ? root.querySelector('.epr-body') : null;
3
+
4
+ if (!root || !$eprBody) {
5
+ return;
6
+ }
7
+
8
+ requestAnimationFrame(() => {
9
+ $eprBody.scrollTop = top + 1;
10
+ });
11
+ }
@@ -0,0 +1,93 @@
1
+ import { DataEmoji } from '../dataUtils/DataTypes';
2
+ import { emojiByUnified } from '../dataUtils/emojiSelectors';
3
+
4
+ export function buttonFromEmoji(
5
+ emojiElement: HTMLElement | null
6
+ ): HTMLButtonElement | null {
7
+ return emojiElement?.closest('button.epr-emoji') ?? null;
8
+ }
9
+
10
+ export function emojiFromElement(
11
+ element: HTMLElement | null
12
+ ): DataEmoji | undefined {
13
+ const unified = originalUnifiedFromEmojiElement(element);
14
+
15
+ if (!unified) {
16
+ return;
17
+ }
18
+ return emojiByUnified(unified);
19
+ }
20
+
21
+ export function isEmojiElement(element: HTMLElement | null): boolean {
22
+ return Boolean(
23
+ element?.matches('button.epr-emoji') ||
24
+ element?.parentElement?.matches('button.epr-emoji')
25
+ );
26
+ }
27
+
28
+ export function closestCategory(
29
+ element: HTMLElement | null
30
+ ): HTMLElement | null {
31
+ return element?.closest('.epr-emoji-category') ?? null;
32
+ }
33
+
34
+ export function categoryLabelFromCategory(
35
+ category: HTMLElement | null
36
+ ): HTMLElement | null {
37
+ return category?.querySelector('.epr-emoji-category-label') ?? null;
38
+ }
39
+
40
+ export function closestCategoryLabel(
41
+ element: null | HTMLElement
42
+ ): HTMLElement | null {
43
+ const category = closestCategory(element);
44
+ return categoryLabelFromCategory(category);
45
+ }
46
+
47
+ export function elementHeight(element: HTMLElement | null): number {
48
+ return element?.clientHeight ?? 0;
49
+ }
50
+
51
+ export function emojiTrueOffsetTop(element: HTMLElement | null): number {
52
+ const button = buttonFromEmoji(element);
53
+ const category = closestCategory(button);
54
+
55
+ return elementOffsetTop(button) + elementOffsetTop(category);
56
+ }
57
+ export function emojiTruOffsetLeft(element: HTMLElement | null): number {
58
+ const button = buttonFromEmoji(element);
59
+ const category = closestCategory(button);
60
+
61
+ return elementOffsetLeft(button) + elementOffsetLeft(category);
62
+ }
63
+
64
+ function elementOffsetTop(element: HTMLElement | null): number {
65
+ return element?.offsetTop ?? 0;
66
+ }
67
+
68
+ function elementOffsetLeft(element: HTMLElement | null): number {
69
+ return element?.offsetLeft ?? 0;
70
+ }
71
+
72
+ export function unifiedFromEmojiElement(
73
+ emoji: HTMLElement | null
74
+ ): string | null {
75
+ return elementDataSetKey(buttonFromEmoji(emoji), 'unified') ?? null;
76
+ }
77
+
78
+ export function originalUnifiedFromEmojiElement(
79
+ emoji: HTMLElement | null
80
+ ): string | null {
81
+ return elementDataSetKey(buttonFromEmoji(emoji), 'original') ?? null;
82
+ }
83
+
84
+ function elementDataSetKey(
85
+ element: HTMLElement | null,
86
+ key: string
87
+ ): string | null {
88
+ return elementDataSet(element)[key] ?? null;
89
+ }
90
+
91
+ function elementDataSet(element: HTMLElement | null): DOMStringMap {
92
+ return element?.dataset ?? {};
93
+ }
@@ -0,0 +1,85 @@
1
+ .EmojiPickerReact {
2
+ --highlight-color: #007aeb;
3
+ --hover-backdrop-color: #f1f8ff;
4
+ --text-color-base: #858585;
5
+ --epr-header-height: 70px;
6
+ --epr-picker-width: 350px;
7
+ --epr-picker-height: 500px;
8
+ --epr-emoji-size: 33px;
9
+ --epr-category-navigation-button-size: 30px;
10
+ --epr-emoji-variation-picker-bg-color: var(--epr-background-color);
11
+ --epr-emoji-variation-picker-height: 55px;
12
+ --epr-preview-height: 70px;
13
+ --epr-preview-text-color: var(--text-color-base);
14
+ --epr-preview-text-size: 14px;
15
+ --epr-preview-text-padding: 0 10px;
16
+ --epr-search-bar-bg-color: #f6f6f6;
17
+ --epr-active-category-indicator-color: var(--highlight-color);
18
+ --epr-active-skin-tone-indicator-border-color: var(--highlight-color);
19
+ --epr-search-border-color: var(--highlight-color);
20
+ --epr-active-skin-hover-color: var(--hover-backdrop-color);
21
+ --epr-emoji-hover-color: var(--hover-backdrop-color);
22
+ --epr-category-label-text-color: var(--text-color-base);
23
+ --epr-category-label-background-color: #ffffffe6;
24
+ --epr-emoji-padding: 5px;
25
+ --epr-header-padding: 15px 10px;
26
+ --epr-emoji-gap: 4px;
27
+ --epr-category-padding: 0 10px;
28
+ --epr-search-input-padding: 0 30px;
29
+ --epr-search-input-border-radius: 8px;
30
+ --epr-search-input-height: 40px;
31
+ --epr-category-label-padding: 0 10px;
32
+ --epr-category-label-height: 40px;
33
+
34
+ --epr-header-overlay-z-index: 3;
35
+ --epr-emoji-variations-indictator-z-index: 1;
36
+ --epr-category-label-z-index: 2;
37
+ --epr-skin-variation-picker-z-index: 5;
38
+
39
+ --epr-picker-border-radius: 8px;
40
+ --epr-search-bar-text-color: var(--text-color-base);
41
+ --epr-search-bar-placeholder-color: var(--text-color-base);
42
+ --epr-picker-border-color: #e7e7e7;
43
+ --epr-background-color: #fff;
44
+ --epr-preview-border-color: var(--epr-picker-border-color);
45
+ --epr-search-bar-bg-color-active: var(--epr-search-bar-bg-color);
46
+ --epr-emoji-variation-indicator-color: rgba(0, 0, 0, 0.1);
47
+ --epr-emoji-variation-indicator-color-hover: rgba(0, 0, 0, 0.4);
48
+ }
49
+
50
+ .EmojiPickerReact.epr-dark-theme {
51
+ --epr-emoji-variation-picker-bg-color: #000000;
52
+ --highlight-color: #c0c0c0;
53
+ --text-color-base: var(--highlight-color);
54
+ --hover-backdrop-color: #363636f6;
55
+ --epr-search-bar-bg-color: #333333;
56
+ --epr-category-label-background-color: #222222e6;
57
+ --epr-picker-border-color: #151617;
58
+ --epr-background-color: #222222;
59
+ --epr-search-bar-bg-color-active: #000000;
60
+ --epr-emoji-variation-indicator-color: rgba(255, 255, 255, 0.1);
61
+ --epr-emoji-variation-indicator-color-hover: rgba(255, 255, 255, 0.4);
62
+ }
63
+
64
+ .EmojiPickerReact {
65
+ background-color: var(--epr-background-color);
66
+ overflow: hidden;
67
+ }
68
+
69
+ .EmojiPickerReact .hidden {
70
+ display: none !important;
71
+ opacity: 0 !important;
72
+ pointer-events: none !important;
73
+ visibility: hidden !important;
74
+ }
75
+
76
+ .EmojiPickerReact * {
77
+ box-sizing: border-box;
78
+ font-family: sans-serif;
79
+ }
80
+
81
+ .EmojiPickerReact button {
82
+ cursor: pointer;
83
+ border: 0;
84
+ background: none;
85
+ }
@@ -0,0 +1,11 @@
1
+ .EmojiPickerReact .Flex {
2
+ display: flex;
3
+ }
4
+
5
+ .EmojiPickerReact .Flex.FlexRow {
6
+ flex-direction: row;
7
+ }
8
+
9
+ .EmojiPickerReact .Flex.FlexColumn {
10
+ flex-direction: column;
11
+ }
@@ -0,0 +1,28 @@
1
+ import clsx from 'clsx';
2
+ import * as React from 'react';
3
+ import './Flex.css';
4
+
5
+ export enum FlexDirection {
6
+ ROW = 'FlexRow',
7
+ COLUMN = 'FlexColumn'
8
+ }
9
+
10
+ type Props = Readonly<{
11
+ children: React.ReactNode;
12
+ className?: string;
13
+ style?: React.CSSProperties;
14
+ direction?: FlexDirection;
15
+ }>;
16
+
17
+ export default function Flex({
18
+ children,
19
+ className,
20
+ style = {},
21
+ direction = FlexDirection.ROW
22
+ }: Props) {
23
+ return (
24
+ <div style={{ ...style }} className={clsx('Flex', className, direction)}>
25
+ {children}
26
+ </div>
27
+ );
28
+ }
@@ -0,0 +1,14 @@
1
+ import * as React from 'react';
2
+
3
+ type Props = Readonly<{
4
+ children: React.ReactNode;
5
+ className?: string;
6
+ }>;
7
+
8
+ export default function Relative({ children, className }: Props) {
9
+ return (
10
+ <div style={{ position: 'relative' }} className={className}>
11
+ {children}
12
+ </div>
13
+ );
14
+ }
@@ -0,0 +1,6 @@
1
+ .EmojiPickerReact .epr-body {
2
+ position: relative;
3
+ flex: 1;
4
+ overflow-y: scroll;
5
+ overflow-x: hidden;
6
+ }
@@ -0,0 +1,24 @@
1
+ import * as React from 'react';
2
+
3
+ import { useActiveCategoryScrollDetection } from '../../hooks/useActiveCategoryScrollDetection';
4
+ import { useMouseDownHandlers } from '../../hooks/useMouseDownHandlers';
5
+ import { useOnScroll } from '../../hooks/useOnScroll';
6
+ import { useBodyRef } from '../context/ElementRefContext';
7
+
8
+ import { EmojiList } from './EmojiList';
9
+ import { EmojiVariationPicker } from './EmojiVariationPicker';
10
+ import './Body.css';
11
+
12
+ export function Body() {
13
+ const BodyRef = useBodyRef();
14
+ useActiveCategoryScrollDetection(BodyRef);
15
+ useOnScroll(BodyRef);
16
+ useMouseDownHandlers(BodyRef);
17
+
18
+ return (
19
+ <div className="epr-body" ref={BodyRef}>
20
+ <EmojiVariationPicker />
21
+ <EmojiList />
22
+ </div>
23
+ );
24
+ }
@@ -0,0 +1,38 @@
1
+ .EmojiPickerReact li.epr-emoji-category > .epr-emoji-category-label {
2
+ position: sticky;
3
+ top: 0;
4
+ width: 100%;
5
+ display: flex;
6
+ align-items: center;
7
+ font-weight: bold;
8
+ text-transform: capitalize;
9
+ backdrop-filter: blur(3px);
10
+ padding: var(--epr-category-label-padding);
11
+ background-color: var(--epr-category-label-background-color);
12
+ color: var(--epr-category-label-text-color);
13
+ z-index: var(--epr-category-label-z-index);
14
+ height: var(--epr-category-label-height);
15
+ }
16
+
17
+ .EmojiPickerReact.epr-search-active
18
+ li.epr-emoji-category
19
+ > .epr-emoji-category-label {
20
+ position: relative;
21
+ opacity: 0.4;
22
+ }
23
+
24
+ .EmojiPickerReact li.epr-emoji-category {
25
+ position: relative;
26
+ display: flex;
27
+ flex-direction: row;
28
+ flex-wrap: wrap;
29
+ justify-content: space-around;
30
+ padding: var(--epr-category-padding);
31
+ gap: var(--epr-emoji-gap);
32
+ }
33
+
34
+ .EmojiPickerReact li.epr-emoji-category:after {
35
+ content: '';
36
+ display: inline-block;
37
+ flex: 1;
38
+ }
@@ -0,0 +1,27 @@
1
+ import clsx from 'clsx';
2
+ import * as React from 'react';
3
+
4
+ import {
5
+ CategoryConfig,
6
+ categoryFromCategoryConfig,
7
+ categoryNameFromCategoryConfig
8
+ } from '../../config/categoryConfig';
9
+ import './EmojiCategory.css';
10
+
11
+ type Props = Readonly<{
12
+ categoryConfig: CategoryConfig;
13
+ children?: React.ReactNode;
14
+ hidden?: boolean;
15
+ }>;
16
+
17
+ export function EmojiCategory({ categoryConfig, children, hidden }: Props) {
18
+ const category = categoryFromCategoryConfig(categoryConfig);
19
+ const categoryName = categoryNameFromCategoryConfig(categoryConfig);
20
+
21
+ return (
22
+ <li className={clsx('epr-emoji-category', { hidden })} data-name={category}>
23
+ <div className="epr-emoji-category-label">{categoryName}</div>
24
+ {children}
25
+ </li>
26
+ );
27
+ }
@@ -0,0 +1,5 @@
1
+ .EmojiPickerReact ul.epr-emoji-list {
2
+ list-style: none;
3
+ padding: 0;
4
+ margin: 0;
5
+ }
@@ -0,0 +1,101 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ Categories,
5
+ CategoryConfig,
6
+ categoryFromCategoryConfig
7
+ } from '../../config/categoryConfig';
8
+ import {
9
+ useCategoriesConfig,
10
+ useEmojiStyleConfig
11
+ } from '../../config/useConfig';
12
+ import { emojisByCategory, emojiUnified } from '../../dataUtils/emojiSelectors';
13
+ import { useIsEmojiHidden } from '../../hooks/useIsEmojiHidden';
14
+ import {
15
+ useActiveSkinToneState,
16
+ useIsPastInitialLoad
17
+ } from '../context/PickerContext';
18
+ import { Emoji } from '../emoji/Emoji';
19
+
20
+ import { EmojiCategory } from './EmojiCategory';
21
+ import { RecentlyUsed } from './RecentlyUsed';
22
+ import './EmojiList.css';
23
+
24
+ export function EmojiList() {
25
+ const categories = useCategoriesConfig();
26
+
27
+ return (
28
+ <ul className="epr-emoji-list">
29
+ {categories.map((categoryConfig, index) => {
30
+ const category = categoryFromCategoryConfig(categoryConfig);
31
+
32
+ if (category === Categories.RECENTLY_USED) {
33
+ return (
34
+ <RecentlyUsed key={category} categoryConfig={categoryConfig} />
35
+ );
36
+ }
37
+
38
+ return (
39
+ <RenderCategory
40
+ key={category}
41
+ index={index}
42
+ category={category}
43
+ categoryConfig={categoryConfig}
44
+ />
45
+ );
46
+ })}
47
+ </ul>
48
+ );
49
+ }
50
+
51
+ function RenderCategory({
52
+ index,
53
+ category,
54
+ categoryConfig
55
+ }: {
56
+ index: number;
57
+ category: Categories;
58
+ categoryConfig: CategoryConfig;
59
+ }) {
60
+ const isEmojiHidden = useIsEmojiHidden();
61
+ const emojiStyle = useEmojiStyleConfig();
62
+ const isPastInitialLoad = useIsPastInitialLoad();
63
+ const [activeSkinTone] = useActiveSkinToneState();
64
+
65
+ // Small trick to defer the rendering of all emoji categories until the first category is visible
66
+ // This way the user gets to actually see something and not wait for the whole picker to render.
67
+ const emojisToPush =
68
+ !isPastInitialLoad && index > 1 ? [] : emojisByCategory(category);
69
+
70
+ let hiddenCounter = 0;
71
+
72
+ const emojis = emojisToPush.map(emoji => {
73
+ const unified = emojiUnified(emoji, activeSkinTone);
74
+ const hidden = isEmojiHidden(emoji);
75
+
76
+ if (hidden) {
77
+ hiddenCounter++;
78
+ }
79
+
80
+ return (
81
+ <Emoji
82
+ key={unified}
83
+ emoji={emoji}
84
+ unified={unified}
85
+ hidden={hidden}
86
+ emojiStyle={emojiStyle}
87
+ />
88
+ );
89
+ });
90
+
91
+ return (
92
+ <EmojiCategory
93
+ categoryConfig={categoryConfig}
94
+ // Indicates that there are no visible emojis
95
+ // Hence, the category should be hidden
96
+ hidden={hiddenCounter === emojis.length}
97
+ >
98
+ {emojis}
99
+ </EmojiCategory>
100
+ );
101
+ }