move HTML and Text components into the Emoji directory
Some checks are pending
Chromatic / Run Chromatic (push) Waiting to run

This commit is contained in:
ChaosExAnima 2025-09-29 13:25:48 +02:00
parent 2e7629d03b
commit 3188a0e11e
No known key found for this signature in database
GPG Key ID: 8F2B333100FB6117
9 changed files with 68 additions and 77 deletions

View File

@ -2,10 +2,11 @@ import { useCallback } from 'react';
import { useLinks } from 'mastodon/hooks/useLinks';
import { EmojiHTML } from '../features/emoji/emoji_html';
import { useAppSelector } from '../store';
import { isModernEmojiEnabled } from '../utils/environment';
import { EmojiHTML } from './emoji/html';
interface AccountBioProps {
className: string;
accountId: string;

View File

@ -2,7 +2,7 @@ import type { ComponentPropsWithoutRef, FC } from 'react';
import classNames from 'classnames';
import { EmojiText } from '@/mastodon/features/emoji/emoji_text';
import { EmojiText } from '@/mastodon/components/emoji/text';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { AnimateEmojiProvider } from '../emoji/context';

View File

@ -1,9 +1,9 @@
import type { ComponentPropsWithoutRef, FC } from 'react';
import { ModernEmojiText } from '@/mastodon/features/emoji/emoji_text';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { AnimateEmojiProvider } from '../emoji/context';
import { ModernEmojiText } from '../emoji/text';
import type { DisplayNameProps } from './index';

View File

@ -3,10 +3,14 @@ import type {
ElementType,
PropsWithChildren,
} from 'react';
import { createContext, useCallback, useState } from 'react';
import { createContext, useCallback, useMemo, useState } from 'react';
import { cleanExtraEmojis } from '@/mastodon/features/emoji/normalize';
import { autoPlayGif } from '@/mastodon/initial_state';
import type { ExtraCustomEmojiMap } from 'mastodon/features/emoji/types';
import type {
CustomEmojiMapArg,
ExtraCustomEmojiMap,
} from 'mastodon/features/emoji/types';
// Animation context
export const AnimateEmojiContext = createContext(autoPlayGif ?? false);
@ -47,10 +51,11 @@ export const CustomEmojiContext = createContext<ExtraCustomEmojiMap>({});
export const CustomEmojiProvider = ({
children,
emoji = {},
}: PropsWithChildren<{ emoji?: ExtraCustomEmojiMap | null }>) => {
emojis: rawEmojis,
}: PropsWithChildren<{ emojis?: CustomEmojiMapArg }>) => {
const emojis = useMemo(() => cleanExtraEmojis(rawEmojis) ?? {}, [rawEmojis]);
return (
<CustomEmojiContext.Provider value={emoji ?? {}}>
<CustomEmojiContext.Provider value={emojis}>
{children}
</CustomEmojiContext.Provider>
);

View File

@ -3,14 +3,12 @@ import type { ComponentPropsWithoutRef, ElementType } from 'react';
import classNames from 'classnames';
import { Emoji } from '@/mastodon/components/emoji';
import { CustomEmojiProvider } from '@/mastodon/components/emoji/context';
import type { CustomEmojiMapArg } from '@/mastodon/features/emoji/types';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { htmlStringToComponents } from '@/mastodon/utils/html';
import { cleanExtraEmojis } from './normalize';
import { tokenizeText } from './render';
import type { CustomEmojiMapArg } from './types';
import { CustomEmojiProvider } from './context';
import { textToEmojis } from './index';
type EmojiHTMLProps<Element extends ElementType = 'div'> = Omit<
ComponentPropsWithoutRef<Element>,
@ -19,21 +17,11 @@ type EmojiHTMLProps<Element extends ElementType = 'div'> = Omit<
htmlString: string;
extraEmojis?: CustomEmojiMapArg;
as?: Element;
shallow?: boolean;
className?: string;
};
export function onText(text: string) {
return tokenizeText(text).map((token, index) => {
if (typeof token === 'string') {
return token;
}
return <Emoji code={token.code} key={`emoji-${token.code}-${index}`} />;
});
}
export const ModernEmojiHTML = ({
extraEmojis: rawExtraEmojis,
extraEmojis,
htmlString,
as: Wrapper = 'div', // Rename for syntax highlighting
shallow,
@ -41,20 +29,16 @@ export const ModernEmojiHTML = ({
...props
}: EmojiHTMLProps<ElementType>) => {
const contents = useMemo(
() => htmlStringToComponents(htmlString, { onText }),
() => htmlStringToComponents(htmlString, { onText: textToEmojis }),
[htmlString],
);
const extraEmojis = useMemo(
() => cleanExtraEmojis(rawExtraEmojis),
[rawExtraEmojis],
);
const components = (
<Wrapper {...props} className={className}>
{contents}
</Wrapper>
);
return (
<CustomEmojiProvider emoji={extraEmojis}>{components}</CustomEmojiProvider>
<CustomEmojiProvider emojis={extraEmojis}>
<Wrapper {...props} className={className}>
{contents}
</Wrapper>
</CustomEmojiProvider>
);
};
@ -64,14 +48,7 @@ export const EmojiHTML = <Element extends ElementType>(
if (isModernEmojiEnabled()) {
return <ModernEmojiHTML {...props} />;
}
const {
as: asElement,
htmlString,
extraEmojis,
className,
shallow,
...rest
} = props;
const { as: asElement, htmlString, extraEmojis, className, ...rest } = props;
const Wrapper = asElement ?? 'div';
return (
<Wrapper

View File

@ -9,6 +9,7 @@ import {
loadEmojiDataToState,
shouldRenderImage,
stringToEmojiState,
tokenizeText,
} from '@/mastodon/features/emoji/render';
import { AnimateEmojiContext, CustomEmojiContext } from './context';
@ -83,3 +84,16 @@ export const Emoji: FC<EmojiProps> = ({
/>
);
};
/**
* Takes a text string and converts it to an array of React nodes.
* @param text The text to be tokenized and converted.
*/
export function textToEmojis(text: string) {
return tokenizeText(text).map((token, index) => {
if (typeof token === 'string') {
return token;
}
return <Emoji code={token.code} key={`emoji-${token.code}-${index}`} />;
});
}

View File

@ -0,0 +1,24 @@
import { useMemo } from 'react';
import type { FC } from 'react';
import type { CustomEmojiMapArg } from '@/mastodon/features/emoji/types';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { CustomEmojiProvider } from './context';
import { textToEmojis } from './index';
interface EmojiTextProps {
text: string;
extraEmojis?: CustomEmojiMapArg;
}
export const ModernEmojiText: FC<EmojiTextProps> = ({ text, extraEmojis }) => {
const contents = useMemo(() => textToEmojis(text), [text]);
return (
<CustomEmojiProvider emojis={extraEmojis}>{contents}</CustomEmojiProvider>
);
};
export const EmojiText: FC<EmojiTextProps> = ({ text }) =>
isModernEmojiEnabled() ? <ModernEmojiText text={text} /> : text;

View File

@ -13,10 +13,12 @@ import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'
import { Icon } from 'mastodon/components/icon';
import { Poll } from 'mastodon/components/poll';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
import { EmojiHTML } from '../features/emoji/emoji_html';
import { languages as preloadedLanguages } from 'mastodon/initial_state';
import { isModernEmojiEnabled } from '../utils/environment';
import { EmojiHTML } from './emoji/html';
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
/**

View File

@ -1,32 +0,0 @@
import { useMemo } from 'react';
import type { FC } from 'react';
import { CustomEmojiProvider } from '@/mastodon/components/emoji/context';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { onText } from './emoji_html';
import { cleanExtraEmojis } from './normalize';
import type { CustomEmojiMapArg } from './types';
interface EmojiTextProps {
text: string;
extraEmojis?: CustomEmojiMapArg;
}
export const ModernEmojiText: FC<EmojiTextProps> = ({
text,
extraEmojis: rawExtraEmojis,
}) => {
const contents = useMemo(() => onText(text), [text]);
const extraEmojis = useMemo(
() => cleanExtraEmojis(rawExtraEmojis),
[rawExtraEmojis],
);
return (
<CustomEmojiProvider emoji={extraEmojis}>{contents}</CustomEmojiProvider>
);
};
export const EmojiText: FC<EmojiTextProps> = ({ text }) =>
isModernEmojiEnabled() ? <ModernEmojiText text={text} /> : text;