Skip to content

Commit f7bd1e4

Browse files
committed
Better react to props change
1 parent 952c250 commit f7bd1e4

10 files changed

+97
-56
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66

77
![image](https://github.com/ealush/emoji-picker-react/assets/11255103/48901306-e7fd-49cd-8f1e-9b214083a61d)
88

9-
![reactions](https://github.com/ealush/emoji-picker-react/assets/11255103/c28cc954-dc1d-4d82-91a8-64a74cf1d598)
10-
---
9+
## ![reactions](https://github.com/ealush/emoji-picker-react/assets/11255103/c28cc954-dc1d-4d82-91a8-64a74cf1d598)
1110

1211
_If you enjoy using emoji-picker-react<br/>
1312
You should also consider trying:<br/>
@@ -65,6 +64,7 @@ The following props are accepted by them picker:
6564

6665
| Prop | Type | Default | Description |
6766
| ---------------------- | ------------------------------------------------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
67+
| open | boolean | `true` | Controls whether the picker is open or not. |
6868
| onEmojiClick | function | | Callback function that is called when an emoji is clicked. The function receives the emoji object as a parameter. |
6969
| autoFocusSearch | boolean | `true` | Controls the auto focus of the search input. |
7070
| Theme | string | `light` | Controls the theme of the picker. Possible values are `light`, `dark` and `auto`. |

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "4.7.11",
2+
"version": "4.7.12",
33
"license": "MIT",
44
"main": "dist/index.js",
55
"typings": "dist/index.d.ts",

src/EmojiPickerReact.tsx

+10-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
22

3+
import { PickerStyleTag } from './Stylesheet/stylesheet';
34
import { Reactions } from './components/Reactions/Reactions';
45
import { Body } from './components/body/Body';
56
import { ElementRefContextProvider } from './components/context/ElementRefContext';
@@ -8,12 +9,15 @@ import { useReactionsModeState } from './components/context/PickerContext';
89
import { Preview } from './components/footer/Preview';
910
import { Header } from './components/header/Header';
1011
import PickerMain from './components/main/PickerMain';
12+
import { compareConfig } from './config/compareConfig';
13+
import { useOpenConfig } from './config/useConfig';
1114

1215
import { PickerProps } from './index';
1316

1417
function EmojiPicker(props: PickerProps) {
1518
return (
1619
<ElementRefContextProvider>
20+
<PickerStyleTag />
1721
<PickerConfigProvider {...props}>
1822
<ContentControl />
1923
</PickerConfigProvider>
@@ -24,13 +28,18 @@ function EmojiPicker(props: PickerProps) {
2428
function ContentControl() {
2529
const [reactionsDefaultOpen] = useReactionsModeState();
2630
const [renderAll, setRenderAll] = React.useState(!reactionsDefaultOpen);
31+
const isOpen = useOpenConfig();
2732

2833
React.useEffect(() => {
2934
if (!renderAll) {
3035
setRenderAll(true);
3136
}
3237
}, [renderAll]);
3338

39+
if (!isOpen) {
40+
return null;
41+
}
42+
3443
return (
3544
<PickerMain>
3645
<Reactions />
@@ -46,27 +55,4 @@ function ContentControl() {
4655
}
4756

4857
// eslint-disable-next-line complexity
49-
export default React.memo(EmojiPicker, (prev, next) => {
50-
const prevCustomEmojis = prev.customEmojis ?? [];
51-
const nextCustomEmojis = next.customEmojis ?? [];
52-
return (
53-
prev.emojiVersion === next.emojiVersion &&
54-
prev.reactionsDefaultOpen === next.reactionsDefaultOpen &&
55-
prev.searchPlaceHolder === next.searchPlaceHolder &&
56-
prev.searchPlaceholder === next.searchPlaceholder &&
57-
prev.defaultSkinTone === next.defaultSkinTone &&
58-
prev.skinTonesDisabled === next.skinTonesDisabled &&
59-
prev.autoFocusSearch === next.autoFocusSearch &&
60-
prev.emojiStyle === next.emojiStyle &&
61-
prev.theme === next.theme &&
62-
prev.suggestedEmojisMode === next.suggestedEmojisMode &&
63-
prev.lazyLoadEmojis === next.lazyLoadEmojis &&
64-
prev.className === next.className &&
65-
prev.height === next.height &&
66-
prev.width === next.width &&
67-
prev.style === next.style &&
68-
prev.searchDisabled === next.searchDisabled &&
69-
prev.skinTonePickerLocation === next.skinTonePickerLocation &&
70-
prevCustomEmojis.length === nextCustomEmojis.length
71-
);
72-
});
58+
export default React.memo(EmojiPicker, compareConfig);

src/components/context/PickerConfigContext.tsx

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
22

3+
import { compareConfig } from '../../config/compareConfig';
34
import {
45
basePickerConfig,
56
mergeConfig,
@@ -32,12 +33,32 @@ export function useSetConfig(config: PickerConfig) {
3233
);
3334

3435
React.useEffect(() => {
35-
if (config.customEmojis?.length !== mergedConfig.customEmojis?.length) {
36-
setMergedConfig(mergeConfig(config));
36+
if (compareConfig(mergedConfig, config)) {
37+
return;
3738
}
39+
setMergedConfig(mergeConfig(config));
3840
// not gonna...
3941
// eslint-disable-next-line react-hooks/exhaustive-deps
40-
}, [config.customEmojis?.length]);
42+
}, [
43+
config.customEmojis?.length,
44+
config.open,
45+
config.emojiVersion,
46+
config.reactionsDefaultOpen,
47+
config.searchPlaceHolder,
48+
config.searchPlaceholder,
49+
config.defaultSkinTone,
50+
config.skinTonesDisabled,
51+
config.autoFocusSearch,
52+
config.emojiStyle,
53+
config.theme,
54+
config.suggestedEmojisMode,
55+
config.lazyLoadEmojis,
56+
config.className,
57+
config.height,
58+
config.width,
59+
config.searchDisabled,
60+
config.skinTonePickerLocation
61+
]);
4162

4263
return mergedConfig;
4364
}

src/components/main/PickerMain.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { cx } from 'flairup';
22
import * as React from 'react';
33

44
import { ClassNames } from '../../DomUtils/classNames';
5-
import { PickerStyleTag, stylesheet } from '../../Stylesheet/stylesheet';
5+
import { stylesheet } from '../../Stylesheet/stylesheet';
66
import {
77
useClassNameConfig,
88
useStyleConfig,
@@ -25,7 +25,6 @@ type Props = Readonly<{
2525
export default function PickerMain({ children }: Props) {
2626
return (
2727
<PickerContextProvider>
28-
<PickerStyleTag />
2928
<PickerRootElement>{children}</PickerRootElement>
3029
</PickerContextProvider>
3130
);

src/config/compareConfig.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { PickerConfig } from './config';
2+
3+
// eslint-disable-next-line complexity
4+
export function compareConfig(prev: PickerConfig, next: PickerConfig) {
5+
const prevCustomEmojis = prev.customEmojis ?? [];
6+
const nextCustomEmojis = next.customEmojis ?? [];
7+
return (
8+
prev.open === next.open &&
9+
prev.emojiVersion === next.emojiVersion &&
10+
prev.reactionsDefaultOpen === next.reactionsDefaultOpen &&
11+
prev.searchPlaceHolder === next.searchPlaceHolder &&
12+
prev.searchPlaceholder === next.searchPlaceholder &&
13+
prev.defaultSkinTone === next.defaultSkinTone &&
14+
prev.skinTonesDisabled === next.skinTonesDisabled &&
15+
prev.autoFocusSearch === next.autoFocusSearch &&
16+
prev.emojiStyle === next.emojiStyle &&
17+
prev.theme === next.theme &&
18+
prev.suggestedEmojisMode === next.suggestedEmojisMode &&
19+
prev.lazyLoadEmojis === next.lazyLoadEmojis &&
20+
prev.className === next.className &&
21+
prev.height === next.height &&
22+
prev.width === next.width &&
23+
prev.style === next.style &&
24+
prev.searchDisabled === next.searchDisabled &&
25+
prev.skinTonePickerLocation === next.skinTonePickerLocation &&
26+
prevCustomEmojis.length === nextCustomEmojis.length
27+
);
28+
}

src/config/config.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ export function basePickerConfig(): PickerConfigInternal {
8888
unicodeToHide: new Set<string>(KNOWN_FAILING_EMOJIS),
8989
width: 350,
9090
reactionsDefaultOpen: false,
91-
reactions: DEFAULT_REACTIONS
91+
reactions: DEFAULT_REACTIONS,
92+
open: true
9293
};
9394
}
9495

@@ -116,6 +117,7 @@ export type PickerConfigInternal = {
116117
customEmojis: CustomEmoji[];
117118
reactionsDefaultOpen: boolean;
118119
reactions: string[];
120+
open: boolean;
119121
};
120122

121123
export type PreviewConfig = {

src/config/mutableConfig.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ export function useDefineMutableConfig(
2626

2727
React.useEffect(() => {
2828
MutableConfigRef.current.onEmojiClick = config.onEmojiClick || emptyFunc;
29-
}, [config.onEmojiClick]);
29+
MutableConfigRef.current.onReactionClick =
30+
config.onReactionClick || config.onEmojiClick;
31+
}, [config.onEmojiClick, config.onReactionClick]);
3032

3133
return MutableConfigRef;
3234
}

src/config/useConfig.ts

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ export function useCustomEmojisConfig(): CustomEmoji[] {
6666
return customEmojis;
6767
}
6868

69+
export function useOpenConfig(): boolean {
70+
const { open } = usePickerConfig();
71+
return open;
72+
}
73+
6974
export function useOnEmojiClickConfig(
7075
mouseEventSource: MOUSE_EVENT_SOURCE
7176
): (emoji: EmojiClickData, event: MouseEvent) => void {

stories/picker.stories.tsx

+20-22
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ export const HideEmojisByUnicode = (args: Props) => (
266266
);
267267

268268
function TemplateDark(args) {
269-
const [shown, setShown] = useState(true);
269+
const [open, setOpen] = useState(true);
270270
const [hasBg, setHasBg] = useState(false);
271271
return (
272272
<div
@@ -282,7 +282,7 @@ function TemplateDark(args) {
282282
})
283283
}}
284284
>
285-
<button onClick={() => setShown(!shown)} style={{ margin: '20px' }}>
285+
<button onClick={() => setOpen(!open)} style={{ margin: '20px' }}>
286286
Toggle
287287
</button>
288288
<input
@@ -291,17 +291,16 @@ function TemplateDark(args) {
291291
onChange={() => setHasBg(!hasBg)}
292292
/>
293293
<br />
294-
{shown ? (
295-
<EmojiPicker
296-
{...args}
297-
onEmojiClick={(...args) => console.log(...args)}
298-
/>
299-
) : null}
294+
<EmojiPicker
295+
{...args}
296+
open={open}
297+
onEmojiClick={(...args) => console.log(...args)}
298+
/>
300299
</div>
301300
);
302301
}
303302
function Template(args) {
304-
const [shown, setShown] = useState(true);
303+
const [open, setOpen] = useState(true);
305304
const [inputValue, setInputValue] = useState('');
306305
const [hasBg, setHasBg] = useState(false);
307306

@@ -325,7 +324,7 @@ function Template(args) {
325324
value={inputValue}
326325
onChange={e => setInputValue(e.target.value)}
327326
/>
328-
<button onClick={() => setShown(!shown)} style={{ margin: '20px' }}>
327+
<button onClick={() => setOpen(!open)} style={{ margin: '20px' }}>
329328
Toggle
330329
</button>
331330
<input
@@ -334,18 +333,17 @@ function Template(args) {
334333
onChange={() => setHasBg(!hasBg)}
335334
/>
336335
<br />
337-
{shown ? (
338-
<EmojiPicker
339-
{...args}
340-
onEmojiClick={(emoji, event) => {
341-
setInputValue(
342-
// inputValue =>
343-
inputValue + (emoji.isCustom ? emoji.unified : emoji.emoji)
344-
);
345-
console.log(emoji, event);
346-
}}
347-
/>
348-
) : null}
336+
<EmojiPicker
337+
{...args}
338+
open={open}
339+
onEmojiClick={(emoji, event) => {
340+
setInputValue(
341+
// inputValue =>
342+
inputValue + (emoji.isCustom ? emoji.unified : emoji.emoji)
343+
);
344+
console.log(emoji, event);
345+
}}
346+
/>
349347
</div>
350348
</React.StrictMode>
351349
);

0 commit comments

Comments
 (0)