emoji-picker-react 4.6.15 → 4.7.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 +37 -12
- package/dist/components/Reactions/BtnPlus.d.ts +2 -0
- package/dist/components/Reactions/DEFAULT_REACTIONS.d.ts +1 -0
- package/dist/components/Reactions/Reactions.d.ts +2 -0
- package/dist/components/context/ElementRefContext.d.ts +1 -0
- package/dist/components/context/PickerContext.d.ts +1 -0
- package/dist/components/emoji/ClickableEmojiButton.d.ts +2 -1
- package/dist/components/emoji/Emoji.d.ts +2 -1
- package/dist/config/config.d.ts +2 -0
- package/dist/config/useConfig.d.ts +2 -0
- package/dist/emoji-picker-react.cjs.development.js +931 -725
- 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 +932 -726
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/package.json +5 -2
- package/src/EmojiPickerReact.tsx +28 -3
- package/src/Stylesheet/stylesheet.tsx +14 -2
- package/src/components/Reactions/BtnPlus.tsx +78 -0
- package/src/components/Reactions/DEFAULT_REACTIONS.ts +9 -0
- package/src/components/Reactions/Reactions.tsx +62 -0
- package/src/components/Reactions/svg/plus.svg +17 -0
- package/src/components/body/Body.tsx +8 -2
- package/src/components/context/ElementRefContext.tsx +10 -2
- package/src/components/context/PickerContext.tsx +16 -3
- package/src/components/emoji/ClickableEmojiButton.tsx +8 -2
- package/src/components/emoji/Emoji.tsx +4 -1
- package/src/components/footer/Preview.tsx +7 -2
- package/src/components/header/Header.tsx +5 -1
- package/src/components/main/PickerMain.tsx +27 -2
- package/src/config/config.ts +7 -2
- package/src/config/useConfig.ts +16 -3
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.
|
|
2
|
+
"version": "4.7.0",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
"emoji-picker",
|
|
13
13
|
"react-emoji-picker",
|
|
14
14
|
"emoji",
|
|
15
|
-
"emojis"
|
|
15
|
+
"emojis",
|
|
16
|
+
"reactions",
|
|
17
|
+
"reactions-picker",
|
|
18
|
+
"emoji-reactions"
|
|
16
19
|
],
|
|
17
20
|
"engines": {
|
|
18
21
|
"node": ">=10"
|
package/src/EmojiPickerReact.tsx
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import { Reactions } from './components/Reactions/Reactions';
|
|
3
4
|
import { Body } from './components/body/Body';
|
|
4
5
|
import { ElementRefContextProvider } from './components/context/ElementRefContext';
|
|
5
6
|
import { PickerConfigProvider } from './components/context/PickerConfigContext';
|
|
7
|
+
import { useReactionsModeState } from './components/context/PickerContext';
|
|
6
8
|
import { Preview } from './components/footer/Preview';
|
|
7
9
|
import { Header } from './components/header/Header';
|
|
8
10
|
import PickerMain from './components/main/PickerMain';
|
|
@@ -14,21 +16,44 @@ function EmojiPicker(props: PickerProps) {
|
|
|
14
16
|
<ElementRefContextProvider>
|
|
15
17
|
<PickerConfigProvider {...props}>
|
|
16
18
|
<PickerMain>
|
|
17
|
-
<
|
|
18
|
-
<Body />
|
|
19
|
-
<Preview />
|
|
19
|
+
<ContentControl />
|
|
20
20
|
</PickerMain>
|
|
21
21
|
</PickerConfigProvider>
|
|
22
22
|
</ElementRefContextProvider>
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function ContentControl() {
|
|
27
|
+
const [reactionsDefaultOpen] = useReactionsModeState();
|
|
28
|
+
const [renderAll, setRenderAll] = React.useState(!reactionsDefaultOpen);
|
|
29
|
+
|
|
30
|
+
React.useEffect(() => {
|
|
31
|
+
if (!renderAll) {
|
|
32
|
+
setRenderAll(true);
|
|
33
|
+
}
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<Reactions />
|
|
39
|
+
{renderAll ? (
|
|
40
|
+
<>
|
|
41
|
+
<Header />
|
|
42
|
+
<Body />
|
|
43
|
+
<Preview />
|
|
44
|
+
</>
|
|
45
|
+
) : null}
|
|
46
|
+
</>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
26
50
|
// eslint-disable-next-line complexity
|
|
27
51
|
export default React.memo(EmojiPicker, (prev, next) => {
|
|
28
52
|
const prevCustomEmojis = prev.customEmojis ?? [];
|
|
29
53
|
const nextCustomEmojis = next.customEmojis ?? [];
|
|
30
54
|
return (
|
|
31
55
|
prev.emojiVersion === next.emojiVersion &&
|
|
56
|
+
prev.reactionsDefaultOpen === next.reactionsDefaultOpen &&
|
|
32
57
|
prev.searchPlaceHolder === next.searchPlaceHolder &&
|
|
33
58
|
prev.searchPlaceholder === next.searchPlaceholder &&
|
|
34
59
|
prev.defaultSkinTone === next.defaultSkinTone &&
|
|
@@ -10,7 +10,8 @@ const hidden = {
|
|
|
10
10
|
display: 'none',
|
|
11
11
|
opacity: '0',
|
|
12
12
|
pointerEvents: 'none',
|
|
13
|
-
visibility: 'hidden'
|
|
13
|
+
visibility: 'hidden',
|
|
14
|
+
overflow: 'hidden'
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
export const commonStyles = stylesheet.create({
|
|
@@ -53,7 +54,18 @@ export const commonInteractionStyles = stylesheet.create({
|
|
|
53
54
|
visibleOnSearchOnly: hidden
|
|
54
55
|
}
|
|
55
56
|
},
|
|
56
|
-
|
|
57
|
+
hiddenOnReactions: {
|
|
58
|
+
transition: 'all 0.5s ease-in-out'
|
|
59
|
+
},
|
|
60
|
+
'.epr-reactions': {
|
|
61
|
+
hiddenOnReactions: {
|
|
62
|
+
height: '0px',
|
|
63
|
+
width: '0px',
|
|
64
|
+
opacity: '0',
|
|
65
|
+
pointerEvents: 'none',
|
|
66
|
+
overflow: 'hidden'
|
|
67
|
+
}
|
|
68
|
+
},
|
|
57
69
|
'.EmojiPickerReact:not(.epr-search-active)': {
|
|
58
70
|
categoryBtn: {
|
|
59
71
|
':hover': {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { cx } from 'flairup';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { stylesheet } from '../../Stylesheet/stylesheet';
|
|
5
|
+
import { Button } from '../atoms/Button';
|
|
6
|
+
import { useReactionsModeState } from '../context/PickerContext';
|
|
7
|
+
|
|
8
|
+
import Plus from './svg/plus.svg';
|
|
9
|
+
|
|
10
|
+
export function BtnPlus() {
|
|
11
|
+
const [, setReactionsMode] = useReactionsModeState();
|
|
12
|
+
return (
|
|
13
|
+
<Button
|
|
14
|
+
aria-label="Show all Emojis"
|
|
15
|
+
title="Show all Emojis"
|
|
16
|
+
tabIndex={0}
|
|
17
|
+
className={cx(styles.plusSign)}
|
|
18
|
+
onClick={() => setReactionsMode(false)}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const styles = stylesheet.create({
|
|
24
|
+
plusSign: {
|
|
25
|
+
fontSize: '20px',
|
|
26
|
+
padding: '18px',
|
|
27
|
+
color: 'var(--epr-text-color)',
|
|
28
|
+
borderRadius: '50%',
|
|
29
|
+
textAlign: 'center',
|
|
30
|
+
lineHeight: '100%',
|
|
31
|
+
width: '20px',
|
|
32
|
+
height: '20px',
|
|
33
|
+
display: 'flex',
|
|
34
|
+
justifyContent: 'center',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
transition: 'background-color 0.1s ease-in-out',
|
|
37
|
+
':after': {
|
|
38
|
+
content: '',
|
|
39
|
+
minWidth: '20px',
|
|
40
|
+
minHeight: '20px',
|
|
41
|
+
backgroundImage: `url(${Plus})`,
|
|
42
|
+
backgroundColor: 'transparent',
|
|
43
|
+
backgroundRepeat: 'no-repeat',
|
|
44
|
+
backgroundSize: '20px',
|
|
45
|
+
backgroundPositionY: '0'
|
|
46
|
+
},
|
|
47
|
+
':hover': {
|
|
48
|
+
color: 'var(--epr-highlight-color)',
|
|
49
|
+
backgroundColor: 'var(--epr-hover-bg-color)',
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
':after': {
|
|
52
|
+
backgroundPositionY: '-20px'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
':focus': {
|
|
56
|
+
color: 'var(--epr-highlight-color)',
|
|
57
|
+
backgroundColor: 'var(--epr-hover-bg-color)',
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
':after': {
|
|
60
|
+
backgroundPositionY: '-40px'
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
'.epr-dark-theme': {
|
|
65
|
+
plusSign: {
|
|
66
|
+
':after': { backgroundPositionY: '-40px' },
|
|
67
|
+
':hover:after': { backgroundPositionY: '-60px' }
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
'.epr-auto-theme': {
|
|
71
|
+
plusSign: {
|
|
72
|
+
'@media (prefers-color-scheme: dark)': {
|
|
73
|
+
':after': { backgroundPositionY: '-40px' },
|
|
74
|
+
':hover:after': { backgroundPositionY: '-60px' }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { cx } from 'flairup';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { commonStyles, stylesheet } from '../../Stylesheet/stylesheet';
|
|
5
|
+
import {
|
|
6
|
+
useEmojiStyleConfig,
|
|
7
|
+
useReactionsConfig
|
|
8
|
+
} from '../../config/useConfig';
|
|
9
|
+
import { DataEmoji } from '../../dataUtils/DataTypes';
|
|
10
|
+
import { emojiByUnified } from '../../dataUtils/emojiSelectors';
|
|
11
|
+
import { useMouseDownHandlers } from '../../hooks/useMouseDownHandlers';
|
|
12
|
+
import { useReactionsRef } from '../context/ElementRefContext';
|
|
13
|
+
import { useReactionsModeState } from '../context/PickerContext';
|
|
14
|
+
import { ClickableEmoji } from '../emoji/Emoji';
|
|
15
|
+
|
|
16
|
+
import { BtnPlus } from './BtnPlus';
|
|
17
|
+
|
|
18
|
+
export function Reactions() {
|
|
19
|
+
const [reactionsOpen] = useReactionsModeState();
|
|
20
|
+
const ReactionsRef = useReactionsRef();
|
|
21
|
+
const reactions = useReactionsConfig();
|
|
22
|
+
useMouseDownHandlers(ReactionsRef);
|
|
23
|
+
const emojiStyle = useEmojiStyleConfig();
|
|
24
|
+
|
|
25
|
+
if (!reactionsOpen) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<ul
|
|
31
|
+
className={cx(styles.list, !reactionsOpen && commonStyles.hidden)}
|
|
32
|
+
ref={ReactionsRef}
|
|
33
|
+
>
|
|
34
|
+
{reactions.map(reaction => (
|
|
35
|
+
<li key={reaction}>
|
|
36
|
+
<ClickableEmoji
|
|
37
|
+
emoji={emojiByUnified(reaction) as DataEmoji}
|
|
38
|
+
emojiStyle={emojiStyle}
|
|
39
|
+
unified={reaction}
|
|
40
|
+
showVariations={false}
|
|
41
|
+
round
|
|
42
|
+
/>
|
|
43
|
+
</li>
|
|
44
|
+
))}
|
|
45
|
+
<li>
|
|
46
|
+
<BtnPlus />
|
|
47
|
+
</li>
|
|
48
|
+
</ul>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const styles = stylesheet.create({
|
|
53
|
+
list: {
|
|
54
|
+
listStyle: 'none',
|
|
55
|
+
margin: '0',
|
|
56
|
+
padding: '0 5px',
|
|
57
|
+
display: 'flex',
|
|
58
|
+
justifyContent: 'space-between',
|
|
59
|
+
alignItems: 'center',
|
|
60
|
+
height: '100%'
|
|
61
|
+
}
|
|
62
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!-- Generator: Adobe Illustrator 28.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
3
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
4
|
+
width="20px" height="80px" viewBox="0 0 20 80" enable-background="new 0 0 20 80" xml:space="preserve">
|
|
5
|
+
<path fill="#868686" d="M5.7,10.4c0,0.1,0.1,0.3,0.2,0.4C6,10.9,6.1,11,6.3,11h3.4v3.4c0,0.1,0.1,0.3,0.2,0.4
|
|
6
|
+
c0.1,0.1,0.2,0.2,0.4,0.2c0.3,0,0.5-0.2,0.5-0.5v-3.4h3.4c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5h-3.4V6.7c0-0.3-0.2-0.5-0.5-0.5
|
|
7
|
+
C9.8,6,9.6,6.2,9.6,6.5v3.4H6.2C5.9,9.9,5.7,10.1,5.7,10.4L5.7,10.4z"/>
|
|
8
|
+
<path fill="#3371B7" d="M5.7,30.4c0,0.1,0.1,0.3,0.2,0.4S6.1,31,6.3,31h3.4v3.4c0,0.1,0.1,0.3,0.2,0.4c0.1,0.1,0.2,0.2,0.4,0.2
|
|
9
|
+
c0.3,0,0.5-0.2,0.5-0.5v-3.4h3.4c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5h-3.4v-3.4c0-0.3-0.2-0.5-0.5-0.5s-0.5,0.2-0.5,0.5v3.4H6.2
|
|
10
|
+
C5.9,29.9,5.7,30.1,5.7,30.4L5.7,30.4z"/>
|
|
11
|
+
<path fill="#C0C0BF" d="M5.7,50.4c0,0.1,0.1,0.3,0.2,0.4C6,50.9,6.1,51,6.3,51h3.4v3.4c0,0.1,0.1,0.3,0.2,0.4
|
|
12
|
+
c0.1,0.1,0.2,0.2,0.4,0.2c0.3,0,0.5-0.2,0.5-0.5v-3.4h3.4c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5h-3.4v-3.4c0-0.3-0.2-0.5-0.5-0.5
|
|
13
|
+
s-0.5,0.2-0.5,0.5v3.4H6.2C5.9,49.9,5.7,50.1,5.7,50.4L5.7,50.4z"/>
|
|
14
|
+
<path fill="#6AA9DD" d="M5.7,70.4c0,0.1,0.1,0.3,0.2,0.4S6.1,71,6.3,71h3.4v3.4c0,0.1,0.1,0.3,0.2,0.4c0.1,0.1,0.2,0.2,0.4,0.2
|
|
15
|
+
c0.3,0,0.5-0.2,0.5-0.5v-3.4h3.4c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5h-3.4v-3.4c0-0.3-0.2-0.5-0.5-0.5s-0.5,0.2-0.5,0.5v3.4H6.4
|
|
16
|
+
C5.9,69.9,5.7,70.1,5.7,70.4L5.7,70.4z"/>
|
|
17
|
+
</svg>
|
|
@@ -2,7 +2,10 @@ import { cx } from 'flairup';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
4
|
import { ClassNames } from '../../DomUtils/classNames';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
commonInteractionStyles,
|
|
7
|
+
stylesheet
|
|
8
|
+
} from '../../Stylesheet/stylesheet';
|
|
6
9
|
import { useOnMouseMove } from '../../hooks/useDisallowMouseMove';
|
|
7
10
|
import { useMouseDownHandlers } from '../../hooks/useMouseDownHandlers';
|
|
8
11
|
import { useOnScroll } from '../../hooks/useOnScroll';
|
|
@@ -18,7 +21,10 @@ export function Body() {
|
|
|
18
21
|
useOnMouseMove();
|
|
19
22
|
|
|
20
23
|
return (
|
|
21
|
-
<div
|
|
24
|
+
<div
|
|
25
|
+
className={cx(styles.body, commonInteractionStyles.hiddenOnReactions)}
|
|
26
|
+
ref={BodyRef}
|
|
27
|
+
>
|
|
22
28
|
<EmojiVariationPicker />
|
|
23
29
|
<EmojiList />
|
|
24
30
|
</div>
|
|
@@ -15,6 +15,7 @@ export function ElementRefContextProvider({
|
|
|
15
15
|
const SkinTonePickerRef = React.useRef<HTMLDivElement>(null);
|
|
16
16
|
const CategoryNavigationRef = React.useRef<HTMLDivElement>(null);
|
|
17
17
|
const VariationPickerRef = React.useRef<HTMLDivElement>(null);
|
|
18
|
+
const ReactionsRef = React.useRef<HTMLUListElement>(null);
|
|
18
19
|
|
|
19
20
|
return (
|
|
20
21
|
<ElementRefContext.Provider
|
|
@@ -25,7 +26,8 @@ export function ElementRefContextProvider({
|
|
|
25
26
|
PickerMainRef,
|
|
26
27
|
SearchInputRef,
|
|
27
28
|
SkinTonePickerRef,
|
|
28
|
-
VariationPickerRef
|
|
29
|
+
VariationPickerRef,
|
|
30
|
+
ReactionsRef
|
|
29
31
|
}}
|
|
30
32
|
>
|
|
31
33
|
{children}
|
|
@@ -45,6 +47,7 @@ type ElementRefs = {
|
|
|
45
47
|
BodyRef: ElementRef<HTMLDivElement>;
|
|
46
48
|
CategoryNavigationRef: ElementRef<HTMLDivElement>;
|
|
47
49
|
VariationPickerRef: ElementRef<HTMLDivElement>;
|
|
50
|
+
ReactionsRef: ElementRef<HTMLUListElement>;
|
|
48
51
|
};
|
|
49
52
|
|
|
50
53
|
const ElementRefContext = React.createContext<ElementRefs>({
|
|
@@ -54,7 +57,8 @@ const ElementRefContext = React.createContext<ElementRefs>({
|
|
|
54
57
|
PickerMainRef: React.createRef(),
|
|
55
58
|
SearchInputRef: React.createRef(),
|
|
56
59
|
SkinTonePickerRef: React.createRef(),
|
|
57
|
-
VariationPickerRef: React.createRef()
|
|
60
|
+
VariationPickerRef: React.createRef(),
|
|
61
|
+
ReactionsRef: React.createRef()
|
|
58
62
|
});
|
|
59
63
|
|
|
60
64
|
function useElementRef() {
|
|
@@ -84,6 +88,10 @@ export function useBodyRef() {
|
|
|
84
88
|
return useElementRef()['BodyRef'];
|
|
85
89
|
}
|
|
86
90
|
|
|
91
|
+
export function useReactionsRef() {
|
|
92
|
+
return useElementRef()['ReactionsRef'];
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
export function useSearchInputRef() {
|
|
88
96
|
return useElementRef()['SearchInputRef'];
|
|
89
97
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
useDefaultSkinToneConfig,
|
|
6
|
+
useReactionsOpenConfig
|
|
7
|
+
} from '../../config/useConfig';
|
|
5
8
|
import { DataEmoji } from '../../dataUtils/DataTypes';
|
|
6
9
|
import { alphaNumericEmojiIndex } from '../../dataUtils/alphaNumericEmojiIndex';
|
|
7
10
|
import { useDebouncedState } from '../../hooks/useDebouncedState';
|
|
@@ -13,6 +16,7 @@ import { SkinTones } from '../../types/exposedTypes';
|
|
|
13
16
|
export function PickerContextProvider({ children }: Props) {
|
|
14
17
|
const disallowedEmojis = useDisallowedEmojis();
|
|
15
18
|
const defaultSkinTone = useDefaultSkinToneConfig();
|
|
19
|
+
const reactionsDefaultOpen = useReactionsOpenConfig();
|
|
16
20
|
|
|
17
21
|
// Initialize the filter with the inititial dictionary
|
|
18
22
|
const filterRef = React.useRef<FilterState>(alphaNumericEmojiIndex);
|
|
@@ -29,6 +33,7 @@ export function PickerContextProvider({ children }: Props) {
|
|
|
29
33
|
const activeCategoryState = useState<ActiveCategoryState>(null);
|
|
30
34
|
const emojisThatFailedToLoadState = useState<Set<string>>(new Set());
|
|
31
35
|
const emojiVariationPickerState = useState<DataEmoji | null>(null);
|
|
36
|
+
const reactionsModeState = useState(reactionsDefaultOpen);
|
|
32
37
|
const [isPastInitialLoad, setIsPastInitialLoad] = useState(false);
|
|
33
38
|
|
|
34
39
|
useMarkInitialLoad(setIsPastInitialLoad);
|
|
@@ -47,7 +52,8 @@ export function PickerContextProvider({ children }: Props) {
|
|
|
47
52
|
isPastInitialLoad,
|
|
48
53
|
searchTerm,
|
|
49
54
|
skinToneFanOpenState,
|
|
50
|
-
suggestedUpdateState
|
|
55
|
+
suggestedUpdateState,
|
|
56
|
+
reactionsModeState
|
|
51
57
|
}}
|
|
52
58
|
>
|
|
53
59
|
{children}
|
|
@@ -70,6 +76,7 @@ const PickerContext = React.createContext<{
|
|
|
70
76
|
disallowClickRef: React.MutableRefObject<boolean>;
|
|
71
77
|
disallowMouseRef: React.MutableRefObject<boolean>;
|
|
72
78
|
disallowedEmojisRef: React.MutableRefObject<Record<string, boolean>>;
|
|
79
|
+
reactionsModeState: ReactState<boolean>;
|
|
73
80
|
}>({
|
|
74
81
|
activeCategoryState: [null, () => {}],
|
|
75
82
|
activeSkinTone: [SkinTones.NEUTRAL, () => {}],
|
|
@@ -82,7 +89,8 @@ const PickerContext = React.createContext<{
|
|
|
82
89
|
isPastInitialLoad: true,
|
|
83
90
|
searchTerm: ['', () => new Promise<string>(() => undefined)],
|
|
84
91
|
skinToneFanOpenState: [false, () => {}],
|
|
85
|
-
suggestedUpdateState: [Date.now(), () => {}]
|
|
92
|
+
suggestedUpdateState: [Date.now(), () => {}],
|
|
93
|
+
reactionsModeState: [false, () => {}]
|
|
86
94
|
});
|
|
87
95
|
|
|
88
96
|
type Props = Readonly<{
|
|
@@ -104,6 +112,11 @@ export function useDisallowMouseRef() {
|
|
|
104
112
|
return disallowMouseRef;
|
|
105
113
|
}
|
|
106
114
|
|
|
115
|
+
export function useReactionsModeState() {
|
|
116
|
+
const { reactionsModeState } = React.useContext(PickerContext);
|
|
117
|
+
return reactionsModeState;
|
|
118
|
+
}
|
|
119
|
+
|
|
107
120
|
export function useSearchTermState() {
|
|
108
121
|
const { searchTerm } = React.useContext(PickerContext);
|
|
109
122
|
return searchTerm;
|
|
@@ -17,6 +17,7 @@ type ClickableEmojiButtonProps = Readonly<{
|
|
|
17
17
|
children: React.ReactNode;
|
|
18
18
|
hasVariations: boolean;
|
|
19
19
|
unified?: string;
|
|
20
|
+
round?: boolean;
|
|
20
21
|
}>;
|
|
21
22
|
|
|
22
23
|
export function ClickableEmojiButton({
|
|
@@ -26,7 +27,8 @@ export function ClickableEmojiButton({
|
|
|
26
27
|
hiddenOnSearch,
|
|
27
28
|
showVariations = true,
|
|
28
29
|
hasVariations,
|
|
29
|
-
children
|
|
30
|
+
children,
|
|
31
|
+
round = false
|
|
30
32
|
}: ClickableEmojiButtonProps) {
|
|
31
33
|
return (
|
|
32
34
|
<Button
|
|
@@ -37,7 +39,8 @@ export function ClickableEmojiButton({
|
|
|
37
39
|
{
|
|
38
40
|
[ClassNames.visible]: !hidden && !hiddenOnSearch
|
|
39
41
|
},
|
|
40
|
-
!!(hasVariations && showVariations) && styles.hasVariations
|
|
42
|
+
!!(hasVariations && showVariations) && styles.hasVariations,
|
|
43
|
+
round && styles.round
|
|
41
44
|
)}
|
|
42
45
|
data-unified={unified}
|
|
43
46
|
aria-label={emojiNames[0]}
|
|
@@ -70,6 +73,9 @@ const styles = stylesheet.create({
|
|
|
70
73
|
backgroundColor: 'var(--epr-focus-bg-color)'
|
|
71
74
|
}
|
|
72
75
|
},
|
|
76
|
+
round: {
|
|
77
|
+
borderRadius: '50%'
|
|
78
|
+
},
|
|
73
79
|
hasVariations: {
|
|
74
80
|
'.': ClassNames.emojiHasVariations,
|
|
75
81
|
':after': {
|
|
@@ -14,6 +14,7 @@ type ClickableEmojiProps = Readonly<
|
|
|
14
14
|
hiddenOnSearch?: boolean;
|
|
15
15
|
emoji: DataEmoji;
|
|
16
16
|
className?: string;
|
|
17
|
+
round?: boolean;
|
|
17
18
|
}
|
|
18
19
|
>;
|
|
19
20
|
|
|
@@ -26,7 +27,8 @@ export function ClickableEmoji({
|
|
|
26
27
|
showVariations = true,
|
|
27
28
|
size,
|
|
28
29
|
lazyLoad,
|
|
29
|
-
getEmojiUrl
|
|
30
|
+
getEmojiUrl,
|
|
31
|
+
round = false
|
|
30
32
|
}: ClickableEmojiProps) {
|
|
31
33
|
const hasVariations = emojiHasVariations(emoji);
|
|
32
34
|
|
|
@@ -38,6 +40,7 @@ export function ClickableEmoji({
|
|
|
38
40
|
hiddenOnSearch={hiddenOnSearch}
|
|
39
41
|
emojiNames={emojiNames(emoji)}
|
|
40
42
|
unified={unified}
|
|
43
|
+
round={round}
|
|
41
44
|
>
|
|
42
45
|
<ViewOnlyEmoji
|
|
43
46
|
unified={unified}
|
|
@@ -2,7 +2,10 @@ import { cx } from 'flairup';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
commonInteractionStyles,
|
|
7
|
+
stylesheet
|
|
8
|
+
} from '../../Stylesheet/stylesheet';
|
|
6
9
|
import {
|
|
7
10
|
useEmojiStyleConfig,
|
|
8
11
|
useGetEmojiUrlConfig,
|
|
@@ -30,7 +33,9 @@ export function Preview() {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
return (
|
|
33
|
-
<Flex
|
|
36
|
+
<Flex
|
|
37
|
+
className={cx(styles.preview, commonInteractionStyles.hiddenOnReactions)}
|
|
38
|
+
>
|
|
34
39
|
<PreviewBody />
|
|
35
40
|
<Space />
|
|
36
41
|
{isSkinToneInPreview ? <SkinTonePickerMenu /> : null}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { cx } from 'flairup';
|
|
1
2
|
import * as React from 'react';
|
|
2
3
|
|
|
4
|
+
import { commonInteractionStyles } from '../../Stylesheet/stylesheet';
|
|
3
5
|
import Relative from '../Layout/Relative';
|
|
4
6
|
import { CategoryNavigation } from '../navigation/CategoryNavigation';
|
|
5
7
|
|
|
@@ -7,7 +9,9 @@ import { SearchContainer } from './Search/Search';
|
|
|
7
9
|
|
|
8
10
|
export function Header() {
|
|
9
11
|
return (
|
|
10
|
-
<Relative
|
|
12
|
+
<Relative
|
|
13
|
+
className={cx('epr-header', commonInteractionStyles.hiddenOnReactions)}
|
|
14
|
+
>
|
|
11
15
|
<SearchContainer />
|
|
12
16
|
<CategoryNavigation />
|
|
13
17
|
</Relative>
|
|
@@ -13,7 +13,10 @@ import { useKeyboardNavigation } from '../../hooks/useKeyboardNavigation';
|
|
|
13
13
|
import { useOnFocus } from '../../hooks/useOnFocus';
|
|
14
14
|
import { Theme } from '../../types/exposedTypes';
|
|
15
15
|
import { usePickerMainRef } from '../context/ElementRefContext';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
PickerContextProvider,
|
|
18
|
+
useReactionsModeState
|
|
19
|
+
} from '../context/PickerContext';
|
|
17
20
|
|
|
18
21
|
type Props = Readonly<{
|
|
19
22
|
children: React.ReactNode;
|
|
@@ -35,6 +38,7 @@ type RootProps = Readonly<{
|
|
|
35
38
|
}>;
|
|
36
39
|
|
|
37
40
|
function PickerRootElement({ children }: RootProps) {
|
|
41
|
+
const [reactionsMode] = useReactionsModeState();
|
|
38
42
|
const theme = useThemeConfig();
|
|
39
43
|
const searchModeActive = useIsSearchMode();
|
|
40
44
|
const PickerMainRef = usePickerMainRef();
|
|
@@ -44,6 +48,8 @@ function PickerRootElement({ children }: RootProps) {
|
|
|
44
48
|
useKeyboardNavigation();
|
|
45
49
|
useOnFocus();
|
|
46
50
|
|
|
51
|
+
const { width, height, ...styleProps } = style || {};
|
|
52
|
+
|
|
47
53
|
return (
|
|
48
54
|
<aside
|
|
49
55
|
className={cx(
|
|
@@ -54,10 +60,14 @@ function PickerRootElement({ children }: RootProps) {
|
|
|
54
60
|
{
|
|
55
61
|
[ClassNames.searchActive]: searchModeActive
|
|
56
62
|
},
|
|
63
|
+
reactionsMode && styles.reactionsMenu,
|
|
57
64
|
className
|
|
58
65
|
)}
|
|
59
66
|
ref={PickerMainRef}
|
|
60
|
-
style={
|
|
67
|
+
style={{
|
|
68
|
+
...styleProps,
|
|
69
|
+
...(!reactionsMode && { height, width })
|
|
70
|
+
}}
|
|
61
71
|
>
|
|
62
72
|
{children}
|
|
63
73
|
</aside>
|
|
@@ -75,6 +85,7 @@ const DarkTheme = {
|
|
|
75
85
|
'--epr-category-label-bg-color': 'var(--epr-dark-category-label-bg-color)',
|
|
76
86
|
'--epr-picker-border-color': 'var(--epr-dark-picker-border-color)',
|
|
77
87
|
'--epr-bg-color': 'var(--epr-dark-bg-color)',
|
|
88
|
+
'--epr-reactions-bg-color': 'var(--epr-dark-reactions-bg-color)',
|
|
78
89
|
'--epr-search-input-bg-color-active':
|
|
79
90
|
'var(--epr-dark-search-input-bg-color-active)',
|
|
80
91
|
'--epr-emoji-variation-indicator-color':
|
|
@@ -97,6 +108,7 @@ const styles = stylesheet.create({
|
|
|
97
108
|
borderColor: 'var(--epr-picker-border-color)',
|
|
98
109
|
backgroundColor: 'var(--epr-bg-color)',
|
|
99
110
|
overflow: 'hidden',
|
|
111
|
+
transition: 'all 0.3s ease-in-out, background-color 0.1s ease-in-out',
|
|
100
112
|
// @ts-expect-error - need to work on this
|
|
101
113
|
'*': {
|
|
102
114
|
boxSizing: 'border-box',
|
|
@@ -112,6 +124,7 @@ const styles = stylesheet.create({
|
|
|
112
124
|
'--epr-search-input-bg-color': '#f6f6f6',
|
|
113
125
|
'--epr-picker-border-color': '#e7e7e7',
|
|
114
126
|
'--epr-bg-color': '#fff',
|
|
127
|
+
'--epr-reactions-bg-color': '#ffffff90',
|
|
115
128
|
'--epr-category-icon-active-color': '#6aa8de',
|
|
116
129
|
'--epr-skin-tone-picker-menu-color': '#ffffff95',
|
|
117
130
|
|
|
@@ -187,6 +200,7 @@ const styles = stylesheet.create({
|
|
|
187
200
|
'--epr-dark-category-label-bg-color': '#222222e6',
|
|
188
201
|
'--epr-dark-picker-border-color': '#151617',
|
|
189
202
|
'--epr-dark-bg-color': '#222222',
|
|
203
|
+
'--epr-dark-reactions-bg-color': '#22222290',
|
|
190
204
|
'--epr-dark-search-input-bg-color-active': 'var(--epr-dark)',
|
|
191
205
|
'--epr-dark-emoji-variation-indicator-color': '#444',
|
|
192
206
|
'--epr-dark-category-icon-active-color': '#3271b7',
|
|
@@ -202,5 +216,16 @@ const styles = stylesheet.create({
|
|
|
202
216
|
darkTheme: {
|
|
203
217
|
'.': ClassNames.darkTheme,
|
|
204
218
|
'--': DarkTheme
|
|
219
|
+
},
|
|
220
|
+
reactionsMenu: {
|
|
221
|
+
'.': 'epr-reactions',
|
|
222
|
+
height: '50px',
|
|
223
|
+
display: 'inline-flex',
|
|
224
|
+
backgroundColor: 'var(--epr-reactions-bg-color)',
|
|
225
|
+
// @ts-expect-error - need to work on this
|
|
226
|
+
backdropFilter: 'blur(8px)',
|
|
227
|
+
'--': {
|
|
228
|
+
'--epr-picker-border-radius': '50px'
|
|
229
|
+
}
|
|
205
230
|
}
|
|
206
231
|
});
|
package/src/config/config.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import { DEFAULT_REACTIONS } from '../components/Reactions/DEFAULT_REACTIONS';
|
|
3
4
|
import { GetEmojiUrl } from '../components/emoji/BaseEmojiProps';
|
|
4
5
|
import {
|
|
5
6
|
setCustomEmojis,
|
|
@@ -85,7 +86,9 @@ export function basePickerConfig(): PickerConfigInternal {
|
|
|
85
86
|
suggestedEmojisMode: SuggestionMode.FREQUENT,
|
|
86
87
|
theme: Theme.LIGHT,
|
|
87
88
|
unicodeToHide: new Set<string>(KNOWN_FAILING_EMOJIS),
|
|
88
|
-
width: 350
|
|
89
|
+
width: 350,
|
|
90
|
+
reactionsDefaultOpen: false,
|
|
91
|
+
reactions: DEFAULT_REACTIONS
|
|
89
92
|
};
|
|
90
93
|
}
|
|
91
94
|
|
|
@@ -111,6 +114,8 @@ export type PickerConfigInternal = {
|
|
|
111
114
|
skinTonePickerLocation: SkinTonePickerLocation;
|
|
112
115
|
unicodeToHide: Set<string>;
|
|
113
116
|
customEmojis: CustomEmoji[];
|
|
117
|
+
reactionsDefaultOpen: boolean;
|
|
118
|
+
reactions: string[];
|
|
114
119
|
};
|
|
115
120
|
|
|
116
121
|
export type PreviewConfig = {
|
package/src/config/useConfig.ts
CHANGED
|
@@ -100,6 +100,11 @@ export function useStyleConfig(): React.CSSProperties {
|
|
|
100
100
|
return { height: getDimension(height), width: getDimension(width), ...style };
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
export function useReactionsOpenConfig(): boolean {
|
|
104
|
+
const { reactionsDefaultOpen } = usePickerConfig();
|
|
105
|
+
return reactionsDefaultOpen;
|
|
106
|
+
}
|
|
107
|
+
|
|
103
108
|
export function useEmojiVersionConfig(): string | null {
|
|
104
109
|
const { emojiVersion } = usePickerConfig();
|
|
105
110
|
return emojiVersion;
|
|
@@ -120,6 +125,11 @@ export function useUnicodeToHide() {
|
|
|
120
125
|
return unicodeToHide;
|
|
121
126
|
}
|
|
122
127
|
|
|
128
|
+
export function useReactionsConfig(): string[] {
|
|
129
|
+
const { reactions } = usePickerConfig();
|
|
130
|
+
return reactions;
|
|
131
|
+
}
|
|
132
|
+
|
|
123
133
|
export function useGetEmojiUrlConfig(): (
|
|
124
134
|
unified: string,
|
|
125
135
|
style: EmojiStyle
|
|
@@ -139,9 +149,12 @@ export function useSearchResultsConfig(searchResultsCount: number): string {
|
|
|
139
149
|
const isPlural = searchResultsCount > 1;
|
|
140
150
|
|
|
141
151
|
if (hasResults) {
|
|
142
|
-
return isPlural
|
|
143
|
-
SEARCH_RESULTS_MULTIPLE_RESULTS_FOUND.replace(
|
|
144
|
-
|
|
152
|
+
return isPlural
|
|
153
|
+
? SEARCH_RESULTS_MULTIPLE_RESULTS_FOUND.replace(
|
|
154
|
+
'%n',
|
|
155
|
+
searchResultsCount.toString()
|
|
156
|
+
)
|
|
157
|
+
: SEARCH_RESULTS_ONE_RESULT_FOUND;
|
|
145
158
|
}
|
|
146
159
|
|
|
147
160
|
return SEARCH_RESULTS_NO_RESULTS_FOUND;
|