diff --git a/app/editor/components/EmojiMenu.tsx b/app/editor/components/EmojiMenu.tsx index 961e7a092..efd24aa75 100644 --- a/app/editor/components/EmojiMenu.tsx +++ b/app/editor/components/EmojiMenu.tsx @@ -1,6 +1,8 @@ -import data, { type Emoji as TEmoji, EmojiMartData } from "@emoji-mart/data"; +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 EmojiMenuItem from "./EmojiMenuItem"; @@ -16,14 +18,8 @@ type Emoji = { attrs: { markup: string; "data-name": string }; }; -const searcher = new FuzzySearch( - Object.values((data as EmojiMartData).emojis), - ["keywords"], - { - caseSensitive: true, - sort: true, - } -); +void init({ data }); +let searcher: FuzzySearch; type Props = Omit< SuggestionsMenuProps, @@ -33,24 +29,35 @@ type Props = Omit< 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(); - const result = searcher.search(n).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 }, - }; - }); + 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 result.slice(0, 10); + return { + name: "emoji", + title: emoji, + description: capitalize(item.name.toLowerCase()), + emoji, + attrs: { markup: shortcode, "data-name": shortcode }, + }; + }) + .slice(0, 15); }, [search]); return (