emoji-picker-react 4.4.12 → 4.5.0
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/README.md +64 -26
- package/dist/components/emoji/BaseEmojiProps.d.ts +12 -0
- package/dist/components/emoji/ClickableEmojiButton.d.ts +13 -0
- package/dist/components/emoji/Emoji.d.ts +3 -13
- package/dist/components/emoji/EmojiImg.d.ts +10 -0
- package/dist/components/emoji/ExportedEmoji.d.ts +2 -2
- package/dist/components/emoji/NativeEmoji.d.ts +5 -0
- package/dist/components/emoji/ViewOnlyEmoji.d.ts +3 -0
- package/dist/config/categoryConfig.d.ts +4 -0
- package/dist/config/config.d.ts +3 -1
- package/dist/config/customEmojiConfig.d.ts +6 -0
- package/dist/config/useConfig.d.ts +2 -0
- package/dist/data/emojis.d.ts +1 -0
- package/dist/dataUtils/DataTypes.d.ts +16 -6
- package/dist/dataUtils/alphaNumericEmojiIndex.d.ts +1 -0
- package/dist/dataUtils/emojiSelectors.d.ts +5 -3
- package/dist/emoji-picker-react.cjs.development.css +2 -2
- package/dist/emoji-picker-react.cjs.development.js +284 -184
- package/dist/emoji-picker-react.cjs.development.js.map +1 -1
- package/dist/emoji-picker-react.cjs.production.min.js +1 -1
- package/dist/emoji-picker-react.cjs.production.min.js.map +1 -1
- package/dist/emoji-picker-react.esm.js +294 -194
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/dist/hooks/preloadEmoji.d.ts +1 -1
- package/dist/hooks/useShouldHideCustomEmojis.d.ts +1 -0
- package/dist/typeRefinements/typeRefinements.d.ts +5 -0
- package/dist/types/exposedTypes.d.ts +1 -0
- package/package.json +5 -5
- package/src/components/context/PickerConfigContext.tsx +2 -1
- package/src/components/emoji/BaseEmojiProps.ts +13 -0
- package/src/components/emoji/ClickableEmojiButton.tsx +42 -0
- package/src/components/emoji/Emoji.css +2 -0
- package/src/components/emoji/Emoji.tsx +15 -125
- package/src/components/emoji/EmojiImg.tsx +31 -0
- package/src/components/emoji/ExportedEmoji.tsx +3 -2
- package/src/components/emoji/NativeEmoji.tsx +23 -0
- package/src/components/emoji/ViewOnlyEmoji.tsx +70 -0
- package/src/components/footer/Preview.tsx +1 -1
- package/src/components/navigation/CategoryNavigation.css +3 -0
- package/src/components/navigation/CategoryNavigation.tsx +8 -0
- package/src/config/categoryConfig.ts +10 -0
- package/src/config/config.ts +10 -2
- package/src/config/customEmojiConfig.ts +7 -0
- package/src/config/useConfig.ts +8 -2
- package/src/data/emojis.json +1 -1
- package/src/data/emojis.ts +1 -1
- package/src/dataUtils/DataTypes.ts +19 -6
- package/src/dataUtils/alphaNumericEmojiIndex.ts +16 -11
- package/src/dataUtils/emojiSelectors.ts +30 -11
- package/src/hooks/preloadEmoji.ts +1 -1
- package/src/hooks/useEmojiPreviewEvents.ts +0 -2
- package/src/hooks/useMouseDownHandlers.ts +1 -1
- package/src/hooks/useShouldHideCustomEmojis.ts +11 -0
- package/src/typeRefinements/typeRefinements.ts +17 -0
- package/src/types/exposedTypes.ts +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GetEmojiUrl } from '../components/emoji/
|
|
1
|
+
import { GetEmojiUrl } from '../components/emoji/BaseEmojiProps';
|
|
2
2
|
import { DataEmoji } from '../dataUtils/DataTypes';
|
|
3
3
|
import { EmojiStyle } from '../types/exposedTypes';
|
|
4
4
|
export declare function preloadEmoji(getEmojiUrl: GetEmojiUrl, emoji: undefined | DataEmoji, emojiStyle: EmojiStyle): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useShouldHideCustomEmojis(): boolean;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { CategoryConfig, CustomCategoryConfig } from '../config/categoryConfig';
|
|
2
|
+
import { CustomEmoji } from '../config/customEmojiConfig';
|
|
3
|
+
import { DataEmoji } from '../dataUtils/DataTypes';
|
|
4
|
+
export declare function isCustomCategory(category: CategoryConfig | CustomCategoryConfig): category is CustomCategoryConfig;
|
|
5
|
+
export declare function isCustomEmoji(emoji: Partial<DataEmoji>): emoji is CustomEmoji;
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.
|
|
2
|
+
"version": "4.5.0",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -77,6 +77,9 @@
|
|
|
77
77
|
"emoji-datasource": "^14.0.0",
|
|
78
78
|
"eslint-import-resolver-typescript": "^3.3.0",
|
|
79
79
|
"eslint-plugin-import": "^2.26.0",
|
|
80
|
+
"eslint-plugin-jsx-a11y": "^6.6.1",
|
|
81
|
+
"eslint-plugin-react": "^7.31.8",
|
|
82
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
80
83
|
"fs-extra": "^10.1.0",
|
|
81
84
|
"glob": "^8.0.3",
|
|
82
85
|
"husky": "^8.0.1",
|
|
@@ -92,10 +95,7 @@
|
|
|
92
95
|
"tiny-invariant": "^1.2.0",
|
|
93
96
|
"tsdx": "^0.14.1",
|
|
94
97
|
"tslib": "^2.4.0",
|
|
95
|
-
"typescript": "^4.7.4"
|
|
96
|
-
"eslint-plugin-jsx-a11y": "^6.6.1",
|
|
97
|
-
"eslint-plugin-react": "^7.31.8",
|
|
98
|
-
"eslint-plugin-react-hooks": "^4.6.0"
|
|
98
|
+
"typescript": "^4.7.4"
|
|
99
99
|
},
|
|
100
100
|
"dependencies": {
|
|
101
101
|
"clsx": "^1.2.1"
|
|
@@ -17,8 +17,9 @@ const ConfigContext = React.createContext<PickerConfigInternal>(
|
|
|
17
17
|
);
|
|
18
18
|
|
|
19
19
|
export function PickerConfigProvider({ children, ...config }: Props) {
|
|
20
|
+
const [mergedConfig] = React.useState(() => mergeConfig(config));
|
|
20
21
|
return (
|
|
21
|
-
<ConfigContext.Provider value={
|
|
22
|
+
<ConfigContext.Provider value={mergedConfig}>
|
|
22
23
|
{children}
|
|
23
24
|
</ConfigContext.Provider>
|
|
24
25
|
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CustomEmoji } from '../../config/customEmojiConfig';
|
|
2
|
+
import { DataEmoji } from '../../dataUtils/DataTypes';
|
|
3
|
+
import { EmojiStyle } from '../../types/exposedTypes';
|
|
4
|
+
|
|
5
|
+
export type BaseEmojiProps = {
|
|
6
|
+
emoji?: DataEmoji | CustomEmoji;
|
|
7
|
+
emojiStyle: EmojiStyle;
|
|
8
|
+
unified: string;
|
|
9
|
+
size?: number;
|
|
10
|
+
lazyLoad?: boolean;
|
|
11
|
+
getEmojiUrl?: GetEmojiUrl;
|
|
12
|
+
};
|
|
13
|
+
export type GetEmojiUrl = (unified: string, style: EmojiStyle) => string;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { ClassNames } from '../../DomUtils/classNames';
|
|
5
|
+
import { Button } from '../atoms/Button';
|
|
6
|
+
import './Emoji.css';
|
|
7
|
+
|
|
8
|
+
type ClickableEmojiButtonProps = Readonly<{
|
|
9
|
+
hidden?: boolean;
|
|
10
|
+
showVariations?: boolean;
|
|
11
|
+
hiddenOnSearch?: boolean;
|
|
12
|
+
emojiNames: string[];
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
hasVariations: boolean;
|
|
15
|
+
unified?: string;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
18
|
+
export function ClickableEmojiButton({
|
|
19
|
+
emojiNames,
|
|
20
|
+
unified,
|
|
21
|
+
hidden,
|
|
22
|
+
hiddenOnSearch,
|
|
23
|
+
showVariations = true,
|
|
24
|
+
hasVariations,
|
|
25
|
+
children
|
|
26
|
+
}: ClickableEmojiButtonProps) {
|
|
27
|
+
return (
|
|
28
|
+
<Button
|
|
29
|
+
className={clsx(ClassNames.emoji, {
|
|
30
|
+
[ClassNames.hidden]: hidden,
|
|
31
|
+
[ClassNames.hiddenOnSearch]: hiddenOnSearch,
|
|
32
|
+
[ClassNames.visible]: !hidden && !hiddenOnSearch,
|
|
33
|
+
[ClassNames.emojiHasVariations]: hasVariations && showVariations
|
|
34
|
+
})}
|
|
35
|
+
data-unified={unified}
|
|
36
|
+
aria-label={emojiNames[0]}
|
|
37
|
+
data-full-name={emojiNames}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
</Button>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
.EmojiPickerReact button.epr-emoji .epr-emoji-img {
|
|
31
31
|
max-width: var(--epr-emoji-fullsize);
|
|
32
32
|
max-height: var(--epr-emoji-fullsize);
|
|
33
|
+
min-width: var(--epr-emoji-fullsize);
|
|
34
|
+
min-height: var(--epr-emoji-fullsize);
|
|
33
35
|
padding: var(--epr-emoji-padding);
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
import clsx from 'clsx';
|
|
2
1
|
import * as React from 'react';
|
|
3
2
|
|
|
4
|
-
import { ClassNames } from '../../DomUtils/classNames';
|
|
5
3
|
import { DataEmoji } from '../../dataUtils/DataTypes';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
emojiHasVariations,
|
|
9
|
-
emojiName,
|
|
10
|
-
emojiNames,
|
|
11
|
-
emojiUrlByUnified,
|
|
12
|
-
} from '../../dataUtils/emojiSelectors';
|
|
13
|
-
import { parseNativeEmoji } from '../../dataUtils/parseNativeEmoji';
|
|
14
|
-
import { EmojiStyle } from '../../types/exposedTypes';
|
|
15
|
-
import { Button } from '../atoms/Button';
|
|
16
|
-
import { useEmojisThatFailedToLoadState } from '../context/PickerContext';
|
|
4
|
+
import { emojiHasVariations, emojiNames } from '../../dataUtils/emojiSelectors';
|
|
5
|
+
|
|
17
6
|
import './Emoji.css';
|
|
7
|
+
import { BaseEmojiProps } from './BaseEmojiProps';
|
|
8
|
+
import { ClickableEmojiButton } from './ClickableEmojiButton';
|
|
9
|
+
import { ViewOnlyEmoji } from './ViewOnlyEmoji';
|
|
18
10
|
|
|
19
11
|
type ClickableEmojiProps = Readonly<
|
|
20
|
-
|
|
12
|
+
BaseEmojiProps & {
|
|
21
13
|
hidden?: boolean;
|
|
22
14
|
showVariations?: boolean;
|
|
23
15
|
hiddenOnSearch?: boolean;
|
|
@@ -25,15 +17,6 @@ type ClickableEmojiProps = Readonly<
|
|
|
25
17
|
}
|
|
26
18
|
>;
|
|
27
19
|
|
|
28
|
-
type BaseProps = {
|
|
29
|
-
emoji?: DataEmoji;
|
|
30
|
-
emojiStyle: EmojiStyle;
|
|
31
|
-
unified: string;
|
|
32
|
-
size?: number;
|
|
33
|
-
lazyLoad?: boolean;
|
|
34
|
-
getEmojiUrl?: GetEmojiUrl;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
20
|
export function ClickableEmoji({
|
|
38
21
|
emoji,
|
|
39
22
|
unified,
|
|
@@ -43,22 +26,18 @@ export function ClickableEmoji({
|
|
|
43
26
|
showVariations = true,
|
|
44
27
|
size,
|
|
45
28
|
lazyLoad,
|
|
46
|
-
getEmojiUrl
|
|
29
|
+
getEmojiUrl
|
|
47
30
|
}: ClickableEmojiProps) {
|
|
48
31
|
const hasVariations = emojiHasVariations(emoji);
|
|
49
32
|
|
|
50
33
|
return (
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
data-unified={unified}
|
|
59
|
-
// @ts-ignore - let's ignore the fact this is not a real react ref, ok?
|
|
60
|
-
aria-label={emojiName(emoji)}
|
|
61
|
-
data-full-name={emojiNames(emoji)}
|
|
34
|
+
<ClickableEmojiButton
|
|
35
|
+
hasVariations={hasVariations}
|
|
36
|
+
showVariations={showVariations}
|
|
37
|
+
hidden={hidden}
|
|
38
|
+
hiddenOnSearch={hiddenOnSearch}
|
|
39
|
+
emojiNames={emojiNames(emoji)}
|
|
40
|
+
unified={unified}
|
|
62
41
|
>
|
|
63
42
|
<ViewOnlyEmoji
|
|
64
43
|
unified={unified}
|
|
@@ -68,95 +47,6 @@ export function ClickableEmoji({
|
|
|
68
47
|
lazyLoad={lazyLoad}
|
|
69
48
|
getEmojiUrl={getEmojiUrl}
|
|
70
49
|
/>
|
|
71
|
-
</
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function ViewOnlyEmoji({
|
|
76
|
-
emoji,
|
|
77
|
-
unified,
|
|
78
|
-
emojiStyle,
|
|
79
|
-
size,
|
|
80
|
-
lazyLoad,
|
|
81
|
-
getEmojiUrl = emojiUrlByUnified,
|
|
82
|
-
}: BaseProps) {
|
|
83
|
-
const style = {} as React.CSSProperties;
|
|
84
|
-
if (size) {
|
|
85
|
-
style.width = style.height = style.fontSize = `${size}px`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const emojiToRender = emoji ? emoji : emojiByUnified(unified);
|
|
89
|
-
if(!emojiToRender) {
|
|
90
|
-
return null
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<>
|
|
95
|
-
{emojiStyle === EmojiStyle.NATIVE ? (
|
|
96
|
-
<NativeEmoji unified={unified} style={style} />
|
|
97
|
-
) : (
|
|
98
|
-
<EmojiImg
|
|
99
|
-
unified={unified}
|
|
100
|
-
style={style}
|
|
101
|
-
emoji={emojiToRender}
|
|
102
|
-
emojiStyle={emojiStyle}
|
|
103
|
-
lazyLoad={lazyLoad}
|
|
104
|
-
getEmojiUrl={getEmojiUrl}
|
|
105
|
-
/>
|
|
106
|
-
)}
|
|
107
|
-
</>
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function NativeEmoji({
|
|
112
|
-
unified,
|
|
113
|
-
style,
|
|
114
|
-
}: {
|
|
115
|
-
unified: string;
|
|
116
|
-
style: React.CSSProperties;
|
|
117
|
-
}) {
|
|
118
|
-
return (
|
|
119
|
-
<span
|
|
120
|
-
className={clsx(ClassNames.external, 'epr-emoji-native')}
|
|
121
|
-
data-unified={unified}
|
|
122
|
-
style={style}
|
|
123
|
-
>
|
|
124
|
-
{parseNativeEmoji(unified)}
|
|
125
|
-
</span>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function EmojiImg({
|
|
130
|
-
emoji,
|
|
131
|
-
unified,
|
|
132
|
-
emojiStyle,
|
|
133
|
-
style,
|
|
134
|
-
lazyLoad = false,
|
|
135
|
-
getEmojiUrl,
|
|
136
|
-
}: {
|
|
137
|
-
emoji: DataEmoji;
|
|
138
|
-
unified: string;
|
|
139
|
-
emojiStyle: EmojiStyle;
|
|
140
|
-
style: React.CSSProperties;
|
|
141
|
-
lazyLoad?: boolean;
|
|
142
|
-
getEmojiUrl: GetEmojiUrl;
|
|
143
|
-
}) {
|
|
144
|
-
const [, setEmojisThatFailedToLoad] = useEmojisThatFailedToLoadState();
|
|
145
|
-
|
|
146
|
-
return (
|
|
147
|
-
<img
|
|
148
|
-
src={getEmojiUrl(unified, emojiStyle)}
|
|
149
|
-
alt={emojiName(emoji)}
|
|
150
|
-
className={clsx(ClassNames.external, 'epr-emoji-img')}
|
|
151
|
-
loading={lazyLoad ? 'lazy' : 'eager'}
|
|
152
|
-
onError={onError}
|
|
153
|
-
style={style}
|
|
154
|
-
/>
|
|
50
|
+
</ClickableEmojiButton>
|
|
155
51
|
);
|
|
156
|
-
|
|
157
|
-
function onError() {
|
|
158
|
-
setEmojisThatFailedToLoad((prev) => new Set(prev).add(unified));
|
|
159
|
-
}
|
|
160
52
|
}
|
|
161
|
-
|
|
162
|
-
export type GetEmojiUrl = (unified: string, style: EmojiStyle) => string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { ClassNames } from '../../DomUtils/classNames';
|
|
5
|
+
import { EmojiStyle } from '../../types/exposedTypes';
|
|
6
|
+
|
|
7
|
+
export function EmojiImg({
|
|
8
|
+
emojiName,
|
|
9
|
+
style,
|
|
10
|
+
lazyLoad = false,
|
|
11
|
+
imgUrl,
|
|
12
|
+
onError
|
|
13
|
+
}: {
|
|
14
|
+
emojiName: string;
|
|
15
|
+
emojiStyle: EmojiStyle;
|
|
16
|
+
style: React.CSSProperties;
|
|
17
|
+
lazyLoad?: boolean;
|
|
18
|
+
imgUrl: string;
|
|
19
|
+
onError: () => void;
|
|
20
|
+
}) {
|
|
21
|
+
return (
|
|
22
|
+
<img
|
|
23
|
+
src={imgUrl}
|
|
24
|
+
alt={emojiName}
|
|
25
|
+
className={clsx(ClassNames.external, 'epr-emoji-img')}
|
|
26
|
+
loading={lazyLoad ? 'lazy' : 'eager'}
|
|
27
|
+
onError={onError}
|
|
28
|
+
style={style}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -2,14 +2,15 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { EmojiStyle } from '../../types/exposedTypes';
|
|
4
4
|
|
|
5
|
-
import { GetEmojiUrl
|
|
5
|
+
import { GetEmojiUrl } from './BaseEmojiProps';
|
|
6
|
+
import { ViewOnlyEmoji } from './ViewOnlyEmoji';
|
|
6
7
|
|
|
7
8
|
export function ExportedEmoji({
|
|
8
9
|
unified,
|
|
9
10
|
size = 32,
|
|
10
11
|
emojiStyle = EmojiStyle.APPLE,
|
|
11
12
|
lazyLoad = false,
|
|
12
|
-
getEmojiUrl
|
|
13
|
+
getEmojiUrl
|
|
13
14
|
}: {
|
|
14
15
|
unified: string;
|
|
15
16
|
emojiStyle?: EmojiStyle;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { ClassNames } from '../../DomUtils/classNames';
|
|
5
|
+
import { parseNativeEmoji } from '../../dataUtils/parseNativeEmoji';
|
|
6
|
+
|
|
7
|
+
export function NativeEmoji({
|
|
8
|
+
unified,
|
|
9
|
+
style
|
|
10
|
+
}: {
|
|
11
|
+
unified: string;
|
|
12
|
+
style: React.CSSProperties;
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<span
|
|
16
|
+
className={clsx(ClassNames.external, 'epr-emoji-native')}
|
|
17
|
+
data-unified={unified}
|
|
18
|
+
style={style}
|
|
19
|
+
>
|
|
20
|
+
{parseNativeEmoji(unified)}
|
|
21
|
+
</span>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
emojiByUnified,
|
|
5
|
+
emojiName,
|
|
6
|
+
emojiUrlByUnified
|
|
7
|
+
} from '../../dataUtils/emojiSelectors';
|
|
8
|
+
import { isCustomEmoji } from '../../typeRefinements/typeRefinements';
|
|
9
|
+
import { EmojiStyle } from '../../types/exposedTypes';
|
|
10
|
+
import { useEmojisThatFailedToLoadState } from '../context/PickerContext';
|
|
11
|
+
|
|
12
|
+
import { BaseEmojiProps } from './BaseEmojiProps';
|
|
13
|
+
import { EmojiImg } from './EmojiImg';
|
|
14
|
+
import { NativeEmoji } from './NativeEmoji';
|
|
15
|
+
|
|
16
|
+
export function ViewOnlyEmoji({
|
|
17
|
+
emoji,
|
|
18
|
+
unified,
|
|
19
|
+
emojiStyle,
|
|
20
|
+
size,
|
|
21
|
+
lazyLoad,
|
|
22
|
+
getEmojiUrl = emojiUrlByUnified
|
|
23
|
+
}: BaseEmojiProps) {
|
|
24
|
+
const [, setEmojisThatFailedToLoad] = useEmojisThatFailedToLoadState();
|
|
25
|
+
|
|
26
|
+
const style = {} as React.CSSProperties;
|
|
27
|
+
if (size) {
|
|
28
|
+
style.width = style.height = style.fontSize = `${size}px`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const emojiToRender = emoji ? emoji : emojiByUnified(unified);
|
|
32
|
+
|
|
33
|
+
if (!emojiToRender) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (isCustomEmoji(emojiToRender)) {
|
|
38
|
+
return (
|
|
39
|
+
<EmojiImg
|
|
40
|
+
style={style}
|
|
41
|
+
emojiName={unified}
|
|
42
|
+
emojiStyle={emojiStyle}
|
|
43
|
+
lazyLoad={lazyLoad}
|
|
44
|
+
imgUrl={emojiToRender.imgUrl}
|
|
45
|
+
onError={onError}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
{emojiStyle === EmojiStyle.NATIVE ? (
|
|
53
|
+
<NativeEmoji unified={unified} style={style} />
|
|
54
|
+
) : (
|
|
55
|
+
<EmojiImg
|
|
56
|
+
style={style}
|
|
57
|
+
emojiName={emojiName(emojiToRender)}
|
|
58
|
+
emojiStyle={emojiStyle}
|
|
59
|
+
lazyLoad={lazyLoad}
|
|
60
|
+
imgUrl={getEmojiUrl(unified, emojiStyle)}
|
|
61
|
+
onError={onError}
|
|
62
|
+
/>
|
|
63
|
+
)}
|
|
64
|
+
</>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
function onError() {
|
|
68
|
+
setEmojisThatFailedToLoad(prev => new Set(prev).add(unified));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -16,9 +16,9 @@ import { useIsSkinToneInPreview } from '../../hooks/useShouldShowSkinTonePicker'
|
|
|
16
16
|
import Flex from '../Layout/Flex';
|
|
17
17
|
import Space from '../Layout/Space';
|
|
18
18
|
import { useEmojiVariationPickerState } from '../context/PickerContext';
|
|
19
|
-
import { ViewOnlyEmoji } from '../emoji/Emoji';
|
|
20
19
|
import './Preview.css';
|
|
21
20
|
import { SkinTonePickerMenu } from '../header/SkinTonePicker';
|
|
21
|
+
import { ViewOnlyEmoji } from '../emoji/ViewOnlyEmoji';
|
|
22
22
|
|
|
23
23
|
export function Preview() {
|
|
24
24
|
const previewConfig = usePreviewConfig();
|
|
@@ -87,6 +87,9 @@ aside.EmojiPickerReact.epr-main:has(input:placeholder-shown) .epr-category-nav {
|
|
|
87
87
|
.EmojiPickerReact button.epr-cat-btn.epr-icn-suggested {
|
|
88
88
|
background-position-x: calc(var(--epr-category-navigation-button-size) * -8);
|
|
89
89
|
}
|
|
90
|
+
.EmojiPickerReact button.epr-cat-btn.epr-icn-custom {
|
|
91
|
+
background-position-x: calc(var(--epr-category-navigation-button-size) * -9);
|
|
92
|
+
}
|
|
90
93
|
.EmojiPickerReact button.epr-cat-btn.epr-icn-activities {
|
|
91
94
|
background-position-x: calc(var(--epr-category-navigation-button-size) * -4);
|
|
92
95
|
}
|
|
@@ -12,6 +12,8 @@ import { useCategoriesConfig } from '../../config/useConfig';
|
|
|
12
12
|
import { useActiveCategoryScrollDetection } from '../../hooks/useActiveCategoryScrollDetection';
|
|
13
13
|
import useIsSearchMode from '../../hooks/useIsSearchMode';
|
|
14
14
|
import { useScrollCategoryIntoView } from '../../hooks/useScrollCategoryIntoView';
|
|
15
|
+
import { useShouldHideCustomEmojis } from '../../hooks/useShouldHideCustomEmojis';
|
|
16
|
+
import { isCustomCategory } from '../../typeRefinements/typeRefinements';
|
|
15
17
|
import { Button } from '../atoms/Button';
|
|
16
18
|
import { useCategoryNavigationRef } from '../context/ElementRefContext';
|
|
17
19
|
|
|
@@ -23,11 +25,17 @@ export function CategoryNavigation() {
|
|
|
23
25
|
|
|
24
26
|
const categoriesConfig = useCategoriesConfig();
|
|
25
27
|
const CategoryNavigationRef = useCategoryNavigationRef();
|
|
28
|
+
const hideCustomCategory = useShouldHideCustomEmojis();
|
|
26
29
|
|
|
27
30
|
return (
|
|
28
31
|
<div className="epr-category-nav" ref={CategoryNavigationRef}>
|
|
29
32
|
{categoriesConfig.map(categoryConfig => {
|
|
30
33
|
const category = categoryFromCategoryConfig(categoryConfig);
|
|
34
|
+
|
|
35
|
+
if (isCustomCategory(categoryConfig) && hideCustomCategory) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
return (
|
|
32
40
|
<Button
|
|
33
41
|
tabIndex={isSearchMode ? -1 : 0}
|
|
@@ -4,6 +4,7 @@ export { Categories };
|
|
|
4
4
|
|
|
5
5
|
const categoriesOrdered: Categories[] = [
|
|
6
6
|
Categories.SUGGESTED,
|
|
7
|
+
Categories.CUSTOM,
|
|
7
8
|
Categories.SMILEYS_PEOPLE,
|
|
8
9
|
Categories.ANIMALS_NATURE,
|
|
9
10
|
Categories.FOOD_DRINK,
|
|
@@ -19,11 +20,20 @@ export const SuggestedRecent: CategoryConfig = {
|
|
|
19
20
|
category: Categories.SUGGESTED
|
|
20
21
|
};
|
|
21
22
|
|
|
23
|
+
export type CustomCategoryConfig = {
|
|
24
|
+
category: Categories.CUSTOM;
|
|
25
|
+
name: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
22
28
|
const configByCategory: Record<Categories, CategoryConfig> = {
|
|
23
29
|
[Categories.SUGGESTED]: {
|
|
24
30
|
category: Categories.SUGGESTED,
|
|
25
31
|
name: 'Frequently Used'
|
|
26
32
|
},
|
|
33
|
+
[Categories.CUSTOM]: {
|
|
34
|
+
category: Categories.CUSTOM,
|
|
35
|
+
name: 'Custom Emojis'
|
|
36
|
+
},
|
|
27
37
|
[Categories.SMILEYS_PEOPLE]: {
|
|
28
38
|
category: Categories.SMILEYS_PEOPLE,
|
|
29
39
|
name: 'Smileys & People'
|
package/src/config/config.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { GetEmojiUrl } from '../components/emoji/
|
|
2
|
-
import {
|
|
1
|
+
import { GetEmojiUrl } from '../components/emoji/BaseEmojiProps';
|
|
2
|
+
import {
|
|
3
|
+
addCustomEmojis,
|
|
4
|
+
emojiUrlByUnified
|
|
5
|
+
} from '../dataUtils/emojiSelectors';
|
|
3
6
|
import {
|
|
4
7
|
EmojiClickData,
|
|
5
8
|
EmojiStyle,
|
|
@@ -14,6 +17,7 @@ import {
|
|
|
14
17
|
baseCategoriesConfig,
|
|
15
18
|
mergeCategoriesConfig
|
|
16
19
|
} from './categoryConfig';
|
|
20
|
+
import { CustomEmoji } from './customEmojiConfig';
|
|
17
21
|
|
|
18
22
|
const KNOWN_FAILING_EMOJIS = ['2640-fe0f', '2642-fe0f', '2695-fe0f'];
|
|
19
23
|
|
|
@@ -34,6 +38,8 @@ export function mergeConfig(
|
|
|
34
38
|
suggestionMode: config.suggestedEmojisMode
|
|
35
39
|
});
|
|
36
40
|
|
|
41
|
+
addCustomEmojis(config.customEmojis ?? []);
|
|
42
|
+
|
|
37
43
|
const skinTonePickerLocation = config.searchDisabled
|
|
38
44
|
? SkinTonePickerLocation.PREVIEW
|
|
39
45
|
: config.skinTonePickerLocation;
|
|
@@ -50,6 +56,7 @@ export function basePickerConfig(): PickerConfigInternal {
|
|
|
50
56
|
return {
|
|
51
57
|
autoFocusSearch: true,
|
|
52
58
|
categories: baseCategoriesConfig(),
|
|
59
|
+
customEmojis: [],
|
|
53
60
|
defaultSkinTone: SkinTones.NEUTRAL,
|
|
54
61
|
emojiStyle: EmojiStyle.APPLE,
|
|
55
62
|
emojiVersion: null,
|
|
@@ -99,6 +106,7 @@ export type PickerConfigInternal = {
|
|
|
99
106
|
searchDisabled: boolean;
|
|
100
107
|
skinTonePickerLocation: SkinTonePickerLocation;
|
|
101
108
|
unicodeToHide: Set<string>;
|
|
109
|
+
customEmojis: CustomEmoji[];
|
|
102
110
|
};
|
|
103
111
|
|
|
104
112
|
export type PreviewConfig = {
|
package/src/config/useConfig.ts
CHANGED
|
@@ -13,14 +13,15 @@ import { CategoriesConfig } from './categoryConfig';
|
|
|
13
13
|
import {
|
|
14
14
|
DEFAULT_SEARCH_PLACEHOLDER,
|
|
15
15
|
PickerDimensions,
|
|
16
|
-
PreviewConfig
|
|
16
|
+
PreviewConfig
|
|
17
17
|
} from './config';
|
|
18
|
+
import { CustomEmoji } from './customEmojiConfig';
|
|
18
19
|
|
|
19
20
|
export function useSearchPlaceHolderConfig(): string {
|
|
20
21
|
const { searchPlaceHolder, searchPlaceholder } = usePickerConfig();
|
|
21
22
|
return (
|
|
22
23
|
[searchPlaceHolder, searchPlaceholder].find(
|
|
23
|
-
|
|
24
|
+
p => p !== DEFAULT_SEARCH_PLACEHOLDER
|
|
24
25
|
) ?? DEFAULT_SEARCH_PLACEHOLDER
|
|
25
26
|
);
|
|
26
27
|
}
|
|
@@ -50,6 +51,11 @@ export function useCategoriesConfig(): CategoriesConfig {
|
|
|
50
51
|
return categories;
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
export function useCustomEmojisConfig(): CustomEmoji[] {
|
|
55
|
+
const { customEmojis } = usePickerConfig();
|
|
56
|
+
return customEmojis;
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
export function useOnEmojiClickConfig(): (
|
|
54
60
|
emoji: EmojiClickData,
|
|
55
61
|
event: MouseEvent
|