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.
- package/LICENSE +17 -20
- package/README.md +129 -168
- package/dist/DomUtils/categoryNameFromDom.d.ts +1 -0
- package/dist/DomUtils/scrollCategoryIntoView.d.ts +1 -0
- package/dist/DomUtils/scrollTo.d.ts +1 -0
- package/dist/DomUtils/selectors.d.ts +12 -0
- package/dist/components/Layout/Flex.d.ts +14 -0
- package/dist/components/Layout/Relative.d.ts +7 -0
- package/dist/components/body/Body.d.ts +3 -0
- package/dist/components/body/EmojiCategory.d.ts +10 -0
- package/dist/components/body/EmojiList.d.ts +3 -0
- package/dist/components/body/EmojiVariationPicker.d.ts +3 -0
- package/dist/components/body/RecentlyUsed.d.ts +7 -0
- package/dist/components/context/ElementRefContext.d.ts +17 -0
- package/dist/components/context/PickerConfigContext.d.ts +8 -0
- package/dist/components/context/PickerContext.d.ts +21 -0
- package/dist/components/emoji/Emoji.d.ts +14 -0
- package/dist/components/footer/Preview.d.ts +7 -0
- package/dist/components/header/Header.d.ts +3 -0
- package/dist/components/header/Search.d.ts +3 -0
- package/dist/components/header/SkinTonePicker.d.ts +3 -0
- package/dist/components/main/PickerMain.d.ts +7 -0
- package/dist/components/navigation/CategoryNavigation.d.ts +3 -0
- package/dist/config/categoryConfig.d.ts +21 -0
- package/dist/config/cdnUrls.d.ts +2 -0
- package/dist/config/config.d.ts +26 -0
- package/dist/config/useConfig.d.ts +11 -0
- package/dist/data/emojis.d.ts +40 -0
- package/dist/data/groups.d.ts +2 -0
- package/dist/data/skinToneVariations.d.ts +3 -0
- package/dist/dataUtils/DataTypes.d.ts +8 -0
- package/dist/dataUtils/alphaNumericEmojiIndex.d.ts +4 -0
- package/dist/dataUtils/asEmoji.d.ts +2 -0
- package/dist/dataUtils/emojiSelectors.d.ts +15 -0
- package/dist/dataUtils/parseNativeEmoji.d.ts +1 -0
- package/dist/dataUtils/recentlyUsed.d.ts +11 -0
- package/dist/emoji-picker-react.cjs.development.css +13 -0
- package/dist/emoji-picker-react.cjs.development.js +7419 -0
- package/dist/emoji-picker-react.cjs.development.js.map +1 -0
- package/dist/emoji-picker-react.cjs.production.min.js +2 -0
- package/dist/emoji-picker-react.cjs.production.min.js.map +1 -0
- package/dist/emoji-picker-react.esm.js +7485 -0
- package/dist/emoji-picker-react.esm.js.map +1 -0
- package/dist/hooks/preloadEmoji.d.ts +4 -0
- package/dist/hooks/useActiveCategoryScrollDetection.d.ts +2 -0
- package/dist/hooks/useCloseAllOpenToggles.d.ts +4 -0
- package/dist/hooks/useEmojiElements.d.ts +1 -0
- package/dist/hooks/useEmojiMouseEnter.d.ts +3 -0
- package/dist/hooks/useFilter.d.ts +8 -0
- package/dist/hooks/useInitialLoad.d.ts +2 -0
- package/dist/hooks/useIsEmojiHidden.d.ts +2 -0
- package/dist/hooks/useIsSearchMode.d.ts +1 -0
- package/dist/hooks/useMouseDownHandlers.d.ts +2 -0
- package/dist/hooks/useOnScroll.d.ts +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -3
- package/dist/types/exposedTypes.d.ts +28 -0
- package/package.json +72 -52
- package/src/DomUtils/categoryNameFromDom.ts +3 -0
- package/src/DomUtils/scrollCategoryIntoView.ts +18 -0
- package/src/DomUtils/scrollTo.ts +11 -0
- package/src/DomUtils/selectors.ts +93 -0
- package/src/EmojiPickerReact.css +85 -0
- package/src/components/Layout/Flex.css +11 -0
- package/src/components/Layout/Flex.tsx +28 -0
- package/src/components/Layout/Relative.tsx +14 -0
- package/src/components/body/Body.css +6 -0
- package/src/components/body/Body.tsx +24 -0
- package/src/components/body/EmojiCategory.css +38 -0
- package/src/components/body/EmojiCategory.tsx +27 -0
- package/src/components/body/EmojiList.css +5 -0
- package/src/components/body/EmojiList.tsx +101 -0
- package/src/components/body/EmojiVariationPicker.css +65 -0
- package/src/components/body/EmojiVariationPicker.tsx +154 -0
- package/src/components/body/RecentlyUsed.tsx +50 -0
- package/src/components/body/svg/triangle.svg +11 -0
- package/src/components/context/ElementRefContext.tsx +61 -0
- package/src/components/context/PickerConfigContext.tsx +29 -0
- package/src/components/context/PickerContext.tsx +139 -0
- package/src/components/emoji/Emoji.css +44 -0
- package/src/components/emoji/Emoji.tsx +104 -0
- package/src/components/footer/Preview.css +14 -0
- package/src/components/footer/Preview.tsx +80 -0
- package/src/components/header/Header.css +4 -0
- package/src/components/header/Header.tsx +21 -0
- package/src/components/header/Search.css +72 -0
- package/src/components/header/Search.tsx +36 -0
- package/src/components/header/SkinTonePicker.css +86 -0
- package/src/components/header/SkinTonePicker.tsx +55 -0
- package/src/components/header/svg/magnifier.svg +13 -0
- package/src/components/header/svg/times.svg +33 -0
- package/src/components/main/PickerMain.css +11 -0
- package/src/components/main/PickerMain.tsx +42 -0
- package/src/components/navigation/CategoryNavigation.css +82 -0
- package/src/components/navigation/CategoryNavigation.tsx +32 -0
- package/src/components/navigation/svg/CategoryNav.svg +508 -0
- package/src/config/categoryConfig.ts +107 -0
- package/src/config/cdnUrls.ts +24 -0
- package/src/config/config.ts +50 -0
- package/src/config/useConfig.ts +52 -0
- package/src/data/emojis.ts +5350 -0
- package/src/data/groups.ts +12 -0
- package/src/data/skinToneVariations.ts +12 -0
- package/src/dataUtils/DataTypes.ts +10 -0
- package/src/dataUtils/alphaNumericEmojiIndex.ts +23 -0
- package/src/dataUtils/asEmoji.ts +5 -0
- package/src/dataUtils/emojiSelectors.ts +94 -0
- package/src/dataUtils/parseNativeEmoji.ts +6 -0
- package/src/dataUtils/recentlyUsed.ts +61 -0
- package/src/hooks/preloadEmoji.ts +29 -0
- package/src/hooks/useActiveCategoryScrollDetection.ts +46 -0
- package/src/hooks/useCloseAllOpenToggles.ts +26 -0
- package/src/hooks/useEmojiElements.ts +7 -0
- package/src/hooks/useEmojiMouseEnter.ts +59 -0
- package/src/hooks/useFilter.ts +142 -0
- package/src/hooks/useInitialLoad.ts +9 -0
- package/src/hooks/useIsEmojiHidden.ts +16 -0
- package/src/hooks/useIsSearchMode.ts +7 -0
- package/src/hooks/useMouseDownHandlers.ts +160 -0
- package/src/hooks/useOnScroll.ts +28 -0
- package/src/index.tsx +27 -0
- package/src/types/exposedTypes.ts +31 -0
- package/.babelrc +0 -30
- package/.eslintrc.js +0 -37
- package/.github/workflows/npmpublish.yml +0 -30
- package/.prettierignore +0 -2
- package/.storybook/addons.js +0 -2
- package/.storybook/config.js +0 -9
- package/assets/captured.gif +0 -0
- package/dist/index.js.LICENSE.txt +0 -5
- package/dist/index.js.map +0 -1
- package/dist/main.css +0 -206
- package/dist/main.css.map +0 -1
- package/emoji-picker-react.d.ts +0 -45
- 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
|
-
"
|
|
3
|
-
"
|
|
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": "
|
|
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": "
|
|
10
|
-
"build-storybook": "build-storybook",
|
|
11
|
-
"lint": "eslint ."
|
|
22
|
+
"build-storybook": "build-storybook"
|
|
12
23
|
},
|
|
13
|
-
"
|
|
14
|
-
"
|
|
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": "
|
|
29
|
+
"pre-commit": "tsdx lint"
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
32
|
"prettier": {
|
|
32
|
-
"
|
|
33
|
+
"printWidth": 80,
|
|
34
|
+
"semi": true,
|
|
33
35
|
"singleQuote": true
|
|
34
36
|
},
|
|
35
|
-
"
|
|
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
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"@babel/
|
|
40
|
-
"@
|
|
41
|
-
"@storybook/addon-
|
|
42
|
-
"@storybook/addon-
|
|
43
|
-
"@storybook/
|
|
44
|
-
"@storybook/
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"react": "^
|
|
60
|
-
"react-
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
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,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,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,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,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,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
|
+
}
|