redo loading emojis from their keys

This commit is contained in:
ChaosExAnima 2025-11-25 14:28:11 +01:00
parent 3779b9f898
commit e9e15d5a6a
No known key found for this signature in database
GPG Key ID: 8F2B333100FB6117

View File

@ -1,4 +1,4 @@
import { useCallback, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import type { FC, MouseEventHandler } from 'react'; import type { FC, MouseEventHandler } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
@ -11,7 +11,6 @@ import { useEmojiAppState } from '@/mastodon/features/emoji/mode';
import { emojiToUnicodeHex } from '@/mastodon/features/emoji/normalize'; import { emojiToUnicodeHex } from '@/mastodon/features/emoji/normalize';
import type { AnyEmojiData } from '@/mastodon/features/emoji/types'; import type { AnyEmojiData } from '@/mastodon/features/emoji/types';
import { isCustomEmoji } from '@/mastodon/features/emoji/utils'; import { isCustomEmoji } from '@/mastodon/features/emoji/utils';
import { usePrevious } from '@/mastodon/hooks/usePrevious';
import ArrowIcon from '@/material-icons/400-24px/arrow_drop_down.svg?react'; import ArrowIcon from '@/material-icons/400-24px/arrow_drop_down.svg?react';
import { Emoji } from '..'; import { Emoji } from '..';
@ -56,55 +55,78 @@ export const PickerGroupCustomList: FC<
return customEmojis.length > 0 ? customEmojis : null; return customEmojis.length > 0 ? customEmojis : null;
}); });
// Next, load all Unicode emojis. // Determine which missing keys are Unicode and which are custom.
const { currentLocale } = useEmojiAppState(); const [missingUnicodeKeys, missingCustomKeys] = useMemo(() => {
const prevKeyCount = usePrevious(emojiKeys.length) ?? null; const emojisToKeys = emojis?.map(emojiToKey) ?? [];
if (
prevKeyCount === null ||
(prevKeyCount !== emojiKeys.length &&
(emojis === null || emojis.length < emojiKeys.length))
) {
// Convert to Unicode hex codes.
const unicodeKeys = emojiKeys const unicodeKeys = emojiKeys
.filter((key) => !isCustomEmoji(key)) .filter((key) => !isCustomEmoji(key))
.map((code) => emojiToUnicodeHex(code)); .map((code) => emojiToUnicodeHex(code))
if (unicodeKeys.length === 0) { .filter((code) => !emojisToKeys.includes(code));
return; const customKeys = emojiKeys.filter(
} (key) => isCustomEmoji(key) && !emojisToKeys.includes(key),
void searchEmojisByHexcodes(unicodeKeys, currentLocale).then( );
(unicodeEmojis) => { return [unicodeKeys, customKeys];
if (emojis?.length === emojiKeys.length) { }, [emojiKeys, emojis]);
return;
}
// Combine custom and Unicode emojis based on the original key order.
setEmojis((prevEmojis) => {
const combinedEmojis = prevEmojis ?? [];
return ( // Next, load all Unicode emojis.
emojiKeys const { currentLocale } = useEmojiAppState();
.map((key) => { const [loading, setLoading] = useState(false); // Use to avoid duplicate loads.
if (isCustomEmoji(key)) { if (missingUnicodeKeys.length > 0 && !loading) {
return combinedEmojis.find( setLoading(true);
(e) => 'shortcode' in e && e.shortcode === key.slice(1, -1),
); void searchEmojisByHexcodes(missingUnicodeKeys, currentLocale).then(
} (unicodeEmojis) => {
return ( setEmojis((prevEmojis) => {
unicodeEmojis.find( setLoading(false);
(e) => e.hexcode === emojiToUnicodeHex(key), return mergeNewEmojis(prevEmojis ?? [], unicodeEmojis, emojiKeys);
) ?? null
);
})
// Discard any unknown emojis.
.filter((e): e is AnyEmojiData => !!e)
);
}); });
}, },
); );
} }
// Finally, load all custom emojis that haven't been loaded yet.
if (missingCustomKeys.length > 0) {
setEmojis((prevEmojis) => {
const newCustomEmojis = mockCustomEmojis.filter((emoji) =>
missingCustomKeys.includes(`:${emoji.shortcode}:`),
);
return mergeNewEmojis(prevEmojis ?? [], newCustomEmojis, emojiKeys);
});
}
return <PickerGroupListInner emojis={emojis} {...props} />; return <PickerGroupListInner emojis={emojis} {...props} />;
}; };
function emojiToKey(emoji: AnyEmojiData): string {
return 'hexcode' in emoji ? emoji.hexcode : `:${emoji.shortcode}:`;
}
function mergeNewEmojis(
currentEmojis: AnyEmojiData[],
newEmojis: AnyEmojiData[],
emojiKeys: string[],
): AnyEmojiData[] {
const allEmojis = new Map([
...currentEmojis.map(
(emoji) => [emojiToKey(emoji), emoji] satisfies [string, AnyEmojiData],
),
...newEmojis.map(
(emoji) => [emojiToKey(emoji), emoji] satisfies [string, AnyEmojiData],
),
]);
return (
emojiKeys
.map((key) =>
isCustomEmoji(key)
? allEmojis.get(key)
: allEmojis.get(emojiToUnicodeHex(key)),
)
// Discard any missing emojis.
.filter((e) => !!e)
);
}
const PickerGroupListInner: FC< const PickerGroupListInner: FC<
PickerGroupListProps & { emojis: AnyEmojiData[] | null } PickerGroupListProps & { emojis: AnyEmojiData[] | null }
> = ({ group, name, onSelect, emojis }) => { > = ({ group, name, onSelect, emojis }) => {