🐛(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:
@@ -18,7 +18,8 @@ and this project adheres to
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
🐛(frontend) table of content disappearing #982
|
-🐛(frontend) table of content disappearing #982
|
||||||
|
-🐛(frontend) fix multiple EmojiPicker #1012
|
||||||
|
|
||||||
|
|
||||||
## [3.3.0] - 2025-05-06
|
## [3.3.0] - 2025-05-06
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import data from '@emoji-mart/data';
|
import { EmojiMartData } from '@emoji-mart/data';
|
||||||
import Picker from '@emoji-mart/react';
|
import Picker from '@emoji-mart/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -6,19 +6,15 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { Box } from '@/components';
|
import { Box } from '@/components';
|
||||||
|
|
||||||
interface EmojiPickerProps {
|
interface EmojiPickerProps {
|
||||||
|
emojiData: EmojiMartData;
|
||||||
categories: string[];
|
categories: string[];
|
||||||
custom: {
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
emojis: string[];
|
|
||||||
}[];
|
|
||||||
onClickOutside: () => void;
|
onClickOutside: () => void;
|
||||||
onEmojiSelect: ({ native }: { native: string }) => void;
|
onEmojiSelect: ({ native }: { native: string }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EmojiPicker = ({
|
export const EmojiPicker = ({
|
||||||
|
emojiData,
|
||||||
categories,
|
categories,
|
||||||
custom,
|
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
onEmojiSelect,
|
onEmojiSelect,
|
||||||
}: EmojiPickerProps) => {
|
}: EmojiPickerProps) => {
|
||||||
@@ -27,9 +23,8 @@ export const EmojiPicker = ({
|
|||||||
return (
|
return (
|
||||||
<Box $position="absolute" $zIndex={1000} $margin="2rem 0 0 0">
|
<Box $position="absolute" $zIndex={1000} $margin="2rem 0 0 0">
|
||||||
<Picker
|
<Picker
|
||||||
|
data={emojiData}
|
||||||
categories={categories}
|
categories={categories}
|
||||||
custom={custom}
|
|
||||||
data={data}
|
|
||||||
locale={i18n.resolvedLanguage}
|
locale={i18n.resolvedLanguage}
|
||||||
navPosition="none"
|
navPosition="none"
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
|
|||||||
@@ -10,52 +10,7 @@ import { Box, BoxButton, Icon } from '@/components';
|
|||||||
import { DocsBlockNoteEditor } from '../../types';
|
import { DocsBlockNoteEditor } from '../../types';
|
||||||
import { EmojiPicker } from '../EmojiPicker';
|
import { EmojiPicker } from '../EmojiPicker';
|
||||||
|
|
||||||
const calloutCustom = [
|
import InitEmojiCallout from './initEmojiCallout';
|
||||||
{
|
|
||||||
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',
|
|
||||||
];
|
|
||||||
|
|
||||||
export const CalloutBlock = createReactBlockSpec(
|
export const CalloutBlock = createReactBlockSpec(
|
||||||
{
|
{
|
||||||
@@ -124,8 +79,8 @@ export const CalloutBlock = createReactBlockSpec(
|
|||||||
|
|
||||||
{openEmojiPicker && (
|
{openEmojiPicker && (
|
||||||
<EmojiPicker
|
<EmojiPicker
|
||||||
categories={calloutCategories}
|
emojiData={InitEmojiCallout.emojidata}
|
||||||
custom={calloutCustom}
|
categories={InitEmojiCallout.calloutCategories}
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
onEmojiSelect={onEmojiSelect}
|
onEmojiSelect={onEmojiSelect}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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;
|
||||||
Reference in New Issue
Block a user