mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
import { capitalize } from "es-toolkit/compat";
|
|
import { observer } from "mobx-react";
|
|
import { useCallback, useMemo, useEffect } from "react";
|
|
import { emojiMartToGemoji, snakeCase } from "@shared/editor/lib/emoji";
|
|
import { search as emojiSearch } from "@shared/utils/emoji";
|
|
import EmojiMenuItem from "./EmojiMenuItem";
|
|
import type { Props as SuggestionsMenuProps } from "./SuggestionsMenu";
|
|
import SuggestionsMenu from "./SuggestionsMenu";
|
|
import useStores from "~/hooks/useStores";
|
|
import { determineIconType } from "@shared/utils/icon";
|
|
import { IconType } from "@shared/types";
|
|
|
|
type Emoji = {
|
|
name: string;
|
|
title: string;
|
|
emoji: string;
|
|
description: string;
|
|
attrs: { "data-name": string };
|
|
};
|
|
|
|
type Props = Omit<
|
|
SuggestionsMenuProps<Emoji>,
|
|
"renderMenuItem" | "items" | "embeds"
|
|
>;
|
|
|
|
const EmojiMenu = (props: Props) => {
|
|
const { emojis } = useStores();
|
|
const { search = "" } = props;
|
|
|
|
useEffect(() => {
|
|
if (search) {
|
|
void emojis.fetchPage({ query: search });
|
|
}
|
|
}, [emojis, search]);
|
|
|
|
const items = useMemo(
|
|
() =>
|
|
emojiSearch({ customEmojis: emojis.orderedData, query: search })
|
|
.map((item) => {
|
|
// We snake_case the shortcode for backwards compatability with gemoji to
|
|
// avoid multiple formats being written into documents.
|
|
const id = emojiMartToGemoji[item.id] || item.id;
|
|
const type = determineIconType(id);
|
|
const value = type === IconType.Custom ? id : snakeCase(id);
|
|
const emoji = item.value;
|
|
|
|
return {
|
|
name: "emoji",
|
|
title: emoji,
|
|
description:
|
|
type === IconType.Custom
|
|
? item.name
|
|
: capitalize(item.name.toLowerCase()),
|
|
emoji,
|
|
attrs: { "data-name": value },
|
|
};
|
|
})
|
|
.slice(0, 15),
|
|
[search, emojis.orderedData]
|
|
);
|
|
|
|
const renderMenuItem = useCallback(
|
|
(item, _index, options) => (
|
|
<EmojiMenuItem {...options} title={item.description} emoji={item.emoji} />
|
|
),
|
|
[]
|
|
);
|
|
|
|
return (
|
|
<SuggestionsMenu
|
|
{...props}
|
|
filterable={false}
|
|
renderMenuItem={renderMenuItem}
|
|
items={items}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default observer(EmojiMenu);
|