emoji-picker-react 4.6.14 → 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/components/header/Search/BtnClearSearch.d.ts +2 -0
- package/dist/components/header/Search/IcnSearch.d.ts +2 -0
- package/dist/components/header/SkinTonePicker/BtnSkinToneVariation.d.ts +11 -0
- package/dist/components/navigation/CategoryButton.d.ts +11 -0
- package/dist/config/config.d.ts +2 -0
- package/dist/config/useConfig.d.ts +2 -0
- package/dist/emoji-picker-react.cjs.development.js +1265 -963
- 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 +1266 -964
- 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/body/EmojiVariationPicker.tsx +6 -7
- package/src/components/context/ElementRefContext.tsx +10 -2
- package/src/components/context/PickerContext.tsx +16 -3
- package/src/components/emoji/ClickableEmojiButton.tsx +13 -3
- package/src/components/emoji/Emoji.tsx +4 -1
- package/src/components/footer/Preview.tsx +11 -8
- package/src/components/header/Header.tsx +6 -2
- package/src/components/header/Search/BtnClearSearch.tsx +91 -0
- package/src/components/header/{CssSearch.tsx → Search/CssSearch.tsx} +2 -2
- package/src/components/header/Search/IcnSearch.tsx +39 -0
- package/src/components/header/{Search.tsx → Search/Search.tsx} +14 -49
- package/src/components/header/SkinTonePicker/BtnSkinToneVariation.tsx +80 -0
- package/src/components/header/{SkinTonePicker.tsx → SkinTonePicker/SkinTonePicker.tsx} +25 -67
- package/src/components/main/PickerMain.tsx +27 -2
- package/src/components/navigation/CategoryButton.tsx +141 -0
- package/src/components/navigation/CategoryNavigation.tsx +10 -129
- package/src/config/config.ts +7 -2
- package/src/config/useConfig.ts +16 -3
- /package/dist/components/header/{CssSearch.d.ts → Search/CssSearch.d.ts} +0 -0
- /package/dist/components/header/{Search.d.ts → Search/Search.d.ts} +0 -0
- /package/dist/components/header/{SkinTonePicker.d.ts → SkinTonePicker/SkinTonePicker.d.ts} +0 -0
- /package/src/components/header/{svg → Search/svg}/magnifier.svg +0 -0
- /package/src/components/header/{svg → Search/svg}/times.svg +0 -0
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>
|
|
@@ -200,6 +200,12 @@ const styles = stylesheet.create({
|
|
|
200
200
|
transform: 'scale(0.9)',
|
|
201
201
|
transition: 'transform 0.1s ease-out, opacity 0.2s ease-out'
|
|
202
202
|
},
|
|
203
|
+
visible: {
|
|
204
|
+
opacity: '1',
|
|
205
|
+
visibility: 'visible',
|
|
206
|
+
pointerEvents: 'all',
|
|
207
|
+
transform: 'scale(1)'
|
|
208
|
+
},
|
|
203
209
|
pointingUp: {
|
|
204
210
|
'.': 'pointing-up',
|
|
205
211
|
transformOrigin: 'center 0%',
|
|
@@ -211,12 +217,6 @@ const styles = stylesheet.create({
|
|
|
211
217
|
transform: 'rotate(180deg) translateY(100%) translateX(18px)'
|
|
212
218
|
}
|
|
213
219
|
},
|
|
214
|
-
visible: {
|
|
215
|
-
opacity: '1',
|
|
216
|
-
visibility: 'visible',
|
|
217
|
-
pointerEvents: 'all',
|
|
218
|
-
transform: 'scale(1)'
|
|
219
|
-
},
|
|
220
220
|
pointer: {
|
|
221
221
|
'.': 'epr-emoji-pointer',
|
|
222
222
|
content: '',
|
|
@@ -237,7 +237,6 @@ const styles = stylesheet.create({
|
|
|
237
237
|
},
|
|
238
238
|
'.epr-auto-theme': {
|
|
239
239
|
pointer: {
|
|
240
|
-
// @ts-ignore
|
|
241
240
|
'@media (prefers-color-scheme: dark)': {
|
|
242
241
|
backgroundPosition: '-25px 0'
|
|
243
242
|
}
|
|
@@ -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;
|
|
@@ -2,7 +2,11 @@ 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
|
+
commonStyles,
|
|
8
|
+
stylesheet
|
|
9
|
+
} from '../../Stylesheet/stylesheet';
|
|
6
10
|
import { Button } from '../atoms/Button';
|
|
7
11
|
|
|
8
12
|
type ClickableEmojiButtonProps = Readonly<{
|
|
@@ -13,6 +17,7 @@ type ClickableEmojiButtonProps = Readonly<{
|
|
|
13
17
|
children: React.ReactNode;
|
|
14
18
|
hasVariations: boolean;
|
|
15
19
|
unified?: string;
|
|
20
|
+
round?: boolean;
|
|
16
21
|
}>;
|
|
17
22
|
|
|
18
23
|
export function ClickableEmojiButton({
|
|
@@ -22,7 +27,8 @@ export function ClickableEmojiButton({
|
|
|
22
27
|
hiddenOnSearch,
|
|
23
28
|
showVariations = true,
|
|
24
29
|
hasVariations,
|
|
25
|
-
children
|
|
30
|
+
children,
|
|
31
|
+
round = false
|
|
26
32
|
}: ClickableEmojiButtonProps) {
|
|
27
33
|
return (
|
|
28
34
|
<Button
|
|
@@ -33,7 +39,8 @@ export function ClickableEmojiButton({
|
|
|
33
39
|
{
|
|
34
40
|
[ClassNames.visible]: !hidden && !hiddenOnSearch
|
|
35
41
|
},
|
|
36
|
-
!!(hasVariations && showVariations) && styles.hasVariations
|
|
42
|
+
!!(hasVariations && showVariations) && styles.hasVariations,
|
|
43
|
+
round && styles.round
|
|
37
44
|
)}
|
|
38
45
|
data-unified={unified}
|
|
39
46
|
aria-label={emojiNames[0]}
|
|
@@ -66,6 +73,9 @@ const styles = stylesheet.create({
|
|
|
66
73
|
backgroundColor: 'var(--epr-focus-bg-color)'
|
|
67
74
|
}
|
|
68
75
|
},
|
|
76
|
+
round: {
|
|
77
|
+
borderRadius: '50%'
|
|
78
|
+
},
|
|
69
79
|
hasVariations: {
|
|
70
80
|
'.': ClassNames.emojiHasVariations,
|
|
71
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,
|
|
@@ -19,7 +22,7 @@ import Flex from '../Layout/Flex';
|
|
|
19
22
|
import Space from '../Layout/Space';
|
|
20
23
|
import { useEmojiVariationPickerState } from '../context/PickerContext';
|
|
21
24
|
import { ViewOnlyEmoji } from '../emoji/ViewOnlyEmoji';
|
|
22
|
-
import { SkinTonePickerMenu } from '../header/SkinTonePicker';
|
|
25
|
+
import { SkinTonePickerMenu } from '../header/SkinTonePicker/SkinTonePicker';
|
|
23
26
|
|
|
24
27
|
export function Preview() {
|
|
25
28
|
const previewConfig = usePreviewConfig();
|
|
@@ -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}
|
|
@@ -88,11 +93,9 @@ export function PreviewBody() {
|
|
|
88
93
|
/>
|
|
89
94
|
) : null}
|
|
90
95
|
</div>
|
|
91
|
-
{
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<div className={cx(styles.label)}>{defaultText}</div>
|
|
95
|
-
)}
|
|
96
|
+
<div className={cx(styles.label)}>
|
|
97
|
+
{show ? emojiName(emoji) : defaultText}
|
|
98
|
+
</div>
|
|
96
99
|
</>
|
|
97
100
|
);
|
|
98
101
|
}
|
|
@@ -1,13 +1,17 @@
|
|
|
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
|
|
|
6
|
-
import { SearchContainer } from './Search';
|
|
8
|
+
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>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { cx } from 'flairup';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
commonInteractionStyles,
|
|
6
|
+
stylesheet
|
|
7
|
+
} from '../../../Stylesheet/stylesheet';
|
|
8
|
+
import { useClearSearch } from '../../../hooks/useFilter';
|
|
9
|
+
import { Button } from '../../atoms/Button';
|
|
10
|
+
|
|
11
|
+
import SVGTimes from './svg/times.svg';
|
|
12
|
+
|
|
13
|
+
export function BtnClearSearch() {
|
|
14
|
+
const clearSearch = useClearSearch();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Button
|
|
18
|
+
className={cx(
|
|
19
|
+
styles.btnClearSearch,
|
|
20
|
+
commonInteractionStyles.visibleOnSearchOnly
|
|
21
|
+
)}
|
|
22
|
+
onClick={clearSearch}
|
|
23
|
+
aria-label="Clear"
|
|
24
|
+
title="Clear"
|
|
25
|
+
>
|
|
26
|
+
<div className={cx(styles.icnClearnSearch)} />
|
|
27
|
+
</Button>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const HoverDark = {
|
|
32
|
+
':hover': {
|
|
33
|
+
'> .epr-icn-clear-search': {
|
|
34
|
+
backgroundPositionY: '-60px'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const styles = stylesheet.create({
|
|
40
|
+
btnClearSearch: {
|
|
41
|
+
'.': 'epr-btn-clear-search',
|
|
42
|
+
position: 'absolute',
|
|
43
|
+
right: 'var(--epr-search-bar-inner-padding)',
|
|
44
|
+
height: '30px',
|
|
45
|
+
width: '30px',
|
|
46
|
+
display: 'flex',
|
|
47
|
+
alignItems: 'center',
|
|
48
|
+
justifyContent: 'center',
|
|
49
|
+
top: '50%',
|
|
50
|
+
transform: 'translateY(-50%)',
|
|
51
|
+
padding: '0',
|
|
52
|
+
borderRadius: '50%',
|
|
53
|
+
':hover': {
|
|
54
|
+
background: 'var(--epr-hover-bg-color)'
|
|
55
|
+
},
|
|
56
|
+
':focus': {
|
|
57
|
+
background: 'var(--epr-hover-bg-color)'
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
icnClearnSearch: {
|
|
61
|
+
'.': 'epr-icn-clear-search',
|
|
62
|
+
backgroundColor: 'transparent',
|
|
63
|
+
backgroundRepeat: 'no-repeat',
|
|
64
|
+
backgroundSize: '20px',
|
|
65
|
+
height: '20px',
|
|
66
|
+
width: '20px',
|
|
67
|
+
backgroundImage: `url(${SVGTimes})`,
|
|
68
|
+
':hover': {
|
|
69
|
+
backgroundPositionY: '-20px'
|
|
70
|
+
},
|
|
71
|
+
':focus': {
|
|
72
|
+
backgroundPositionY: '-20px'
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
'.epr-dark-theme': {
|
|
76
|
+
icnClearnSearch: {
|
|
77
|
+
backgroundPositionY: '-40px'
|
|
78
|
+
},
|
|
79
|
+
btnClearSearch: HoverDark
|
|
80
|
+
},
|
|
81
|
+
'.epr-auto-theme': {
|
|
82
|
+
icnClearnSearch: {
|
|
83
|
+
'@media (prefers-color-scheme: dark)': {
|
|
84
|
+
backgroundPositionY: '-40px'
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
btnClearSearch: {
|
|
88
|
+
'@media (prefers-color-scheme: dark)': HoverDark
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|