Autosuggest emojis rendering fix (#39077)

This commit is contained in:
Echo
2026-05-19 14:22:52 +02:00
committed by GitHub
parent 34c91555ae
commit d5a7b383fa
6 changed files with 43 additions and 28 deletions

View File

@@ -1,7 +1,5 @@
import type { FC } from 'react';
import { useCustomEmojis } from '@/mastodon/hooks/useCustomEmojis';
import { Emoji } from './emoji';
interface LegacyEmoji {
@@ -12,11 +10,10 @@ interface LegacyEmoji {
}
export const AutosuggestEmoji: FC<{ emoji: LegacyEmoji }> = ({ emoji }) => {
const emojis = useCustomEmojis();
const colons = `:${emoji.id}:`;
return (
<div className='autosuggest-emoji'>
<Emoji code={emoji.native ?? colons} customEmoji={emojis} />
<Emoji code={emoji.native ?? colons} />
<div className='autosuggest-emoji__name'>{colons}</div>
</div>
);

View File

@@ -11,6 +11,7 @@ import AutosuggestAccountContainer from '../features/compose/containers/autosugg
import { AutosuggestEmoji } from './autosuggest_emoji';
import { AutosuggestHashtag } from './autosuggest_hashtag';
import { LocalCustomEmojiProvider } from './emoji/context';
const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => {
let word;
@@ -219,15 +220,17 @@ export default class AutosuggestInput extends ImmutablePureComponent {
spellCheck={spellCheck}
/>
<Overlay show={!(suggestionsHidden || suggestions.isEmpty())} offset={[0, 0]} placement='bottom' target={this.input} popperConfig={{ strategy: 'fixed' }}>
{({ props }) => (
<div {...props}>
<div className='autosuggest-textarea__suggestions' style={{ width: this.input?.clientWidth }}>
{suggestions.map(this.renderSuggestion)}
<LocalCustomEmojiProvider>
<Overlay show={!(suggestionsHidden || suggestions.isEmpty())} offset={[0, 0]} placement='bottom' target={this.input} popperConfig={{ strategy: 'fixed' }}>
{({ props }) => (
<div {...props}>
<div className='autosuggest-textarea__suggestions' style={{ width: this.input?.clientWidth }}>
{suggestions.map(this.renderSuggestion)}
</div>
</div>
</div>
)}
</Overlay>
)}
</Overlay>
</LocalCustomEmojiProvider>
</div>
);
}

View File

@@ -12,6 +12,7 @@ import AutosuggestAccountContainer from '../features/compose/containers/autosugg
import { AutosuggestEmoji } from './autosuggest_emoji';
import { AutosuggestHashtag } from './autosuggest_hashtag';
import { LocalCustomEmojiProvider } from './emoji/context';
const textAtCursorMatchesToken = (str, caretPosition) => {
let word;
@@ -218,15 +219,17 @@ const AutosuggestTextarea = forwardRef(({
lang={lang}
/>
<Overlay show={!(suggestionsHidden || suggestions.isEmpty())} offset={[0, 0]} placement='bottom' target={textareaRef} popperConfig={{ strategy: 'fixed' }}>
{({ props }) => (
<div {...props}>
<div className='autosuggest-textarea__suggestions' style={{ width: textareaRef.current?.clientWidth }}>
{suggestions.map(renderSuggestion)}
<LocalCustomEmojiProvider>
<Overlay show={!(suggestionsHidden || suggestions.isEmpty())} offset={[0, 0]} placement='bottom' target={textareaRef} popperConfig={{ strategy: 'fixed' }}>
{({ props }) => (
<div {...props}>
<div className='autosuggest-textarea__suggestions' style={{ width: textareaRef.current?.clientWidth }}>
{suggestions.map(renderSuggestion)}
</div>
</div>
</div>
)}
</Overlay>
)}
</Overlay>
</LocalCustomEmojiProvider>
</div>
);
});

View File

@@ -1,4 +1,9 @@
import type { MouseEventHandler, PropsWithChildren } from 'react';
import type {
FC,
MouseEventHandler,
PropsWithChildren,
ReactNode,
} from 'react';
import {
createContext,
useCallback,
@@ -8,6 +13,7 @@ import {
} from 'react';
import { cleanExtraEmojis } from '@/mastodon/features/emoji/normalize';
import { useCustomEmojis } from '@/mastodon/hooks/useCustomEmojis';
import { autoPlayGif } from '@/mastodon/initial_state';
import { polymorphicForwardRef } from '@/types/polymorphic';
import type {
@@ -103,3 +109,10 @@ export const CustomEmojiProvider = ({
</CustomEmojiContext.Provider>
);
};
export const LocalCustomEmojiProvider: FC<{ children: ReactNode }> = ({
children,
}) => {
const emojis = useCustomEmojis();
return <CustomEmojiProvider emojis={emojis}>{children}</CustomEmojiProvider>;
};

View File

@@ -19,7 +19,6 @@ import {
stringToEmojiState,
tokenizeText,
} from '@/mastodon/features/emoji/render';
import type { ExtraCustomEmojiMap } from '@/mastodon/features/emoji/types';
import { AnimateEmojiContext, CustomEmojiContext } from './context';
@@ -27,19 +26,14 @@ interface EmojiProps {
code: string;
showFallback?: boolean;
showLoading?: boolean;
customEmoji?: ExtraCustomEmojiMap | null;
}
export const Emoji: FC<EmojiProps> = ({
code,
showFallback = true,
showLoading = true,
customEmoji: customEmojiOverride,
}) => {
let customEmoji = useContext(CustomEmojiContext);
if (customEmojiOverride) {
customEmoji = customEmojiOverride;
}
const customEmoji = useContext(CustomEmojiContext);
// First, set the emoji state based on the input code.
const [state, setState] = useState(() =>

View File

@@ -1,9 +1,12 @@
import { useEffect, useState } from 'react';
import type { ExtraCustomEmojiMap } from '../features/emoji/types';
import { emojiLogger } from '../features/emoji/utils';
let emojis: ExtraCustomEmojiMap | null = null;
const log = emojiLogger('useCustomEmojis');
export function useCustomEmojis() {
const [, setLoaded] = useState(emojis !== null);
useEffect(() => {
@@ -21,6 +24,7 @@ async function loadEmojisIntoCache() {
const { loadAllCustomEmoji } = await import('../features/emoji/database');
const emojisRaw = await loadAllCustomEmoji();
if (emojisRaw === null) {
log('Custom emojis not loaded yet');
return;
}
@@ -32,4 +36,5 @@ async function loadEmojisIntoCache() {
static_url: emoji.static_url,
};
}
log('Loaded %d custom emojis into cache', Object.keys(emojis).length);
}