import data, { type Emoji as TEmoji } from "@emoji-mart/data"; import { init, Data } from "emoji-mart"; import FuzzySearch from "fuzzy-search"; import capitalize from "lodash/capitalize"; import sortBy from "lodash/sortBy"; import React from "react"; import { emojiMartToGemoji, snakeCase } from "@shared/editor/lib/emoji"; import { isMac } from "@shared/utils/browser"; import EmojiMenuItem from "./EmojiMenuItem"; import SuggestionsMenu, { Props as SuggestionsMenuProps, } from "./SuggestionsMenu"; type Emoji = { name: string; title: string; emoji: string; description: string; attrs: { markup: string; "data-name": string }; }; init({ data, noCountryFlags: isMac() ? false : undefined, }); let searcher: FuzzySearch; type Props = Omit< SuggestionsMenuProps, "renderMenuItem" | "items" | "embeds" | "trigger" >; const EmojiMenu = (props: Props) => { const { search = "" } = props; if (!searcher) { searcher = new FuzzySearch(Object.values(Data.emojis), ["search"], { caseSensitive: false, sort: true, }); } const items = React.useMemo(() => { const n = search.toLowerCase(); return sortBy(searcher.search(n), (item) => { const nlc = item.name.toLowerCase(); return nlc === n ? -1 : nlc.startsWith(n) ? 0 : 1; }) .map((item) => { // We snake_case the shortcode for backwards compatability with gemoji to // avoid multiple formats being written into documents. const shortcode = snakeCase(emojiMartToGemoji[item.id] || item.id); const emoji = item.skins[0].native; return { name: "emoji", title: emoji, description: capitalize(item.name.toLowerCase()), emoji, attrs: { markup: shortcode, "data-name": shortcode }, }; }) .slice(0, 15); }, [search]); return ( ( )} items={items} /> ); }; export default EmojiMenu;