🐛(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.
This commit is contained in:
Anthony LC
2025-05-26 13:12:58 +02:00
parent d811e3c2fc
commit 1c93fbc007
4 changed files with 85 additions and 58 deletions

View File

@@ -18,7 +18,8 @@ and this project adheres to
### Fixed
🐛(frontend) table of content disappearing #982
-🐛(frontend) table of content disappearing #982
-🐛(frontend) fix multiple EmojiPicker #1012
## [3.3.0] - 2025-05-06

View File

@@ -1,4 +1,4 @@
import data from '@emoji-mart/data';
import { EmojiMartData } from '@emoji-mart/data';
import Picker from '@emoji-mart/react';
import React from 'react';
import { useTranslation } from 'react-i18next';
@@ -6,19 +6,15 @@ import { useTranslation } from 'react-i18next';
import { Box } from '@/components';
interface EmojiPickerProps {
emojiData: EmojiMartData;
categories: string[];
custom: {
name: string;
id: string;
emojis: string[];
}[];
onClickOutside: () => void;
onEmojiSelect: ({ native }: { native: string }) => void;
}
export const EmojiPicker = ({
emojiData,
categories,
custom,
onClickOutside,
onEmojiSelect,
}: EmojiPickerProps) => {
@@ -27,9 +23,8 @@ export const EmojiPicker = ({
return (
<Box $position="absolute" $zIndex={1000} $margin="2rem 0 0 0">
<Picker
data={emojiData}
categories={categories}
custom={custom}
data={data}
locale={i18n.resolvedLanguage}
navPosition="none"
onClickOutside={onClickOutside}

View File

@@ -10,52 +10,7 @@ import { Box, BoxButton, Icon } from '@/components';
import { DocsBlockNoteEditor } from '../../types';
import { EmojiPicker } from '../EmojiPicker';
const calloutCustom = [
{
name: 'Callout',
id: 'callout',
emojis: [
'bulb',
'point_right',
'point_up',
'ok_hand',
'key',
'construction',
'warning',
'fire',
'pushpin',
'scissors',
'question',
'no_entry',
'no_entry_sign',
'alarm_clock',
'phone',
'rotating_light',
'recycle',
'white_check_mark',
'lock',
'paperclip',
'book',
'speaking_head_in_silhouette',
'arrow_right',
'loudspeaker',
'hammer_and_wrench',
'gear',
],
},
];
const calloutCategories = [
'callout',
'people',
'nature',
'foods',
'activity',
'places',
'flags',
'objects',
'symbols',
];
import InitEmojiCallout from './initEmojiCallout';
export const CalloutBlock = createReactBlockSpec(
{
@@ -124,8 +79,8 @@ export const CalloutBlock = createReactBlockSpec(
{openEmojiPicker && (
<EmojiPicker
categories={calloutCategories}
custom={calloutCustom}
emojiData={InitEmojiCallout.emojidata}
categories={InitEmojiCallout.calloutCategories}
onClickOutside={onClickOutside}
onEmojiSelect={onEmojiSelect}
/>

View File

@@ -0,0 +1,76 @@
/**
* "emoji-mart" is a singleton, multiple imports in the same
* application could cause issues.
* BlockNote uses "emoji-mart" internally as well, if
* Blocknote emoji picker is init before the callout emoji picker,
* the callout emoji picker will not be set up correctly.
* To avoid this, we initialize emoji-mart here and before any
* other components that uses it.
*/
import data, { Category, EmojiMartData } from '@emoji-mart/data';
import { init } from 'emoji-mart';
type EmojiMartDataFixed = Omit<EmojiMartData, 'categories'> & {
categories: (Category & { name: string })[];
};
const emojidata = structuredClone(data) as EmojiMartDataFixed;
const CALLOUT_ID = 'callout';
const CALLOUT_EMOJIS = [
'bulb',
'point_right',
'point_up',
'ok_hand',
'key',
'construction',
'warning',
'fire',
'pushpin',
'scissors',
'question',
'no_entry',
'no_entry_sign',
'alarm_clock',
'phone',
'rotating_light',
'recycle',
'white_check_mark',
'lock',
'paperclip',
'book',
'speaking_head_in_silhouette',
'arrow_right',
'loudspeaker',
'hammer_and_wrench',
'gear',
];
if (!emojidata.categories.some((c) => c.id === CALLOUT_ID)) {
emojidata.categories.unshift({
id: CALLOUT_ID,
name: 'Callout',
emojis: CALLOUT_EMOJIS,
});
}
void init({ data: emojidata });
const calloutCategories = [
'callout',
'people',
'nature',
'foods',
'activity',
'places',
'flags',
'objects',
'symbols',
];
const calloutEmojiData = {
emojidata,
calloutCategories,
};
export default calloutEmojiData;