Skip to content

Commit 1c93fbc

Browse files
committed
🐛(frontend) fix multiple EmojiPicker
emoji-mart is used to display emojis in the editor. It is used by the callout block and by Blocknotes editor. The problem is that the emoji-mart is a singleton, so if Blocknotes components init the emoji-mart first, the picker in the callout block will not display correctly. This commit fixes the issue by initializing the emoji-mart in the callout block first.
1 parent d811e3c commit 1c93fbc

File tree

4 files changed

+85
-58
lines changed

4 files changed

+85
-58
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ and this project adheres to
1818

1919
### Fixed
2020

21-
🐛(frontend) table of content disappearing #982
21+
-🐛(frontend) table of content disappearing #982
22+
-🐛(frontend) fix multiple EmojiPicker #1012
2223

2324

2425
## [3.3.0] - 2025-05-06

src/frontend/apps/impress/src/features/docs/doc-editor/components/EmojiPicker.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
1-
import data from '@emoji-mart/data';
1+
import { EmojiMartData } from '@emoji-mart/data';
22
import Picker from '@emoji-mart/react';
33
import React from 'react';
44
import { useTranslation } from 'react-i18next';
55

66
import { Box } from '@/components';
77

88
interface EmojiPickerProps {
9+
emojiData: EmojiMartData;
910
categories: string[];
10-
custom: {
11-
name: string;
12-
id: string;
13-
emojis: string[];
14-
}[];
1511
onClickOutside: () => void;
1612
onEmojiSelect: ({ native }: { native: string }) => void;
1713
}
1814

1915
export const EmojiPicker = ({
16+
emojiData,
2017
categories,
21-
custom,
2218
onClickOutside,
2319
onEmojiSelect,
2420
}: EmojiPickerProps) => {
@@ -27,9 +23,8 @@ export const EmojiPicker = ({
2723
return (
2824
<Box $position="absolute" $zIndex={1000} $margin="2rem 0 0 0">
2925
<Picker
26+
data={emojiData}
3027
categories={categories}
31-
custom={custom}
32-
data={data}
3328
locale={i18n.resolvedLanguage}
3429
navPosition="none"
3530
onClickOutside={onClickOutside}

src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/CalloutBlock.tsx

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,52 +10,7 @@ import { Box, BoxButton, Icon } from '@/components';
1010
import { DocsBlockNoteEditor } from '../../types';
1111
import { EmojiPicker } from '../EmojiPicker';
1212

13-
const calloutCustom = [
14-
{
15-
name: 'Callout',
16-
id: 'callout',
17-
emojis: [
18-
'bulb',
19-
'point_right',
20-
'point_up',
21-
'ok_hand',
22-
'key',
23-
'construction',
24-
'warning',
25-
'fire',
26-
'pushpin',
27-
'scissors',
28-
'question',
29-
'no_entry',
30-
'no_entry_sign',
31-
'alarm_clock',
32-
'phone',
33-
'rotating_light',
34-
'recycle',
35-
'white_check_mark',
36-
'lock',
37-
'paperclip',
38-
'book',
39-
'speaking_head_in_silhouette',
40-
'arrow_right',
41-
'loudspeaker',
42-
'hammer_and_wrench',
43-
'gear',
44-
],
45-
},
46-
];
47-
48-
const calloutCategories = [
49-
'callout',
50-
'people',
51-
'nature',
52-
'foods',
53-
'activity',
54-
'places',
55-
'flags',
56-
'objects',
57-
'symbols',
58-
];
13+
import InitEmojiCallout from './initEmojiCallout';
5914

6015
export const CalloutBlock = createReactBlockSpec(
6116
{
@@ -124,8 +79,8 @@ export const CalloutBlock = createReactBlockSpec(
12479

12580
{openEmojiPicker && (
12681
<EmojiPicker
127-
categories={calloutCategories}
128-
custom={calloutCustom}
82+
emojiData={InitEmojiCallout.emojidata}
83+
categories={InitEmojiCallout.calloutCategories}
12984
onClickOutside={onClickOutside}
13085
onEmojiSelect={onEmojiSelect}
13186
/>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* "emoji-mart" is a singleton, multiple imports in the same
3+
* application could cause issues.
4+
* BlockNote uses "emoji-mart" internally as well, if
5+
* Blocknote emoji picker is init before the callout emoji picker,
6+
* the callout emoji picker will not be set up correctly.
7+
* To avoid this, we initialize emoji-mart here and before any
8+
* other components that uses it.
9+
*/
10+
import data, { Category, EmojiMartData } from '@emoji-mart/data';
11+
import { init } from 'emoji-mart';
12+
13+
type EmojiMartDataFixed = Omit<EmojiMartData, 'categories'> & {
14+
categories: (Category & { name: string })[];
15+
};
16+
17+
const emojidata = structuredClone(data) as EmojiMartDataFixed;
18+
19+
const CALLOUT_ID = 'callout';
20+
const CALLOUT_EMOJIS = [
21+
'bulb',
22+
'point_right',
23+
'point_up',
24+
'ok_hand',
25+
'key',
26+
'construction',
27+
'warning',
28+
'fire',
29+
'pushpin',
30+
'scissors',
31+
'question',
32+
'no_entry',
33+
'no_entry_sign',
34+
'alarm_clock',
35+
'phone',
36+
'rotating_light',
37+
'recycle',
38+
'white_check_mark',
39+
'lock',
40+
'paperclip',
41+
'book',
42+
'speaking_head_in_silhouette',
43+
'arrow_right',
44+
'loudspeaker',
45+
'hammer_and_wrench',
46+
'gear',
47+
];
48+
49+
if (!emojidata.categories.some((c) => c.id === CALLOUT_ID)) {
50+
emojidata.categories.unshift({
51+
id: CALLOUT_ID,
52+
name: 'Callout',
53+
emojis: CALLOUT_EMOJIS,
54+
});
55+
}
56+
57+
void init({ data: emojidata });
58+
59+
const calloutCategories = [
60+
'callout',
61+
'people',
62+
'nature',
63+
'foods',
64+
'activity',
65+
'places',
66+
'flags',
67+
'objects',
68+
'symbols',
69+
];
70+
71+
const calloutEmojiData = {
72+
emojidata,
73+
calloutCategories,
74+
};
75+
76+
export default calloutEmojiData;

0 commit comments

Comments
 (0)