mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-15 00:38:27 +00:00
76 lines
2.1 KiB
TypeScript
76 lines
2.1 KiB
TypeScript
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
|
|
|
import { useAppSelector } from '@/flavours/glitch/store';
|
|
import { isModernEmojiEnabled } from '@/flavours/glitch/utils/environment';
|
|
|
|
import { toSupportedLocale } from './locale';
|
|
import { determineEmojiMode } from './mode';
|
|
import { cleanExtraEmojis } from './normalize';
|
|
import { emojifyElement, emojifyText } from './render';
|
|
import type { CustomEmojiMapArg, EmojiAppState } from './types';
|
|
import { stringHasAnyEmoji } from './utils';
|
|
|
|
interface UseEmojifyOptions {
|
|
text: string;
|
|
extraEmojis?: CustomEmojiMapArg;
|
|
deep?: boolean;
|
|
}
|
|
|
|
export function useEmojify({
|
|
text,
|
|
extraEmojis,
|
|
deep = true,
|
|
}: UseEmojifyOptions) {
|
|
const [emojifiedText, setEmojifiedText] = useState<string | null>(null);
|
|
|
|
const appState = useEmojiAppState();
|
|
const extra = useMemo(() => cleanExtraEmojis(extraEmojis), [extraEmojis]);
|
|
|
|
const emojify = useCallback(
|
|
async (input: string) => {
|
|
let result: string | null = null;
|
|
if (deep) {
|
|
const wrapper = document.createElement('div');
|
|
wrapper.innerHTML = input;
|
|
if (await emojifyElement(wrapper, appState, extra ?? {})) {
|
|
result = wrapper.innerHTML;
|
|
}
|
|
} else {
|
|
result = await emojifyText(text, appState, extra ?? {});
|
|
}
|
|
if (result) {
|
|
setEmojifiedText(result);
|
|
} else {
|
|
setEmojifiedText(input);
|
|
}
|
|
},
|
|
[appState, deep, extra, text],
|
|
);
|
|
useLayoutEffect(() => {
|
|
if (isModernEmojiEnabled() && !!text.trim() && stringHasAnyEmoji(text)) {
|
|
void emojify(text);
|
|
} else {
|
|
// If no emoji or we don't want to render, fall back.
|
|
setEmojifiedText(text);
|
|
}
|
|
}, [emojify, text]);
|
|
|
|
return emojifiedText;
|
|
}
|
|
|
|
export function useEmojiAppState(): EmojiAppState {
|
|
const locale = useAppSelector((state) =>
|
|
toSupportedLocale(state.meta.get('locale') as string),
|
|
);
|
|
const mode = useAppSelector((state) =>
|
|
determineEmojiMode(state.meta.get('emoji_style') as string),
|
|
);
|
|
|
|
return {
|
|
currentLocale: locale,
|
|
locales: [locale],
|
|
mode,
|
|
darkTheme: document.body.classList.contains('theme-default'),
|
|
};
|
|
}
|