Support a custom emoji data source by exposing a callback - #36
Open
nperez0111 wants to merge 7 commits into
Open
Support a custom emoji data source by exposing a callback#36nperez0111 wants to merge 7 commits into
nperez0111 wants to merge 7 commits into
Conversation
Node's types aren't installed since Frimousse only targets the browser, so the development-only warnings using process.env.NODE_ENV failed to type-check.
vitest-fetch-mock builds a Request to pass to its handler, and under jsdom the global AbortSignal comes from jsdom while Request comes from Node's undici, which brand-checks the signal against its own realm. Passing a signal to fetch therefore threw before any request was made. It also ignores AbortSignal entirely, so aborting never rejected. The Emojibase mock is now a plain fetch stub which handles both cases.
EmojiPicker.Root accepts a resolveEmojiData prop which is called with the
current locale and is expected to return its emoji data. It defaults to
defaultEmojiDataResolver, which is also exported so that custom resolvers
can delegate the locales they don't handle themselves.
<EmojiPicker.Root
locale={locale}
resolveEmojiData={(locale, options) =>
locale in myEmojiData
? myEmojiData[locale]
: defaultEmojiDataResolver(locale, options)
}
/>
This makes it possible to support locales Emojibase doesn't cover, or to
replace its data entirely, without it being all-or-nothing.
The local storage caching used for Emojibase data is now built on the
exported createEmojiDataCache, so custom resolvers can cache their own data
the same way. Its default namespace matches the previous keys, so existing
caches are reused as-is.
Resolvers are wrapped in a stable callback, otherwise an inline one would
re-resolve on every render of EmojiPicker.Root.
Emoji data is also revalidated once per locale per session instead of once
per session, which previously meant resolving any locale would skip the
ETag check of every other locale for the rest of the session.
Hand-authoring custom emoji data required setting `countryFlag: undefined` and `skins: undefined` on every emoji. Both are already validated as optional and read defensively, so they can be omitted entirely.
Documents `resolveEmojiData` with a live example switching between English, French, and a hand-written Turkish data set, along with the `createEmojiDataCache` helper and the updated API reference.
The site fails to start without one, but only the reactions in the header need a real key.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The goal of this change was to expose the emoji-data in Frimousse to be customizable so that the user can add additional locales & sets of emojis to expose within the Frimousse picker.
AI generated description of the changes:
Support custom emoji data and locales
Emoji data was previously always fetched from Emojibase, which limited the picker to the ~30 locales Emojibase ships and made it impossible to reuse data an app already has in memory. This adds a first-class way to provide your own.
The API
Emoji data is now resolved by a function, and EmojiPicker.Root takes a resolveEmojiData prop to replace it. Its default, defaultEmojiDataResolver, is exported — so custom resolvers can handle the locales they know about and delegate the rest.
Resolvers can be sync or async, receive (locale, { emojiVersion, emojibaseUrl, signal }), and locale is now widened to Locale | (string & {}) so any locale is accepted. Validation only happens inside defaultEmojiDataResolver, which still falls back to "en" with a warning for locales Emojibase doesn't support. Data returned by a custom resolver is used exactly as provided — no version or country-flag filtering.
createEmojiDataCache is also exported for resolvers that need to persist across page loads. It's the same localStorage cache defaultEmojiDataResolver uses internally, under the same key namespace, so existing caches are unaffected.
const cache = createEmojiDataCache({ name: "my-app/emoji-data" });
Why a resolver rather than a data prop
The motivating case is an editor shipping 36 locales where 8 aren't in Emojibase. A prop taking a data object is all-or-nothing: you either provide everything or nothing. A resolver lets you provide the 8 and delegate the other 28 in one expression, and it keeps caching, revalidation, and support filtering as implementation details of the default resolver rather than API surface.
Fixes along the way
Also included
Testing
New unit tests for the cache and the resolver (including per-locale revalidation and the unsupported-locale fallback), and browser tests covering delegation to the default resolver and the inline-resolver regression. 121 tests passing.
Breaking changes
None — the emojiData prop this replaces was never released.