diff --git a/.prettierignore b/.prettierignore
index 4b02ec540..7307d99ba 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -7,3 +7,7 @@ examples/**/serviceWorker.ts
.agents/
.claude/skills/
skills-lock.json
+
+# Vendored emoji dataset (snapshot of @emoji-mart/data — kept minified; regenerate
+# via `node scripts/vendor-emoji-data.mjs`)
+src/plugins/Emojis/data/emoji-data.json
diff --git a/AI.md b/AI.md
index 0fdb9ed29..83b229940 100644
--- a/AI.md
+++ b/AI.md
@@ -241,26 +241,134 @@ const CustomMessage = () => {
**User intent**: "Add emoji picker and autocomplete"
+Emoji support is built into the SDK — the **`StreamEmojiPicker`** needs no `emoji-mart`
+packages or `init()` call.
+
+> **Deprecation:** the `EmojiPicker` export from `stream-chat-react/emojis` is the legacy
+> **emoji-mart-backed** picker. It still works unchanged for backwards compatibility, but
+> is **deprecated and will be removed in v15** and logs a one-time console warning. New
+> integrations should use `StreamEmojiPicker`; existing emoji-mart integrations keep
+> working until you migrate (see _Migrating from emoji-mart_ below).
+
**Steps**:
-1. Install emoji packages: `npm install emoji-mart @emoji-mart/react @emoji-mart/data`
-2. Initialize emoji data: `init({ data })` from `emoji-mart`
-3. Import `EmojiPicker` from `stream-chat-react/emojis`
-4. Pass `EmojiPicker` and `emojiSearchIndex={SearchIndex}` to `Channel`
+1. Import `StreamEmojiPicker` from `stream-chat-react/emojis` and pass it to `Channel`.
+2. Import the emoji picker's stylesheet: `import 'stream-chat-react/css/emoji-picker.css'`.
+ It is intentionally **not** part of `index.css` (so apps that don't use the picker
+ ship no emoji CSS); without it the picker panel renders unstyled.
+3. (Optional) For `:shortcode` autocomplete + emoticon replacement, register the
+ emoji middleware on the message composer's text composer with
+ `createTextComposerEmojiMiddleware()` (no argument — it uses the built-in index).
```tsx
-import { EmojiPicker } from 'stream-chat-react/emojis';
-import { init, SearchIndex } from 'emoji-mart';
-import data from '@emoji-mart/data';
-
-init({ data });
+import { StreamEmojiPicker } from 'stream-chat-react/emojis';
+import 'stream-chat-react/css/emoji-picker.css';
-
- {/* ... */}
- ;
+{/* ... */} ;
```
-**Note**: For React 19, may need package.json overrides for `@emoji-mart/react`
+**Notes**:
+
+- Passing a custom `emojiSearchIndex` (including emoji-mart's `SearchIndex`) is
+ still supported for advanced use.
+- On `StreamEmojiPicker`, skin tone and "frequently used" are integrator-managed props
+ (`skinTone`/`onSkinToneChange`, `frequentlyUsedEmoji`/`onFrequentlyUsedChange`);
+ the SDK does not persist them. See `examples/vite/` for a localStorage example.
+- `StreamEmojiPicker` exposes a small, flat set of props (no emoji-mart-style
+ `pickerProps` bag): `theme` (`'auto'` — the default, inherits the ancestor SDK theme —
+ `'light'`, or `'dark'`), `style`, `categories` (filter + reorder; `'frequent'` always
+ prepends and cannot be repositioned), `exceptEmojis`, `autoFocus` (default `true`), and
+ `onClickOutside`. Layout and sizing are CSS, not props: set
+ `--str-chat__emoji-picker-per-line` (default `9`) for the column count and the other
+ `--str-chat__emoji-picker-*` tokens for sizing/colors. Emoji-mart-only features (image
+ `set`s, `custom` emoji, `data`, `i18n` / `locale`, …) aren't available on the built-in
+ picker — keep using the deprecated `EmojiPicker` if you still need them. Try it live in
+ the "Emoji Picker" settings tab of `examples/vite/`.
+
+- **Custom layouts (composition).** For a non-standard arrangement, or to replace a part,
+ compose the picker from its slots instead of rearranging props. Rendered directly,
+ `StreamEmojiPicker` is the preset; `StreamEmojiPicker.Root` + the slots let you assemble
+ it yourself:
+
+ ```tsx
+ import { StreamEmojiPicker, useEmojiPickerContext } from 'stream-chat-react/emojis';
+
+
+
+
+
+
+ ;
+ ```
+
+ The rule: **the SDK owns the data + the selection; you own presentation + behavior.**
+ `Root` exposes everything through `useEmojiPickerContext()` — read-only data
+ (`categories`, `searchResults`, `status`, `skinTones`, `resolveNative`) and report-back
+ setters (`selectEmoji`, `setQuery`, `setSkinTone`, `setActiveCategory` /
+ `requestScrollToCategory`). A custom slot is just a component that calls the hook; when
+ you replace a slot, that slot's mechanics (scrolling, scroll-spy, roving keyboard, ARIA,
+ virtualization, hover-preview) become yours, but it keeps talking to the others through
+ the shared state. Example — a paged grid driven by the built-in `Nav`:
+
+ ```tsx
+ function PagedGrid() {
+ const {
+ categories,
+ activeCategoryId,
+ searchResults,
+ isSearching,
+ selectEmoji,
+ resolveNative,
+ } = useEmojiPickerContext();
+ const emojis = isSearching
+ ? (searchResults ?? [])
+ : ((categories.find((c) => c.id === activeCategoryId) ?? categories[0])?.emojis ??
+ []);
+ return (
+
+ {emojis.map((e) => (
+ selectEmoji(e)}>
+ {resolveNative(e)}
+
+ ))}
+
+ );
+ }
+ ```
+
+ `Root` always keeps the container-level a11y (dialog role, Escape-to-close,
+ focus-return) and the loading/error states, regardless of how you recompose the inside.
+
+- To let users **react with any emoji** (the reaction selector's `+` button), fill
+ `reactionOptions.extended` with the full emoji set. It also gates display — a reaction
+ whose type isn't in `quick`/`extended` is not rendered. Load it lazily from the emojis
+ entry (the dataset is code-split, so this adds nothing to your initial bundle):
+
+ ```tsx
+ import { defaultReactionOptions, type ReactionOptions } from 'stream-chat-react';
+ import { loadDefaultExtendedReactionOptions } from 'stream-chat-react/emojis';
+
+ const [reactionOptions, setReactionOptions] =
+ useState(defaultReactionOptions);
+ useEffect(() => {
+ loadDefaultExtendedReactionOptions().then((extended) =>
+ setReactionOptions({ ...defaultReactionOptions, extended }),
+ );
+ }, []);
+
+ {/* ... */} ;
+ ```
+
+ For a curated subset instead, build the `extended` map yourself with `mapEmojiMartData`.
+
+- **Migrating from emoji-mart** (the deprecated `EmojiPicker`): swap `EmojiPicker` →
+ `StreamEmojiPicker`, then remove the `emoji-mart` / `@emoji-mart/react` /
+ `@emoji-mart/data` installs and any `init({ data })` call. The deprecated `EmojiPicker`
+ takes a raw emoji-mart `pickerProps` bag (e.g. `set`, `emojiSize`); `StreamEmojiPicker`
+ instead exposes flat props (`theme`, `categories`, `exceptEmojis`, `autoFocus`, …) and
+ moves layout/sizing to `--str-chat__emoji-picker-*` CSS tokens. Autocomplete
+ (`createTextComposerEmojiMiddleware`) and reactions (`mapEmojiMartData`) are
+ engine-agnostic and need no changes.
**Reference**: See `examples/tutorial/src/6-emoji-picker/`
@@ -365,9 +473,11 @@ body {
**Solution**:
-- Ensure emoji packages are installed
-- Initialize with `init({ data })` before rendering
-- For React 19, add package.json overrides if needed
+- Ensure `EmojiPicker` from `stream-chat-react/emojis` is passed to `Channel` (or set
+ via `ComponentContext`)
+- Import the emoji picker CSS: `import 'stream-chat-react/css/emoji-picker.css'`
+- For `:shortcode` autocomplete, register `createTextComposerEmojiMiddleware()` on
+ the composer's text composer
## Resources
@@ -386,10 +496,8 @@ body {
- `react`: ^19.0.0 || ^18.0.0 || ^17.0.0
- `react-dom`: ^19.0.0 || ^18.0.0 || ^17.0.0
- `stream-chat`: ^9.27.2
-- **Optional Dependencies** (for emoji support):
- - `emoji-mart`: ^5.4.0
- - `@emoji-mart/react`: ^1.1.0
- - `@emoji-mart/data`: ^1.1.0
+- **Emoji support**: built in via the `stream-chat-react/emojis` entry point — no
+ `emoji-mart` packages required.
## Best Practices
diff --git a/examples/tutorial/package.json b/examples/tutorial/package.json
index 101fca5e7..4dfad3662 100644
--- a/examples/tutorial/package.json
+++ b/examples/tutorial/package.json
@@ -12,8 +12,6 @@
"hoistingLimits": "workspaces"
},
"dependencies": {
- "@emoji-mart/data": "^1.2.1",
- "emoji-mart": "^5.6.0",
"react": "^19.2.6",
"react-dom": "^19.2.6",
"stream-chat": "^9.49.0",
diff --git a/examples/tutorial/src/6-emoji-picker/App.tsx b/examples/tutorial/src/6-emoji-picker/App.tsx
index 5f339501b..315b636f3 100644
--- a/examples/tutorial/src/6-emoji-picker/App.tsx
+++ b/examples/tutorial/src/6-emoji-picker/App.tsx
@@ -12,10 +12,7 @@ import {
Window,
WithComponents,
} from 'stream-chat-react';
-import { EmojiPicker } from 'stream-chat-react/emojis';
-
-import { init, SearchIndex } from 'emoji-mart';
-import data from '@emoji-mart/data';
+import { StreamEmojiPicker } from 'stream-chat-react/emojis';
import './layout.css';
import { apiKey, tokenProvider, userId, userName } from '../1-client-setup/credentials';
@@ -32,8 +29,6 @@ const filters: ChannelFilters = {
members: { $in: [userId] },
};
-init({ data });
-
const App = () => {
const [isReady, setIsReady] = useState(false);
const client = useCreateChatClient({
@@ -66,13 +61,13 @@ const App = () => {
return (
-
+
-
+
diff --git a/examples/tutorial/src/6-emoji-picker/layout.css b/examples/tutorial/src/6-emoji-picker/layout.css
index 2fd790e68..fb1ab9794 100644
--- a/examples/tutorial/src/6-emoji-picker/layout.css
+++ b/examples/tutorial/src/6-emoji-picker/layout.css
@@ -1,5 +1,9 @@
@layer stream, stream-overrides;
@import 'stream-chat-react/dist/css/index.css' layer(stream);
+/* The emoji picker ships its own opt-in stylesheet (kept out of index.css so apps
+ that don't use it pay no CSS cost). This step renders , so it must
+ be imported or the picker panel renders unstyled. */
+@import 'stream-chat-react/dist/css/emoji-picker.css' layer(stream);
@layer stream-overrides {
.custom-theme {
diff --git a/examples/tutorial/src/App.tsx b/examples/tutorial/src/App.tsx
index 35a6b0092..6348377e5 100644
--- a/examples/tutorial/src/App.tsx
+++ b/examples/tutorial/src/App.tsx
@@ -57,7 +57,7 @@ const steps: TutorialStep[] = [
id: 'emoji-picker',
title: '6. Emoji Picker',
description:
- 'Wire a custom EmojiPicker into MessageComposer with emoji-mart search support.',
+ 'Wire a custom EmojiPicker into MessageComposer with built-in emoji search support.',
Component: EmojiPickerStep,
},
{
diff --git a/examples/vite/package.json b/examples/vite/package.json
index 7289bf3ba..87b938f87 100644
--- a/examples/vite/package.json
+++ b/examples/vite/package.json
@@ -10,6 +10,7 @@
},
"dependencies": {
"@emoji-mart/data": "^1.2.1",
+ "@emoji-mart/react": "^1.1.1",
"clsx": "^2.1.1",
"emoji-mart": "^5.6.0",
"human-id": "^4.1.3",
diff --git a/examples/vite/src/App.tsx b/examples/vite/src/App.tsx
index bdf11f91c..2b8f9aa91 100644
--- a/examples/vite/src/App.tsx
+++ b/examples/vite/src/App.tsx
@@ -1,4 +1,11 @@
-import { type CSSProperties, useCallback, useEffect, useMemo, useRef } from 'react';
+import {
+ type CSSProperties,
+ useCallback,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from 'react';
import type {
ChannelFilters,
ChannelOptions,
@@ -22,7 +29,6 @@ import {
ChatView,
defaultReactionOptions,
DialogManagerProvider,
- mapEmojiMartData,
MessageReactions,
NotificationList,
type NotificationListProps,
@@ -32,9 +38,12 @@ import {
useCreateChatClient,
WithComponents,
} from 'stream-chat-react';
-import { createTextComposerEmojiMiddleware, EmojiPicker } from 'stream-chat-react/emojis';
-import { init, SearchIndex } from 'emoji-mart';
-import data from '@emoji-mart/data/sets/14/native.json';
+import {
+ createTextComposerEmojiMiddleware,
+ EmojiPicker,
+ loadDefaultExtendedReactionOptions,
+ StreamEmojiPicker,
+} from 'stream-chat-react/emojis';
import { humanId } from 'human-id';
import { appSettingsStore, useAppSettingsSelector } from './AppSettings';
@@ -73,8 +82,6 @@ import { CommandModeAttachmentSelector } from './CommandModeAttachmentSelector.t
const PUBLIC_VITE_EXAMPLE_API_KEY = 'xzwhhgtazy6h';
-init({ data });
-
const parseUserIdFromToken = (token: string): string | undefined => {
try {
const [, payload] = token.split('.');
@@ -109,11 +116,6 @@ const sort: ChannelSort = { last_message_at: -1, updated_at: -1 };
// @ts-expect-error ai_generated isn't on LocalMessage's public type yet
const isMessageAIGenerated = (message: LocalMessage) => !!message?.ai_generated;
-const newReactionOptions: ReactionOptions = {
- ...defaultReactionOptions,
- extended: mapEmojiMartData(data),
-};
-
const useUser = () => {
const searchParams = useMemo(() => new URLSearchParams(window.location.search), []);
@@ -180,18 +182,62 @@ const CustomMessageReactions = (props: React.ComponentProps ;
+// Demonstrates integrator-owned persistence of the picker's skin tone and
+// frequently-used emoji via localStorage. The SDK itself never touches storage —
+// it exposes these as controlled props so apps own where the state lives.
+const EMOJI_SKIN_TONE_KEY = 'vite-example/emoji-skin-tone';
+const EMOJI_FREQUENTLY_USED_KEY = 'vite-example/emoji-frequently-used';
+
+const readStored = (key: string, fallback: T): T => {
+ try {
+ const raw = localStorage.getItem(key);
+ return raw ? (JSON.parse(raw) as T) : fallback;
+ } catch {
+ return fallback;
+ }
+};
+
+const writeStored = (key: string, value: unknown) => {
+ try {
+ localStorage.setItem(key, JSON.stringify(value));
+ } catch {
+ // ignore storage failures (e.g. private browsing)
+ }
+};
+
const EmojiPickerWithCustomOptions = (
- props: React.ComponentProps,
+ props: React.ComponentProps,
) => {
const { mode } = useAppSettingsSelector((state) => state.theme);
+ const { engine, ...pickerOptions } = useAppSettingsSelector(
+ (state) => state.emojiPicker,
+ );
+ const [skinTone, setSkinTone] = useState(() => readStored(EMOJI_SKIN_TONE_KEY, 0));
+ const [frequentlyUsedEmoji, setFrequentlyUsedEmoji] = useState(() =>
+ readStored(EMOJI_FREQUENTLY_USED_KEY, []),
+ );
+
+ // The deprecated emoji-mart picker self-manages skin tone + frequently-used and
+ // accepts the same emoji-mart-compatible option names, so it only needs pickerProps.
+ if (engine === 'emoji-mart') {
+ return ;
+ }
return (
- {
+ setFrequentlyUsedEmoji(ids);
+ writeStored(EMOJI_FREQUENTLY_USED_KEY, ids);
+ }}
+ onSkinToneChange={(tone) => {
+ setSkinTone(tone);
+ writeStored(EMOJI_SKIN_TONE_KEY, tone);
}}
+ skinTone={skinTone}
+ theme={mode}
/>
);
};
@@ -226,6 +272,21 @@ const CustomAttachmentWithActions = (props: AttachmentProps) => (
const App = () => {
const { tokenProvider, userId, userImage, userName } = useUser();
+ // Restore "react with any emoji": lazily load the full emoji set and expose it as the
+ // extended reaction options (the reaction selector's "+" list). The dataset loads on
+ // demand via the same code-split chunk the picker uses; until it resolves only the
+ // quick reactions show.
+ const [reactionOptions, setReactionOptions] =
+ useState(defaultReactionOptions);
+ useEffect(() => {
+ let active = true;
+ loadDefaultExtendedReactionOptions().then((extended) => {
+ if (active) setReactionOptions({ ...defaultReactionOptions, extended });
+ });
+ return () => {
+ active = false;
+ };
+ }, []);
const chatView = useAppSettingsSelector((state) => state.chatView);
const { mode: themeMode } = useAppSettingsSelector((state) => state.theme);
const initialSearchParams = useMemo(
@@ -357,9 +418,7 @@ const App = () => {
});
composer.textComposer.middlewareExecutor.insert({
- middleware: [
- createTextComposerEmojiMiddleware(SearchIndex) as TextComposerMiddleware,
- ],
+ middleware: [createTextComposerEmojiMiddleware() as TextComposerMiddleware],
position: { before: 'stream-io/text-composer/mentions-middleware' },
unique: true,
});
@@ -414,11 +473,10 @@ const App = () => {
return (
>;
+
+type EmojiPickerTabProps = {
+ close: () => void;
+};
+
+const OPTION_BUTTON_CLASS =
+ 'app__settings-modal__option-button str-chat__button--outline str-chat__button--secondary str-chat__button--size-sm';
+
+const update = (patch: Partial) => {
+ const current = appSettingsStore.getLatestValue().emojiPicker;
+ appSettingsStore.partialNext({ emojiPicker: { ...current, ...patch } });
+};
+
+type FieldProps = {
+ label: string;
+ onSelect: (value: T) => void;
+ options: { label: string; value: T }[];
+ value: T;
+};
+
+function Field({
+ label,
+ onSelect,
+ options,
+ value,
+}: FieldProps) {
+ return (
+
+
{label}
+
+ {options.map((option) => (
+ onSelect(option.value)}
+ >
+ {option.label}
+
+ ))}
+
+
+ );
+}
+
+/**
+ * A custom "paged" grid slot — renders only the active category (a layout the default
+ * scrolling grid can't do), driven entirely by context: it reads `activeCategoryId`
+ * (which the built-in Nav sets) and reports selection via `selectEmoji`. Demonstrates
+ * that a replacement slot only needs the SDK's data + report-back APIs.
+ */
+const PagedGrid = () => {
+ const {
+ activeCategoryId,
+ categories,
+ isSearching,
+ resolveNative,
+ searchResults,
+ selectEmoji,
+ } = useEmojiPickerContext();
+ const emojis = isSearching
+ ? (searchResults ?? [])
+ : ((categories.find((category) => category.id === activeCategoryId) ?? categories[0])
+ ?.emojis ?? []);
+
+ // A plain (non-virtualized) grid must bring its own scroll — the default grid gets it
+ // from Virtuoso. `__grid-container` is the SDK's scrollable body class (block-size:100%
+ // + overflow-y), the same one the built-in search-results view uses.
+ return (
+
+
+
+ {emojis.map((emoji) => (
+ selectEmoji(emoji)}
+ type='button'
+ >
+ {resolveNative(emoji)}
+
+ ))}
+
+
+
+ );
+};
+
+/**
+ * Always-open picker wired to the current settings, so tweaks show instantly without
+ * opening the composer. Skin tone and frequently-used are local to the preview —
+ * selecting an emoji here feeds the "frequently used" row. The `stream-composed` engine
+ * shows the same picker assembled from `StreamEmojiPicker.Root` + slots, swapping in the
+ * custom `PagedGrid` while keeping the built-in nav/search/preview/skin-tone.
+ */
+const EmojiPickerPreview = ({ options }: { options: EmojiPickerSettingsState }) => {
+ const { mode } = useAppSettingsSelector((state) => state.theme);
+ const { autoFocus, engine } = options;
+ const [skinTone, setSkinTone] = useState(0);
+ const [frequentlyUsedIds, setFrequentlyUsedIds] = useState([]);
+
+ const recordUse = (emoji: EmojiSelection) =>
+ setFrequentlyUsedIds((ids) => [emoji.id, ...ids.filter((id) => id !== emoji.id)]);
+
+ // The deprecated emoji-mart picker renders inline too and honors the same option
+ // names, so the shared controls drive both engines.
+ if (engine === 'emoji-mart') {
+ return (
+ (await import('@emoji-mart/data')).default}
+ onEmojiSelect={() => undefined}
+ theme={mode}
+ />
+ );
+ }
+
+ if (engine === 'stream-composed') {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+ );
+};
+
+/**
+ * Playground for the built-in `StreamEmojiPicker`. Each control writes to the app
+ * settings store; the live preview (and the composer's picker via
+ * `EmojiPickerWithCustomOptions`) reflect the change instantly.
+ */
+export const EmojiPickerTab = ({ close }: EmojiPickerTabProps) => {
+ const { emojiPicker } = useAppSettingsState();
+ const atDefaults = (
+ Object.keys(DEFAULT_EMOJI_PICKER_SETTINGS) as (keyof EmojiPickerSettingsState)[]
+ ).every((key) => emojiPicker[key] === DEFAULT_EMOJI_PICKER_SETTINGS[key]);
+
+ return (
+
+
+
+
+
+
+
+
+ appSettingsStore.partialNext({
+ emojiPicker: DEFAULT_EMOJI_PICKER_SETTINGS,
+ })
+ }
+ >
+ Reset to defaults
+
+
+
+ label='Picker engine'
+ onSelect={(engine) => update({ engine })}
+ options={[
+ { label: 'Stream (native)', value: 'stream' },
+ { label: 'Stream (composed)', value: 'stream-composed' },
+ { label: 'emoji-mart (deprecated)', value: 'emoji-mart' },
+ ]}
+ value={emojiPicker.engine}
+ />
+
+ label='Auto-focus search'
+ onSelect={(autoFocus) => update({ autoFocus })}
+ options={[
+ { label: 'On', value: true },
+ { label: 'Off', value: false },
+ ]}
+ value={emojiPicker.autoFocus}
+ />
+
+
+
+
+
+ );
+};
diff --git a/examples/vite/src/AppSettings/tabs/EmojiPicker/index.ts b/examples/vite/src/AppSettings/tabs/EmojiPicker/index.ts
new file mode 100644
index 000000000..dc737187a
--- /dev/null
+++ b/examples/vite/src/AppSettings/tabs/EmojiPicker/index.ts
@@ -0,0 +1 @@
+export * from './EmojiPickerTab';
diff --git a/package.json b/package.json
index 6f810565c..54c1701ab 100644
--- a/package.json
+++ b/package.json
@@ -143,7 +143,7 @@
"@breezystack/lamejs": "^1.2.7",
"@commitlint/cli": "^21.0.1",
"@commitlint/config-conventional": "^21.0.1",
- "@emoji-mart/data": "^1.2.1",
+ "@emoji-mart/data": "1.2.1",
"@emoji-mart/react": "^1.1.1",
"@eslint/js": "^9.39.4",
"@semantic-release/changelog": "^6.0.3",
diff --git a/scripts/vendor-emoji-data.mjs b/scripts/vendor-emoji-data.mjs
new file mode 100644
index 000000000..0619c741b
--- /dev/null
+++ b/scripts/vendor-emoji-data.mjs
@@ -0,0 +1,49 @@
+// Regenerates the vendored emoji dataset used by the built-in emoji picker and
+// search index (src/plugins/Emojis/data/emoji-data.json).
+//
+// We vendor a snapshot of @emoji-mart/data's *native* set (no spritesheet) so the
+// SDK ships its own emoji data and does not depend on the unmaintained emoji-mart
+// packages at runtime. @emoji-mart/data stays a pinned devDependency used ONLY by
+// this script.
+//
+// Usage: node scripts/vendor-emoji-data.mjs
+//
+// The dataset is MIT-licensed (Copyright (c) Missive); its license is copied
+// verbatim to src/plugins/Emojis/data/LICENSE.
+
+import { createRequire } from 'node:module';
+import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import { dirname, join, resolve } from 'node:path';
+
+// @emoji-mart/data's "main" resolves to sets/15/native.json (its newest set), so
+// pinning 15 matches a bare `import data from '@emoji-mart/data'`.
+const SET = 15;
+
+const require = createRequire(import.meta.url);
+
+const sourcePath = require.resolve(`@emoji-mart/data/sets/${SET}/native.json`);
+const pkgPath = require.resolve('@emoji-mart/data/package.json');
+const pkg = require('@emoji-mart/data/package.json');
+const licensePath = join(dirname(pkgPath), 'LICENSE');
+
+const outDir = resolve(process.cwd(), 'src/plugins/Emojis/data');
+const outDataPath = join(outDir, 'emoji-data.json');
+const outLicensePath = join(outDir, 'LICENSE');
+
+const data = JSON.parse(readFileSync(sourcePath, 'utf8'));
+
+// `sheet` only describes spritesheet geometry (cols/rows); we render native unicode
+// exclusively, so it is dead weight. Everything else (categories, emojis, aliases)
+// is preserved verbatim so mapEmojiMartData and the search index keep working.
+delete data.sheet;
+
+mkdirSync(outDir, { recursive: true });
+writeFileSync(outDataPath, JSON.stringify(data));
+copyFileSync(licensePath, outLicensePath);
+
+const emojiCount = Object.keys(data.emojis).length;
+console.log(
+ `Vendored @emoji-mart/data@${pkg.version} (set ${SET}, native): ` +
+ `${emojiCount} emoji, ${data.categories.length} categories -> ${outDataPath}`,
+);
+console.log(`Copied upstream MIT LICENSE -> ${outLicensePath}`);
diff --git a/src/components/MessageComposer/MessageComposer.tsx b/src/components/MessageComposer/MessageComposer.tsx
index 70888f629..4febe2c20 100644
--- a/src/components/MessageComposer/MessageComposer.tsx
+++ b/src/components/MessageComposer/MessageComposer.tsx
@@ -49,7 +49,7 @@ export type MessageComposerProps = {
audioRecordingConfig?: CustomAudioRecordingConfig;
/** Controls whether the users will be provided with the UI to record voice messages. */
audioRecordingEnabled?: boolean;
- /** Mechanism to be used with autocomplete and text replace features of the `MessageComposer` component, see [emoji-mart `SearchIndex`](https://github.com/missive/emoji-mart#%EF%B8%8F%EF%B8%8F-headless-search) */
+ /** Custom emoji search index for `MessageComposer` autocomplete and emoticon replacement. Optional — the SDK ships a built-in `defaultEmojiSearchIndex` (used by `createTextComposerEmojiMiddleware`); emoji-mart's `SearchIndex` also satisfies this interface. */
emojiSearchIndex?: ComponentContextValue['emojiSearchIndex'];
/** If true, focuses the text input on component mount */
focus?: boolean;
diff --git a/src/context/ComponentContext.tsx b/src/context/ComponentContext.tsx
index ae6c5fb70..c0b3b4632 100644
--- a/src/context/ComponentContext.tsx
+++ b/src/context/ComponentContext.tsx
@@ -139,7 +139,7 @@ export type ComponentContextValue = {
EditedMessagePreview?: React.ComponentType;
/** Custom UI component for rendering button with emoji picker in MessageComposer */
EmojiPicker?: React.ComponentType;
- /** Mechanism to be used with autocomplete and text replace features of the `MessageComposer` component, see [emoji-mart `SearchIndex`](https://github.com/missive/emoji-mart#%EF%B8%8F%EF%B8%8F-headless-search) */
+ /** Custom emoji search index for `MessageComposer` autocomplete and emoticon replacement. Optional — the SDK ships a built-in `defaultEmojiSearchIndex` (used by `createTextComposerEmojiMiddleware`); emoji-mart's `SearchIndex` also satisfies this interface. */
emojiSearchIndex?: EmojiSearchIndex;
/** Custom UI component to be displayed when the `MessageList` is empty, defaults to and accepts same props as: [EmptyStateIndicator](https://github.com/GetStream/stream-chat-react/blob/master/src/components/EmptyStateIndicator/EmptyStateIndicator.tsx) */
EmptyStateIndicator?: React.ComponentType;
diff --git a/src/i18n/de.json b/src/i18n/de.json
index ebe9c2644..53a87ab77 100644
--- a/src/i18n/de.json
+++ b/src/i18n/de.json
@@ -43,6 +43,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} hat abgestimmt: {{pollOptionText}}",
"📍Shared location": "📍Geteilter Standort",
"Actions": "Actions",
+ "Activities": "Aktivitäten",
"Add": "Hinzufügen",
"Add {{ count }} members_one": "{{ count }} Mitglied hinzufügen",
"Add {{ count }} members_other": "{{ count }} Mitglieder hinzufügen",
@@ -65,6 +66,7 @@
"Also sent in channel": "Auch im Kanal gesendet",
"An error has occurred during recording": "Ein Fehler ist während der Aufnahme aufgetreten",
"An error has occurred during the recording processing": "Ein Fehler ist während der Aufnahmeverarbeitung aufgetreten",
+ "Animals & Nature": "Tiere & Natur",
"Anonymous": "Anonym",
"Anonymous poll": "Anonyme Umfrage",
"Archive": "Archivieren",
@@ -100,8 +102,12 @@
"aria/Channel Actions": "Kanalaktionen",
"aria/Channel details": "Kanaldetails",
"aria/Channel list": "Kanalliste",
+ "aria/Channel search results": "Kanalsuchergebnisse",
"aria/Chat view controls": "Chat-Ansicht-Steuerelemente",
+ "aria/Chat view tabs": "Chat-Ansicht Tabs",
"aria/Chat: {{ channelName }}": "Chat: {{ channelName }}",
+ "aria/Choose default skin tone": "Standard-Hautton wählen",
+ "aria/Clear emoji search": "Emoji-Suche löschen",
"aria/Clear search": "Suche leeren",
"aria/Close callout dialog": "Hinweisdialog schließen",
"aria/Close thread": "Thread schließen",
@@ -270,6 +276,8 @@
"Create a question, add options, and configure poll settings": "Erstelle eine Frage, füge Optionen hinzu und konfiguriere die Umfrageeinstellungen",
"Create poll": "Umfrage erstellen",
"Current location": "Aktueller Standort",
+ "Dark": "Dunkel",
+ "Default": "Standard",
"Delete": "Löschen",
"Delete chat": "Chat löschen",
"Delete for me": "Für mich löschen",
@@ -340,6 +348,7 @@
"Failed to jump to the first unread message": "Fehler beim Springen zur ersten ungelesenen Nachricht",
"Failed to leave channel": "Kanal konnte nicht verlassen werden",
"Failed to load channels": "Kanäle konnten nicht geladen werden",
+ "Failed to load emojis": "Emojis konnten nicht geladen werden",
"Failed to load more channels": "Weitere Kanäle konnten nicht geladen werden",
"Failed to mark channel as read": "Fehler beim Markieren des Kanals als gelesen",
"Failed to play the recording": "Wiedergabe der Aufnahme fehlgeschlagen",
@@ -357,6 +366,9 @@
"fileCount_other": "{{ count }} dateien",
"Files": "Dateien",
"Flag": "Melden",
+ "Flags": "Flaggen",
+ "Food & Drink": "Essen & Trinken",
+ "Frequently used": "Häufig verwendet",
"Generating...": "Generieren...",
"giphy-command-args": "[Text]",
"giphy-command-description": "Poste ein zufälliges Gif in den Kanal",
@@ -430,6 +442,7 @@
"Leave chat": "Kanal verlassen",
"Left channel": "Kanal verlassen",
"Let others add options": "Andere Optionen hinzufügen lassen",
+ "Light": "Hell",
"Limit votes per person": "Stimmen pro Person begrenzen",
"Link": "Link",
"linkCount_one": "Link",
@@ -448,6 +461,9 @@
"Mark as unread": "Als ungelesen markieren",
"Maximum number of votes (from 2 to 10)": "Maximale Anzahl der Stimmen (von 2 bis 10)",
"Maximum votes per person": "Maximale Stimmen pro Person",
+ "Medium": "Mittel",
+ "Medium-Dark": "Mitteldunkel",
+ "Medium-Light": "Mittelhell",
"Member detail": "Mitgliederdetails",
"mention/Channel": "Kanal",
"mention/Channel Description": "Alle in diesem Kanal benachrichtigen",
@@ -478,6 +494,7 @@
"Next image": "Nächstes Bild",
"No chats here yet…": "Noch keine Chats hier...",
"No conversations yet": "Noch keine Unterhaltungen",
+ "No emoji found": "Keine Emojis gefunden",
"No files": "Keine Dateien",
"No items exist": "Keine Elemente vorhanden",
"No member found": "Kein Mitglied gefunden",
@@ -489,6 +506,7 @@
"Nobody will be able to vote in this poll anymore.": "Niemand kann mehr in dieser Umfrage abstimmen.",
"Nothing yet...": "Noch nichts...",
"Notify all {{ role }} members": "Alle Mitglieder mit Rolle {{ role }} benachrichtigen",
+ "Objects": "Objekte",
"Offline": "Offline",
"Ok": "OK",
"Online": "Online",
@@ -508,6 +526,7 @@
"People matching": "Passende Personen",
"Photo": "Foto",
"Photos & videos": "Fotos & Videos",
+ "Pick an emoji…": "Emoji auswählen…",
"Pin": "Anheften",
"Pin a message to see it here": "Hefte eine Nachricht an, um sie hier zu sehen",
"Pinned by {{ name }}": "Angeheftet von {{ name }}",
@@ -553,6 +572,7 @@
"replyCount_one": "1 Antwort",
"replyCount_other": "{{ count }} Antworten",
"Resend": "Erneut senden",
+ "Retry": "Erneut versuchen",
"Retry upload": "Upload erneut versuchen",
"Review all options available in this poll": "Überprüfe alle verfügbaren Optionen in dieser Umfrage",
"Review comments submitted with poll answers": "Überprüfe Kommentare, die mit Umfrageantworten eingereicht wurden",
@@ -563,6 +583,7 @@
"Save for later": "Für später speichern",
"Saved for later": "Für später gespeichert",
"Search": "Suche",
+ "Search emoji": "Emoji suchen",
"Search GIFs": "GIFs suchen",
"search-results-header-filter-source-button-label--channels": "Kanäle",
"search-results-header-filter-source-button-label--messages": "Nachrichten",
@@ -598,12 +619,14 @@
"size limit": "Größenbeschränkung",
"Slow Mode ON": "Langsamer Modus EIN",
"Slow mode, wait {{ seconds }}s...": "Langsamer Modus, warte {{ seconds }}s...",
+ "Smileys & People": "Smileys & Personen",
"Some of the files will not be accepted": "Einige der Dateien werden nicht akzeptiert",
"Start typing to search": "Tippen Sie, um zu suchen",
"Stop sharing": "Teilen beenden",
"Submit": "Absenden",
"Suggest a new option to add to this poll": "Schlage eine neue Option vor, die zu dieser Umfrage hinzugefügt werden soll",
"Suggest an option": "Eine Option vorschlagen",
+ "Symbols": "Symbole",
"Tap to remove": "Tippen zum Entfernen",
"Tap to remove: {{ reactionName }}": "Tippen zum Entfernen: {{ reactionName }}",
"Thinking...": "Denken...",
@@ -642,6 +665,7 @@
"Translated": "Übersetzt",
"Translated from {{ language }}": "Übersetzung aus {{ language }}",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Reisen & Orte",
"Type a number from 2 to 10": "Geben Sie eine Zahl von 2 bis 10 ein",
"Unarchive": "Archivierung aufheben",
"unban-command-args": "[@Benutzername]",
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 4d2d536dd..3eea668af 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -43,6 +43,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} voted: {{pollOptionText}}",
"📍Shared location": "📍Shared location",
"Actions": "Actions",
+ "Activities": "Activities",
"Add": "Add",
"Add {{ count }} members_one": "Add {{ count }} member",
"Add {{ count }} members_other": "Add {{ count }} members",
@@ -65,6 +66,7 @@
"Also sent in channel": "Also sent in channel",
"An error has occurred during recording": "An error has occurred during recording",
"An error has occurred during the recording processing": "An error has occurred during the recording processing",
+ "Animals & Nature": "Animals & Nature",
"Anonymous": "Anonymous",
"Anonymous poll": "Anonymous Poll",
"Archive": "Archive",
@@ -100,8 +102,12 @@
"aria/Channel Actions": "Channel Actions",
"aria/Channel details": "Channel details",
"aria/Channel list": "Channel list",
+ "aria/Channel search results": "Channel search results",
"aria/Chat view controls": "Chat view controls",
+ "aria/Chat view tabs": "Chat view tabs",
"aria/Chat: {{ channelName }}": "Chat: {{ channelName }}",
+ "aria/Choose default skin tone": "aria/Choose default skin tone",
+ "aria/Clear emoji search": "aria/Clear emoji search",
"aria/Clear search": "Clear search",
"aria/Close callout dialog": "Close callout dialog",
"aria/Close thread": "Close thread",
@@ -270,6 +276,8 @@
"Create a question, add options, and configure poll settings": "Create a question, add options, and configure poll settings",
"Create poll": "Create Poll",
"Current location": "Current location",
+ "Dark": "Dark",
+ "Default": "Default",
"Delete": "Delete",
"Delete chat": "Delete chat",
"Delete for me": "Delete for me",
@@ -340,6 +348,7 @@
"Failed to jump to the first unread message": "Failed to jump to the first unread message",
"Failed to leave channel": "Failed to leave channel",
"Failed to load channels": "Failed to load channels",
+ "Failed to load emojis": "Failed to load emojis",
"Failed to load more channels": "Failed to load more channels",
"Failed to mark channel as read": "Failed to mark channel as read",
"Failed to play the recording": "Failed to play the recording",
@@ -357,6 +366,9 @@
"fileCount_other": "{{ count }} files",
"Files": "Files",
"Flag": "Flag",
+ "Flags": "Flags",
+ "Food & Drink": "Food & Drink",
+ "Frequently used": "Frequently used",
"Generating...": "Generating...",
"giphy-command-args": "[text]",
"giphy-command-description": "Post a random gif to the channel",
@@ -430,6 +442,7 @@
"Leave chat": "Leave chat",
"Left channel": "Left channel",
"Let others add options": "Let Others Add Options",
+ "Light": "Light",
"Limit votes per person": "Limit Votes per Person",
"Link": "Link",
"linkCount_one": "Link",
@@ -448,6 +461,9 @@
"Mark as unread": "Mark as unread",
"Maximum number of votes (from 2 to 10)": "Maximum number of votes (from 2 to 10)",
"Maximum votes per person": "Maximum votes per person",
+ "Medium": "Medium",
+ "Medium-Dark": "Medium-Dark",
+ "Medium-Light": "Medium-Light",
"Member detail": "Member detail",
"mention/Channel": "Channel",
"mention/Channel Description": "Notify everyone in this channel",
@@ -478,6 +494,7 @@
"Next image": "Next image",
"No chats here yet…": "No chats here yet…",
"No conversations yet": "No conversations yet",
+ "No emoji found": "No emoji found",
"No files": "No files",
"No items exist": "No items exist",
"No member found": "No member found",
@@ -489,6 +506,7 @@
"Nobody will be able to vote in this poll anymore.": "Nobody will be able to vote in this poll anymore.",
"Nothing yet...": "Nothing yet...",
"Notify all {{ role }} members": "Notify all {{ role }} members",
+ "Objects": "Objects",
"Offline": "Offline",
"Ok": "Ok",
"Online": "Online",
@@ -508,6 +526,7 @@
"People matching": "People matching",
"Photo": "Photo",
"Photos & videos": "Photos & videos",
+ "Pick an emoji…": "Pick an emoji…",
"Pin": "Pin",
"Pin a message to see it here": "Pin a message to see it here",
"Pinned by {{ name }}": "Pinned by {{ name }}",
@@ -553,6 +572,7 @@
"replyCount_one": "1 reply",
"replyCount_other": "{{ count }} replies",
"Resend": "Resend",
+ "Retry": "Retry",
"Retry upload": "Retry upload",
"Review all options available in this poll": "Review all options available in this poll",
"Review comments submitted with poll answers": "Review comments submitted with poll answers",
@@ -563,6 +583,7 @@
"Save for later": "Save for later",
"Saved for later": "Saved for later",
"Search": "Search",
+ "Search emoji": "Search emoji",
"Search GIFs": "Search GIFs",
"search-results-header-filter-source-button-label--channels": "channels",
"search-results-header-filter-source-button-label--messages": "messages",
@@ -598,12 +619,14 @@
"size limit": "size limit",
"Slow Mode ON": "Slow Mode ON",
"Slow mode, wait {{ seconds }}s...": "Slow mode, wait {{ seconds }}s...",
+ "Smileys & People": "Smileys & People",
"Some of the files will not be accepted": "Some of the files will not be accepted",
"Start typing to search": "Start typing to search",
"Stop sharing": "Stop sharing",
"Submit": "Submit",
"Suggest a new option to add to this poll": "Suggest a new option to add to this poll",
"Suggest an option": "Suggest an Option",
+ "Symbols": "Symbols",
"Tap to remove": "Tap to remove",
"Tap to remove: {{ reactionName }}": "Tap to remove: {{ reactionName }}",
"Thinking...": "Thinking...",
@@ -642,6 +665,7 @@
"Translated": "Translated",
"Translated from {{ language }}": "Translated from {{ language }}",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Travel & Places",
"Type a number from 2 to 10": "Type a number from 2 to 10",
"Unarchive": "Unarchive",
"unban-command-args": "[@username]",
diff --git a/src/i18n/es.json b/src/i18n/es.json
index f0a743d48..3981a33e8 100644
--- a/src/i18n/es.json
+++ b/src/i18n/es.json
@@ -53,6 +53,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} votó: {{pollOptionText}}",
"📍Shared location": "📍Ubicación compartida",
"Actions": "Actions",
+ "Activities": "Actividades",
"Add": "Añadir",
"Add {{ count }} members_one": "Añadir {{ count }} miembro",
"Add {{ count }} members_many": "Añadir {{ count }} miembros",
@@ -76,6 +77,7 @@
"Also sent in channel": "También enviado en el canal",
"An error has occurred during recording": "Se ha producido un error durante la grabación",
"An error has occurred during the recording processing": "Se ha producido un error durante el procesamiento de la grabación",
+ "Animals & Nature": "Animales y naturaleza",
"Anonymous": "Anónimo",
"Anonymous poll": "Encuesta anónima",
"Archive": "Archivo",
@@ -116,8 +118,12 @@
"aria/Channel Actions": "Acciones del canal",
"aria/Channel details": "Detalles del canal",
"aria/Channel list": "Lista de canales",
+ "aria/Channel search results": "Resultados de búsqueda de canales",
"aria/Chat view controls": "Controles de la vista del chat",
+ "aria/Chat view tabs": "Pestañas de vista del chat",
"aria/Chat: {{ channelName }}": "Chat: {{ channelName }}",
+ "aria/Choose default skin tone": "Elegir tono de piel predeterminado",
+ "aria/Clear emoji search": "Borrar búsqueda de emojis",
"aria/Clear search": "Borrar búsqueda",
"aria/Close callout dialog": "Cerrar diálogo de aviso",
"aria/Close thread": "Cerrar hilo",
@@ -287,6 +293,8 @@
"Create a question, add options, and configure poll settings": "Crea una pregunta, añade opciones y configura los ajustes de la encuesta",
"Create poll": "Crear encuesta",
"Current location": "Ubicación actual",
+ "Dark": "Oscuro",
+ "Default": "Predeterminado",
"Delete": "Borrar",
"Delete chat": "Eliminar chat",
"Delete for me": "Eliminar para mí",
@@ -357,6 +365,7 @@
"Failed to jump to the first unread message": "Error al saltar al primer mensaje no leído",
"Failed to leave channel": "No se pudo salir del canal",
"Failed to load channels": "No se pudieron cargar los canales",
+ "Failed to load emojis": "No se pudieron cargar los emojis",
"Failed to load more channels": "No se pudieron cargar más canales",
"Failed to mark channel as read": "Error al marcar el canal como leído",
"Failed to play the recording": "No se pudo reproducir la grabación",
@@ -375,6 +384,9 @@
"fileCount_other": "{{ count }} archivos",
"Files": "Archivos",
"Flag": "Marcar",
+ "Flags": "Banderas",
+ "Food & Drink": "Comida y bebida",
+ "Frequently used": "Usados frecuentemente",
"Generating...": "Generando...",
"giphy-command-args": "[texto]",
"giphy-command-description": "Publicar un gif aleatorio en el canal",
@@ -449,6 +461,7 @@
"Leave chat": "Abandonar canal",
"Left channel": "Canal abandonado",
"Let others add options": "Permitir que otros añadan opciones",
+ "Light": "Claro",
"Limit votes per person": "Limitar votos por persona",
"Link": "Enlace",
"linkCount_one": "Enlace",
@@ -468,6 +481,9 @@
"Mark as unread": "Marcar como no leído",
"Maximum number of votes (from 2 to 10)": "Número máximo de votos (de 2 a 10)",
"Maximum votes per person": "Máximo de votos por persona",
+ "Medium": "Medio",
+ "Medium-Dark": "Medio oscuro",
+ "Medium-Light": "Medio claro",
"Member detail": "Detalle del miembro",
"mention/Channel": "Canal",
"mention/Channel Description": "Notificar a todos en este canal",
@@ -498,6 +514,7 @@
"Next image": "Siguiente imagen",
"No chats here yet…": "Aún no hay mensajes aquí...",
"No conversations yet": "Aún no hay conversaciones",
+ "No emoji found": "No se encontraron emojis",
"No files": "No hay archivos",
"No items exist": "No existen elementos",
"No member found": "No se encontró ningún miembro",
@@ -509,6 +526,7 @@
"Nobody will be able to vote in this poll anymore.": "Nadie podrá votar en esta encuesta.",
"Nothing yet...": "Nada aún...",
"Notify all {{ role }} members": "Notificar a todos los miembros con rol {{ role }}",
+ "Objects": "Objetos",
"Offline": "Desconectado",
"Ok": "Aceptar",
"Online": "En línea",
@@ -528,6 +546,7 @@
"People matching": "Personas que coinciden",
"Photo": "Foto",
"Photos & videos": "Fotos y videos",
+ "Pick an emoji…": "Elige un emoji…",
"Pin": "Fijar",
"Pin a message to see it here": "Fija un mensaje para verlo aquí",
"Pinned by {{ name }}": "Fijado por {{ name }}",
@@ -576,6 +595,7 @@
"replyCount_many": "{{ count }} respuestas",
"replyCount_other": "{{ count }} respuestas",
"Resend": "Reenviar",
+ "Retry": "Reintentar",
"Retry upload": "Reintentar la carga",
"Review all options available in this poll": "Revisa todas las opciones disponibles en esta encuesta",
"Review comments submitted with poll answers": "Revisa los comentarios enviados con las respuestas de la encuesta",
@@ -586,6 +606,7 @@
"Save for later": "Guardar para más tarde",
"Saved for later": "Guardado para más tarde",
"Search": "Buscar",
+ "Search emoji": "Buscar emoji",
"Search GIFs": "Buscar GIFs",
"search-results-header-filter-source-button-label--channels": "canales",
"search-results-header-filter-source-button-label--messages": "mensajes",
@@ -623,12 +644,14 @@
"size limit": "límite de tamaño",
"Slow Mode ON": "Modo lento activado",
"Slow mode, wait {{ seconds }}s...": "Modo lento, espera {{ seconds }} s...",
+ "Smileys & People": "Emoticonos y personas",
"Some of the files will not be accepted": "Algunos archivos no serán aceptados",
"Start typing to search": "Empieza a escribir para buscar",
"Stop sharing": "Dejar de compartir",
"Submit": "Enviar",
"Suggest a new option to add to this poll": "Sugiere una nueva opción para añadir a esta encuesta",
"Suggest an option": "Sugerir una opción",
+ "Symbols": "Símbolos",
"Tap to remove": "Toca para quitar",
"Tap to remove: {{ reactionName }}": "Toca para quitar: {{ reactionName }}",
"Thinking...": "Pensando...",
@@ -669,6 +692,7 @@
"Translated": "Traducido",
"Translated from {{ language }}": "Traducido de {{ language }}",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Viajes y lugares",
"Type a number from 2 to 10": "Escribe un número del 2 al 10",
"Unarchive": "Desarchivar",
"unban-command-args": "[@usuario]",
diff --git a/src/i18n/fr.json b/src/i18n/fr.json
index 838567394..ce5476a7e 100644
--- a/src/i18n/fr.json
+++ b/src/i18n/fr.json
@@ -53,6 +53,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} a voté : {{pollOptionText}}",
"📍Shared location": "📍Emplacement partagé",
"Actions": "Actions",
+ "Activities": "Activités",
"Add": "Ajouter",
"Add {{ count }} members_one": "Ajouter {{ count }} membre",
"Add {{ count }} members_many": "Ajouter {{ count }} membres",
@@ -76,6 +77,7 @@
"Also sent in channel": "Également envoyé dans le canal",
"An error has occurred during recording": "Une erreur s'est produite pendant l'enregistrement",
"An error has occurred during the recording processing": "Une erreur s'est produite pendant le traitement de l'enregistrement",
+ "Animals & Nature": "Animaux et nature",
"Anonymous": "Anonyme",
"Anonymous poll": "Sondage anonyme",
"Archive": "Archiver",
@@ -116,8 +118,12 @@
"aria/Channel Actions": "Actions du canal",
"aria/Channel details": "Détails du canal",
"aria/Channel list": "Liste des canaux",
+ "aria/Channel search results": "Résultats de recherche de canaux",
"aria/Chat view controls": "Commandes de la vue du chat",
+ "aria/Chat view tabs": "Onglets de la vue de chat",
"aria/Chat: {{ channelName }}": "Chat : {{ channelName }}",
+ "aria/Choose default skin tone": "Choisir le teint par défaut",
+ "aria/Clear emoji search": "Effacer la recherche d'emoji",
"aria/Clear search": "Effacer la recherche",
"aria/Close callout dialog": "Fermer la boîte de dialogue d'information",
"aria/Close thread": "Fermer le fil",
@@ -287,6 +293,8 @@
"Create a question, add options, and configure poll settings": "Créez une question, ajoutez des options et configurez les paramètres du sondage",
"Create poll": "Créer un sondage",
"Current location": "Emplacement actuel",
+ "Dark": "Foncé",
+ "Default": "Par défaut",
"Delete": "Supprimer",
"Delete chat": "Supprimer le chat",
"Delete for me": "Supprimer pour moi",
@@ -357,6 +365,7 @@
"Failed to jump to the first unread message": "Échec du saut vers le premier message non lu",
"Failed to leave channel": "Impossible de quitter le canal",
"Failed to load channels": "Impossible de charger les canaux",
+ "Failed to load emojis": "Échec du chargement des emojis",
"Failed to load more channels": "Impossible de charger davantage de canaux",
"Failed to mark channel as read": "Échec du marquage du canal comme lu",
"Failed to play the recording": "Impossible de lire l'enregistrement",
@@ -375,6 +384,9 @@
"fileCount_other": "{{ count }} fichiers",
"Files": "Fichiers",
"Flag": "Signaler",
+ "Flags": "Drapeaux",
+ "Food & Drink": "Nourriture et boissons",
+ "Frequently used": "Fréquemment utilisés",
"Generating...": "Génération...",
"giphy-command-args": "[texte]",
"giphy-command-description": "Poster un GIF aléatoire dans le canal",
@@ -449,6 +461,7 @@
"Leave chat": "Quitter le canal",
"Left channel": "Canal quitté",
"Let others add options": "Permettre à d'autres d'ajouter des options",
+ "Light": "Clair",
"Limit votes per person": "Limiter les votes par personne",
"Link": "Lien",
"linkCount_one": "Lien",
@@ -468,6 +481,9 @@
"Mark as unread": "Marquer comme non lu",
"Maximum number of votes (from 2 to 10)": "Nombre maximum de votes (de 2 à 10)",
"Maximum votes per person": "Nombre maximal de votes par personne",
+ "Medium": "Moyen",
+ "Medium-Dark": "Moyennement foncé",
+ "Medium-Light": "Moyennement clair",
"Member detail": "Détails du membre",
"mention/Channel": "Canal",
"mention/Channel Description": "Notifier tout le monde dans ce canal",
@@ -498,6 +514,7 @@
"Next image": "Image suivante",
"No chats here yet…": "Pas encore de messages ici...",
"No conversations yet": "Aucune conversation pour le moment",
+ "No emoji found": "Aucun emoji trouvé",
"No files": "Aucun fichier",
"No items exist": "Aucun élément",
"No member found": "Aucun membre trouvé",
@@ -509,6 +526,7 @@
"Nobody will be able to vote in this poll anymore.": "Personne ne pourra plus voter dans ce sondage.",
"Nothing yet...": "Rien pour l'instant...",
"Notify all {{ role }} members": "Notifier tous les membres ayant le rôle {{ role }}",
+ "Objects": "Objets",
"Offline": "Hors ligne",
"Ok": "D'accord",
"Online": "En ligne",
@@ -528,6 +546,7 @@
"People matching": "Correspondance de personnes",
"Photo": "Photo",
"Photos & videos": "Photos et vidéos",
+ "Pick an emoji…": "Choisissez un emoji…",
"Pin": "Épingler",
"Pin a message to see it here": "Épinglez un message pour le voir ici",
"Pinned by {{ name }}": "Épinglé par {{ name }}",
@@ -576,6 +595,7 @@
"replyCount_many": "{{ count }} réponses",
"replyCount_other": "{{ count }} réponses",
"Resend": "Renvoyer",
+ "Retry": "Réessayer",
"Retry upload": "Réessayer le téléchargement",
"Review all options available in this poll": "Consultez toutes les options disponibles dans ce sondage",
"Review comments submitted with poll answers": "Consultez les commentaires envoyés avec les réponses au sondage",
@@ -586,6 +606,7 @@
"Save for later": "Enregistrer pour plus tard",
"Saved for later": "Enregistré pour plus tard",
"Search": "Rechercher",
+ "Search emoji": "Rechercher un emoji",
"Search GIFs": "Rechercher des GIFs",
"search-results-header-filter-source-button-label--channels": "canaux",
"search-results-header-filter-source-button-label--messages": "messages",
@@ -623,12 +644,14 @@
"size limit": "limite de taille",
"Slow Mode ON": "Mode lent activé",
"Slow mode, wait {{ seconds }}s...": "Mode lent, attendez {{ seconds }} s...",
+ "Smileys & People": "Émoticônes et personnes",
"Some of the files will not be accepted": "Certains fichiers ne seront pas acceptés",
"Start typing to search": "Commencez à taper pour rechercher",
"Stop sharing": "Arrêter de partager",
"Submit": "Envoyer",
"Suggest a new option to add to this poll": "Suggérez une nouvelle option à ajouter à ce sondage",
"Suggest an option": "Suggérer une option",
+ "Symbols": "Symboles",
"Tap to remove": "Appuyez pour retirer",
"Tap to remove: {{ reactionName }}": "Appuyez pour retirer: {{ reactionName }}",
"Thinking...": "Réflexion...",
@@ -669,6 +692,7 @@
"Translated": "Traduit",
"Translated from {{ language }}": "Traduit du {{ language }}",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Voyages et lieux",
"Type a number from 2 to 10": "Tapez un nombre de 2 à 10",
"Unarchive": "Désarchiver",
"unban-command-args": "[@nomdutilisateur]",
diff --git a/src/i18n/hi.json b/src/i18n/hi.json
index 920881d77..c9e18310d 100644
--- a/src/i18n/hi.json
+++ b/src/i18n/hi.json
@@ -43,6 +43,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} ने वोट दिया: {{pollOptionText}}",
"📍Shared location": "📍साझा किया गया स्थान",
"Actions": "Actions",
+ "Activities": "गतिविधियाँ",
"Add": "जोड़ें",
"Add {{ count }} members_one": "{{ count }} सदस्य जोड़ें",
"Add {{ count }} members_other": "{{ count }} सदस्य जोड़ें",
@@ -65,6 +66,7 @@
"Also sent in channel": "चैनल में भी भेजा गया",
"An error has occurred during recording": "रेकॉर्डिंग के दौरान एक त्रुटि आ गई है",
"An error has occurred during the recording processing": "रेकॉर्डिंग प्रोसेसिंग के दौरान एक त्रुटि आ गई है",
+ "Animals & Nature": "जानवर और प्रकृति",
"Anonymous": "गुमनाम",
"Anonymous poll": "गुमनाम मतदान",
"Archive": "आर्काइव",
@@ -100,8 +102,12 @@
"aria/Channel Actions": "चैनल क्रियाएँ",
"aria/Channel details": "चैनल विवरण",
"aria/Channel list": "चैनल सूची",
+ "aria/Channel search results": "चैनल खोज परिणाम",
"aria/Chat view controls": "चैट व्यू नियंत्रण",
+ "aria/Chat view tabs": "चैट व्यू टैब",
"aria/Chat: {{ channelName }}": "चैट: {{ channelName }}",
+ "aria/Choose default skin tone": "डिफ़ॉल्ट त्वचा टोन चुनें",
+ "aria/Clear emoji search": "इमोजी खोज साफ़ करें",
"aria/Clear search": "खोज साफ़ करें",
"aria/Close callout dialog": "कॉलआउट संवाद बंद करें",
"aria/Close thread": "थ्रेड बंद करें",
@@ -270,6 +276,8 @@
"Create a question, add options, and configure poll settings": "एक प्रश्न बनाएं, विकल्प जोड़ें और पोल सेटिंग्स कॉन्फ़िगर करें",
"Create poll": "मतदान बनाएँ",
"Current location": "वर्तमान स्थान",
+ "Dark": "गहरा",
+ "Default": "डिफ़ॉल्ट",
"Delete": "डिलीट",
"Delete chat": "चैट हटाएं",
"Delete for me": "मेरे लिए डिलीट करें",
@@ -341,6 +349,7 @@
"Failed to jump to the first unread message": "पहले अपठित संदेश पर जाने में विफल",
"Failed to leave channel": "चैनल छोड़ने में विफल",
"Failed to load channels": "चैनल लोड करने में विफल",
+ "Failed to load emojis": "इमोजी लोड नहीं हो सके",
"Failed to load more channels": "और चैनल लोड करने में विफल",
"Failed to mark channel as read": "चैनल को पढ़ा हुआ चिह्नित करने में विफल।",
"Failed to play the recording": "रेकॉर्डिंग प्ले करने में विफल",
@@ -358,6 +367,9 @@
"fileCount_other": "{{ count }} फ़ाइलें",
"Files": "फ़ाइलें",
"Flag": "फ्लैग करे",
+ "Flags": "झंडे",
+ "Food & Drink": "खाना और पेय",
+ "Frequently used": "अक्सर उपयोग किए गए",
"Generating...": "बना रहा है...",
"giphy-command-args": "[पाठ]",
"giphy-command-description": "चैनल पर एक क्रॉफिल जीआइएफ पोस्ट करें",
@@ -431,6 +443,7 @@
"Leave chat": "चैनल छोड़ें",
"Left channel": "चैनल छोड़ दिया गया",
"Let others add options": "दूसरों को विकल्प जोड़ने दें",
+ "Light": "हल्का",
"Limit votes per person": "प्रति व्यक्ति वोट सीमित करें",
"Link": "लिंक",
"linkCount_one": "1 लिंक",
@@ -449,6 +462,9 @@
"Mark as unread": "अपठित चिह्नित करें",
"Maximum number of votes (from 2 to 10)": "अधिकतम वोटों की संख्या (2 से 10)",
"Maximum votes per person": "प्रति व्यक्ति अधिकतम वोट",
+ "Medium": "मध्यम",
+ "Medium-Dark": "मध्यम-गहरा",
+ "Medium-Light": "मध्यम-हल्का",
"Member detail": "सदस्य विवरण",
"mention/Channel": "चैनल",
"mention/Channel Description": "इस चैनल में सभी को सूचित करें",
@@ -479,6 +495,7 @@
"Next image": "अगली छवि",
"No chats here yet…": "यहां अभी तक कोई चैट नहीं...",
"No conversations yet": "अभी तक कोई बातचीत नहीं है",
+ "No emoji found": "कोई इमोजी नहीं मिला",
"No files": "कोई फ़ाइल नहीं",
"No items exist": "कोई आइटम मौजूद नहीं है",
"No member found": "कोई सदस्य नहीं मिला",
@@ -490,6 +507,7 @@
"Nobody will be able to vote in this poll anymore.": "अब कोई भी इस मतदान में मतदान नहीं कर सकेगा।",
"Nothing yet...": "कोई मैसेज नहीं है",
"Notify all {{ role }} members": "{{ role }} भूमिका वाले सभी सदस्यों को सूचित करें",
+ "Objects": "वस्तुएँ",
"Offline": "ऑफलाइन",
"Ok": "ठीक है",
"Online": "ऑनलाइन",
@@ -509,6 +527,7 @@
"People matching": "मेल खाते लोग",
"Photo": "फ़ोटो",
"Photos & videos": "फ़ोटो और वीडियो",
+ "Pick an emoji…": "इमोजी चुनें…",
"Pin": "पिन",
"Pin a message to see it here": "इसे यहाँ देखने के लिए संदेश पिन करें",
"Pinned by {{ name }}": "{{ name }} द्वारा पिन किया गया",
@@ -554,6 +573,7 @@
"replyCount_one": "1 रिप्लाई",
"replyCount_other": "{{ count }} रिप्लाई",
"Resend": "फिर से भेजें",
+ "Retry": "पुनः प्रयास करें",
"Retry upload": "अपलोड फिर से करें",
"Review all options available in this poll": "इस पोल में उपलब्ध सभी विकल्पों की समीक्षा करें",
"Review comments submitted with poll answers": "पोल उत्तरों के साथ भेजी गई टिप्पणियों की समीक्षा करें",
@@ -564,6 +584,7 @@
"Save for later": "बाद के लिए सहेजें",
"Saved for later": "बाद के लिए सहेजा गया",
"Search": "खोज",
+ "Search emoji": "इमोजी खोजें",
"Search GIFs": "GIF खोजें",
"search-results-header-filter-source-button-label--channels": "चैनल्स",
"search-results-header-filter-source-button-label--messages": "संदेश",
@@ -599,12 +620,14 @@
"size limit": "आकार सीमा",
"Slow Mode ON": "स्लो मोड ऑन",
"Slow mode, wait {{ seconds }}s...": "स्लो मोड, {{ seconds }} सेकंड प्रतीक्षा करें...",
+ "Smileys & People": "स्माइली और लोग",
"Some of the files will not be accepted": "कुछ फ़ाइलें स्वीकार नहीं की जाएंगी",
"Start typing to search": "खोजने के लिए टाइप करना शुरू करें",
"Stop sharing": "साझा करना बंद करें",
"Submit": "जमा करें",
"Suggest a new option to add to this poll": "इस पोल में जोड़ने के लिए एक नया विकल्प सुझाएं",
"Suggest an option": "एक विकल्प सुझाव दें",
+ "Symbols": "प्रतीक",
"Tap to remove": "हटाने के लिए टैप करें",
"Tap to remove: {{ reactionName }}": "हटाने के लिए टैप करें: {{ reactionName }}",
"Thinking...": "सोच रहा है...",
@@ -643,6 +666,7 @@
"Translated": "अनुवादित",
"Translated from {{ language }}": "{{ language }} से अनुवादित",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "यात्रा और स्थान",
"Type a number from 2 to 10": "2 से 10 तक का एक नंबर टाइप करें",
"Unarchive": "अनआर्काइव",
"unban-command-args": "[@उपयोगकर्तनाम]",
diff --git a/src/i18n/it.json b/src/i18n/it.json
index 3f23847bf..de794792e 100644
--- a/src/i18n/it.json
+++ b/src/i18n/it.json
@@ -53,6 +53,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} ha votato: {{pollOptionText}}",
"📍Shared location": "📍Posizione condivisa",
"Actions": "Actions",
+ "Activities": "Attività",
"Add": "Aggiungi",
"Add {{ count }} members_one": "Aggiungi {{ count }} membro",
"Add {{ count }} members_many": "Aggiungi {{ count }} membri",
@@ -76,6 +77,7 @@
"Also sent in channel": "Inviato anche nel canale",
"An error has occurred during recording": "Si è verificato un errore durante la registrazione",
"An error has occurred during the recording processing": "Si è verificato un errore durante l'elaborazione della registrazione",
+ "Animals & Nature": "Animali e natura",
"Anonymous": "Anonimo",
"Anonymous poll": "Sondaggio anonimo",
"Archive": "Archivia",
@@ -116,8 +118,12 @@
"aria/Channel Actions": "Azioni canale",
"aria/Channel details": "Dettagli canale",
"aria/Channel list": "Elenco dei canali",
+ "aria/Channel search results": "Risultati della ricerca dei canali",
"aria/Chat view controls": "Controlli visualizzazione chat",
+ "aria/Chat view tabs": "Schede visualizzazione chat",
"aria/Chat: {{ channelName }}": "Chat: {{ channelName }}",
+ "aria/Choose default skin tone": "Scegli la tonalità della pelle predefinita",
+ "aria/Clear emoji search": "Cancella ricerca emoji",
"aria/Clear search": "Cancella ricerca",
"aria/Close callout dialog": "Chiudi finestra informativa",
"aria/Close thread": "Chiudi discussione",
@@ -287,6 +293,8 @@
"Create a question, add options, and configure poll settings": "Crea una domanda, aggiungi opzioni e configura le impostazioni del sondaggio",
"Create poll": "Crea sondaggio",
"Current location": "Posizione attuale",
+ "Dark": "Scuro",
+ "Default": "Predefinito",
"Delete": "Elimina",
"Delete chat": "Elimina chat",
"Delete for me": "Elimina per me",
@@ -357,6 +365,7 @@
"Failed to jump to the first unread message": "Impossibile passare al primo messaggio non letto",
"Failed to leave channel": "Impossibile lasciare il canale",
"Failed to load channels": "Impossibile caricare i canali",
+ "Failed to load emojis": "Impossibile caricare gli emoji",
"Failed to load more channels": "Impossibile caricare altri canali",
"Failed to mark channel as read": "Impossibile contrassegnare il canale come letto",
"Failed to play the recording": "Impossibile riprodurre la registrazione",
@@ -375,6 +384,9 @@
"fileCount_other": "{{ count }} file",
"Files": "File",
"Flag": "Segnala",
+ "Flags": "Bandiere",
+ "Food & Drink": "Cibo e bevande",
+ "Frequently used": "Usati di frequente",
"Generating...": "Generando...",
"giphy-command-args": "[testo]",
"giphy-command-description": "Pubblica un gif casuale sul canale",
@@ -449,6 +461,7 @@
"Leave chat": "Lascia il canale",
"Left channel": "Canale lasciato",
"Let others add options": "Lascia che altri aggiungano opzioni",
+ "Light": "Chiaro",
"Limit votes per person": "Limita i voti per persona",
"Link": "Collegamento",
"linkCount_one": "Link",
@@ -468,6 +481,9 @@
"Mark as unread": "Contrassegna come non letto",
"Maximum number of votes (from 2 to 10)": "Numero massimo di voti (da 2 a 10)",
"Maximum votes per person": "Voti massimi per persona",
+ "Medium": "Medio",
+ "Medium-Dark": "Medio scuro",
+ "Medium-Light": "Medio chiaro",
"Member detail": "Dettagli membro",
"mention/Channel": "Canale",
"mention/Channel Description": "Notifica tutti in questo canale",
@@ -498,6 +514,7 @@
"Next image": "Immagine successiva",
"No chats here yet…": "Non ci sono ancora messaggi qui...",
"No conversations yet": "Ancora nessuna conversazione",
+ "No emoji found": "Nessun emoji trovato",
"No files": "Nessun file",
"No items exist": "Nessun elemento presente",
"No member found": "Nessun membro trovato",
@@ -509,6 +526,7 @@
"Nobody will be able to vote in this poll anymore.": "Nessuno potrà più votare in questo sondaggio.",
"Nothing yet...": "Ancora niente...",
"Notify all {{ role }} members": "Notifica tutti i membri con ruolo {{ role }}",
+ "Objects": "Oggetti",
"Offline": "Offline",
"Ok": "OK",
"Online": "Online",
@@ -528,6 +546,7 @@
"People matching": "Persone che corrispondono",
"Photo": "Foto",
"Photos & videos": "Foto e video",
+ "Pick an emoji…": "Scegli un emoji…",
"Pin": "Appunta",
"Pin a message to see it here": "Appunta un messaggio per vederlo qui",
"Pinned by {{ name }}": "Appuntato da {{ name }}",
@@ -576,6 +595,7 @@
"replyCount_many": "{{ count }} risposte",
"replyCount_other": "{{ count }} risposte",
"Resend": "Invia di nuovo",
+ "Retry": "Riprova",
"Retry upload": "Riprova caricamento",
"Review all options available in this poll": "Rivedi tutte le opzioni disponibili in questo sondaggio",
"Review comments submitted with poll answers": "Rivedi i commenti inviati con le risposte al sondaggio",
@@ -586,6 +606,7 @@
"Save for later": "Salva per dopo",
"Saved for later": "Salvato per dopo",
"Search": "Cerca",
+ "Search emoji": "Cerca emoji",
"Search GIFs": "Cerca GIF",
"search-results-header-filter-source-button-label--channels": "canali",
"search-results-header-filter-source-button-label--messages": "messaggi",
@@ -623,12 +644,14 @@
"size limit": "limite di dimensione",
"Slow Mode ON": "Modalità lenta attivata",
"Slow mode, wait {{ seconds }}s...": "Modalità lenta, attendi {{ seconds }} s...",
+ "Smileys & People": "Faccine e persone",
"Some of the files will not be accepted": "Alcuni dei file non saranno accettati",
"Start typing to search": "Inizia a digitare per cercare",
"Stop sharing": "Ferma condivisione",
"Submit": "Invia",
"Suggest a new option to add to this poll": "Suggerisci una nuova opzione da aggiungere a questo sondaggio",
"Suggest an option": "Suggerisci un'opzione",
+ "Symbols": "Simboli",
"Tap to remove": "Tocca per rimuovere",
"Tap to remove: {{ reactionName }}": "Tocca per rimuovere: {{ reactionName }}",
"Thinking...": "Pensando...",
@@ -669,6 +692,7 @@
"Translated": "Tradotto",
"Translated from {{ language }}": "Tradotto da {{ language }}",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Viaggi e luoghi",
"Type a number from 2 to 10": "Digita un numero da 2 a 10",
"Unarchive": "Ripristina",
"unban-command-args": "[@nomeutente]",
diff --git a/src/i18n/ja.json b/src/i18n/ja.json
index 6770d1e19..c627eec70 100644
--- a/src/i18n/ja.json
+++ b/src/i18n/ja.json
@@ -40,6 +40,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} が投票: {{pollOptionText}}",
"📍Shared location": "📍共有された位置情報",
"Actions": "Actions",
+ "Activities": "アクティビティ",
"Add": "追加",
"Add {{ count }} members_other": "{{ count }}人のメンバーを追加",
"Add a comment": "コメントを追加",
@@ -61,6 +62,7 @@
"Also sent in channel": "チャンネルにも送信済み",
"An error has occurred during recording": "録音中にエラーが発生しました",
"An error has occurred during the recording processing": "録音処理中にエラーが発生しました",
+ "Animals & Nature": "動物と自然",
"Anonymous": "匿名",
"Anonymous poll": "匿名投票",
"Archive": "アーカイブ",
@@ -91,8 +93,12 @@
"aria/Channel Actions": "チャンネル操作",
"aria/Channel details": "チャンネル詳細",
"aria/Channel list": "チャンネル一覧",
+ "aria/Channel search results": "チャンネル検索結果",
"aria/Chat view controls": "チャットビューのコントロール",
+ "aria/Chat view tabs": "チャットビューのタブ",
"aria/Chat: {{ channelName }}": "チャット: {{ channelName }}",
+ "aria/Choose default skin tone": "デフォルトの肌の色を選択",
+ "aria/Clear emoji search": "絵文字検索をクリア",
"aria/Clear search": "検索をクリア",
"aria/Close callout dialog": "吹き出しダイアログを閉じる",
"aria/Close thread": "スレッドを閉じる",
@@ -261,6 +267,8 @@
"Create a question, add options, and configure poll settings": "質問を作成し、選択肢を追加して投票設定を構成",
"Create poll": "投票を作成",
"Current location": "現在の位置",
+ "Dark": "暗い",
+ "Default": "デフォルト",
"Delete": "消去",
"Delete chat": "チャットを削除",
"Delete for me": "自分用に削除",
@@ -331,6 +339,7 @@
"Failed to jump to the first unread message": "最初の未読メッセージにジャンプできませんでした",
"Failed to leave channel": "チャンネルの退出に失敗しました",
"Failed to load channels": "チャンネルの読み込みに失敗しました",
+ "Failed to load emojis": "絵文字を読み込めませんでした",
"Failed to load more channels": "さらにチャンネルを読み込めませんでした",
"Failed to mark channel as read": "チャンネルを既読にすることができませんでした",
"Failed to play the recording": "録音の再生に失敗しました",
@@ -347,6 +356,9 @@
"fileCount_other": "{{ count }}件のファイル",
"Files": "ファイル",
"Flag": "フラグ",
+ "Flags": "旗",
+ "Food & Drink": "食べ物と飲み物",
+ "Frequently used": "よく使う",
"Generating...": "生成中...",
"giphy-command-args": "[テキスト]",
"giphy-command-description": "チャンネルにランダムなGIFを投稿する",
@@ -419,6 +431,7 @@
"Leave chat": "チャンネルを退出",
"Left channel": "チャンネルを退出しました",
"Let others add options": "他の人が選択肢を追加できるようにする",
+ "Light": "明るい",
"Limit votes per person": "1人あたりの投票数を制限する",
"Link": "リンク",
"linkCount_other": "{{ count }}件のリンク",
@@ -436,6 +449,9 @@
"Mark as unread": "未読としてマーク",
"Maximum number of votes (from 2 to 10)": "最大投票数(2から10まで)",
"Maximum votes per person": "1人あたりの最大投票数",
+ "Medium": "普通",
+ "Medium-Dark": "やや暗い",
+ "Medium-Light": "やや明るい",
"Member detail": "メンバー詳細",
"mention/Channel": "チャンネル",
"mention/Channel Description": "このチャンネルの全員に通知",
@@ -466,6 +482,7 @@
"Next image": "次の画像",
"No chats here yet…": "ここにはまだチャットはありません…",
"No conversations yet": "まだ会話はありません",
+ "No emoji found": "絵文字が見つかりません",
"No files": "ファイルはありません",
"No items exist": "項目がありません",
"No member found": "メンバーが見つかりません",
@@ -477,6 +494,7 @@
"Nobody will be able to vote in this poll anymore.": "この投票では、誰も投票できなくなります。",
"Nothing yet...": "まだ何もありません...",
"Notify all {{ role }} members": "{{ role }} メンバー全員に通知",
+ "Objects": "物",
"Offline": "オフライン",
"Ok": "OK",
"Online": "オンライン",
@@ -496,6 +514,7 @@
"People matching": "一致する人",
"Photo": "写真",
"Photos & videos": "写真と動画",
+ "Pick an emoji…": "絵文字を選択…",
"Pin": "ピン",
"Pin a message to see it here": "ここに表示するにはメッセージをピン留めしてください",
"Pinned by {{ name }}": "{{ name }}がピンしました",
@@ -539,6 +558,7 @@
"replyCount_one": "1件の返信",
"replyCount_other": "{{ count }} 返信",
"Resend": "再送信",
+ "Retry": "再試行",
"Retry upload": "アップロードを再試行",
"Review all options available in this poll": "この投票で利用可能なすべての選択肢を確認",
"Review comments submitted with poll answers": "投票回答とともに送信されたコメントを確認",
@@ -549,6 +569,7 @@
"Save for later": "後で保存",
"Saved for later": "後で保存済み",
"Search": "探す",
+ "Search emoji": "絵文字を検索",
"Search GIFs": "GIFを検索",
"search-results-header-filter-source-button-label--channels": "チャンネル",
"search-results-header-filter-source-button-label--messages": "メッセージ",
@@ -584,12 +605,14 @@
"size limit": "サイズ制限",
"Slow Mode ON": "スローモードオン",
"Slow mode, wait {{ seconds }}s...": "スローモード、{{ seconds }}秒お待ちください...",
+ "Smileys & People": "スマイリーと人々",
"Some of the files will not be accepted": "一部のファイルは受け付けられません",
"Start typing to search": "検索するには入力を開始してください",
"Stop sharing": "共有を停止",
"Submit": "送信",
"Suggest a new option to add to this poll": "この投票に追加する新しい選択肢を提案",
"Suggest an option": "オプションを提案",
+ "Symbols": "記号",
"Tap to remove": "タップして削除",
"Tap to remove: {{ reactionName }}": "タップして削除: {{ reactionName }}",
"Thinking...": "考え中...",
@@ -626,6 +649,7 @@
"Translated": "翻訳済み",
"Translated from {{ language }}": "{{ language }}から翻訳",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "旅行と場所",
"Type a number from 2 to 10": "2から10までの数字を入力してください",
"Unarchive": "アーカイブ解除",
"unban-command-args": "[@ユーザ名]",
diff --git a/src/i18n/ko.json b/src/i18n/ko.json
index 85159367b..a4f1230ea 100644
--- a/src/i18n/ko.json
+++ b/src/i18n/ko.json
@@ -40,6 +40,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}}이(가) 투표함: {{pollOptionText}}",
"📍Shared location": "📍공유된 위치",
"Actions": "Actions",
+ "Activities": "활동",
"Add": "추가",
"Add {{ count }} members_other": "{{ count }}명 멤버 추가",
"Add a comment": "댓글 추가",
@@ -61,6 +62,7 @@
"Also sent in channel": "채널에도 전송됨",
"An error has occurred during recording": "녹음 중 오류가 발생했습니다",
"An error has occurred during the recording processing": "녹음 처리 중 오류가 발생했습니다",
+ "Animals & Nature": "동물 & 자연",
"Anonymous": "익명",
"Anonymous poll": "익명 투표",
"Archive": "아카이브",
@@ -91,8 +93,12 @@
"aria/Channel Actions": "채널 작업",
"aria/Channel details": "채널 세부 정보",
"aria/Channel list": "채널 목록",
+ "aria/Channel search results": "채널 검색 결과",
"aria/Chat view controls": "채팅 보기 컨트롤",
+ "aria/Chat view tabs": "채팅 보기 탭",
"aria/Chat: {{ channelName }}": "채팅: {{ channelName }}",
+ "aria/Choose default skin tone": "기본 피부색 선택",
+ "aria/Clear emoji search": "이모지 검색 지우기",
"aria/Clear search": "검색 지우기",
"aria/Close callout dialog": "콜아웃 대화 상자 닫기",
"aria/Close thread": "스레드 닫기",
@@ -261,6 +267,8 @@
"Create a question, add options, and configure poll settings": "질문을 만들고 옵션을 추가한 뒤 투표 설정 구성",
"Create poll": "투표 생성",
"Current location": "현재 위치",
+ "Dark": "어두움",
+ "Default": "기본",
"Delete": "삭제",
"Delete chat": "채팅 삭제",
"Delete for me": "나만 삭제",
@@ -331,6 +339,7 @@
"Failed to jump to the first unread message": "첫 번째 읽지 않은 메시지로 이동하지 못했습니다",
"Failed to leave channel": "채널 나가기에 실패했습니다",
"Failed to load channels": "채널을 불러오지 못했습니다",
+ "Failed to load emojis": "이모지를 불러오지 못했습니다",
"Failed to load more channels": "채널을 더 불러오지 못했습니다",
"Failed to mark channel as read": "채널을 읽음으로 표시하는 데 실패했습니다",
"Failed to play the recording": "녹음을 재생하지 못했습니다",
@@ -347,6 +356,9 @@
"fileCount_other": "파일 {{ count }}개",
"Files": "파일",
"Flag": "플래그",
+ "Flags": "깃발",
+ "Food & Drink": "음식 & 음료",
+ "Frequently used": "자주 사용함",
"Generating...": "생성 중...",
"giphy-command-args": "[텍스트]",
"giphy-command-description": "채널에 무작위 GIF 게시",
@@ -419,6 +431,7 @@
"Leave chat": "채널 나가기",
"Left channel": "채널을 나갔습니다",
"Let others add options": "다른 사람이 선택지를 추가할 수 있도록 허용",
+ "Light": "밝음",
"Limit votes per person": "1인당 투표 수 제한",
"Link": "링크",
"linkCount_other": "링크 {{ count }}개",
@@ -436,6 +449,9 @@
"Mark as unread": "읽지 않음으로 표시",
"Maximum number of votes (from 2 to 10)": "최대 투표 수 (2에서 10까지)",
"Maximum votes per person": "1인당 최대 투표 수",
+ "Medium": "중간",
+ "Medium-Dark": "중간 어두움",
+ "Medium-Light": "중간 밝음",
"Member detail": "멤버 상세 정보",
"mention/Channel": "채널",
"mention/Channel Description": "이 채널의 모두에게 알림",
@@ -466,6 +482,7 @@
"Next image": "다음 이미지",
"No chats here yet…": "아직 채팅이 없습니다...",
"No conversations yet": "아직 대화가 없습니다.",
+ "No emoji found": "이모지를 찾을 수 없습니다",
"No files": "파일이 없습니다",
"No items exist": "항목이 없습니다.",
"No member found": "멤버를 찾을 수 없습니다",
@@ -477,6 +494,7 @@
"Nobody will be able to vote in this poll anymore.": "이 투표에 더 이상 아무도 투표할 수 없습니다.",
"Nothing yet...": "아직 아무것도...",
"Notify all {{ role }} members": "{{ role }} 역할의 모든 멤버에게 알림",
+ "Objects": "사물",
"Offline": "오프라인",
"Ok": "확인",
"Online": "온라인",
@@ -496,6 +514,7 @@
"People matching": "일치하는 사람",
"Photo": "사진",
"Photos & videos": "사진 및 동영상",
+ "Pick an emoji…": "이모지 선택…",
"Pin": "핀",
"Pin a message to see it here": "여기에서 보려면 메시지를 고정하세요",
"Pinned by {{ name }}": "{{ name }}님이 핀함",
@@ -539,6 +558,7 @@
"replyCount_one": "답장 1개",
"replyCount_other": "{{ count }} 답장",
"Resend": "다시 보내기",
+ "Retry": "다시 시도",
"Retry upload": "업로드 다시 시도",
"Review all options available in this poll": "이 투표에서 사용 가능한 모든 옵션 검토",
"Review comments submitted with poll answers": "투표 답변과 함께 제출된 댓글 검토",
@@ -549,6 +569,7 @@
"Save for later": "나중에 저장",
"Saved for later": "나중에 저장됨",
"Search": "찾다",
+ "Search emoji": "이모지 검색",
"Search GIFs": "GIF 검색",
"search-results-header-filter-source-button-label--channels": "채널",
"search-results-header-filter-source-button-label--messages": "메시지",
@@ -584,12 +605,14 @@
"size limit": "크기 제한",
"Slow Mode ON": "슬로우 모드 켜짐",
"Slow mode, wait {{ seconds }}s...": "슬로우 모드, {{ seconds }}초 기다려 주세요...",
+ "Smileys & People": "스마일리 & 사람",
"Some of the files will not be accepted": "일부 파일은 허용되지 않을 수 있습니다",
"Start typing to search": "검색하려면 입력을 시작하세요",
"Stop sharing": "공유 중지",
"Submit": "제출",
"Suggest a new option to add to this poll": "이 투표에 추가할 새 옵션 제안",
"Suggest an option": "옵션 제안",
+ "Symbols": "기호",
"Tap to remove": "제거하려면 탭하세요",
"Tap to remove: {{ reactionName }}": "제거하려면 탭하세요: {{ reactionName }}",
"Thinking...": "생각 중...",
@@ -626,6 +649,7 @@
"Translated": "번역됨",
"Translated from {{ language }}": "{{ language }}(으)로 번역됨",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "여행 & 장소",
"Type a number from 2 to 10": "2에서 10 사이의 숫자를 입력하세요",
"Unarchive": "아카이브 해제",
"unban-command-args": "[@사용자이름]",
diff --git a/src/i18n/nl.json b/src/i18n/nl.json
index f83f5ad22..97ff04548 100644
--- a/src/i18n/nl.json
+++ b/src/i18n/nl.json
@@ -43,6 +43,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} heeft gestemd: {{pollOptionText}}",
"📍Shared location": "📍Gedeelde locatie",
"Actions": "Actions",
+ "Activities": "Activiteiten",
"Add": "Toevoegen",
"Add {{ count }} members_one": "{{ count }} lid toevoegen",
"Add {{ count }} members_other": "{{ count }} leden toevoegen",
@@ -65,6 +66,7 @@
"Also sent in channel": "Ook in kanaal verzonden",
"An error has occurred during recording": "Er is een fout opgetreden tijdens het opnemen",
"An error has occurred during the recording processing": "Er is een fout opgetreden tijdens de verwerking van de opname",
+ "Animals & Nature": "Dieren en natuur",
"Anonymous": "Anoniem",
"Anonymous poll": "Anonieme peiling",
"Archive": "Archief",
@@ -100,8 +102,12 @@
"aria/Channel Actions": "Kanaalacties",
"aria/Channel details": "Kanaaldetails",
"aria/Channel list": "Kanaallijst",
+ "aria/Channel search results": "Zoekresultaten voor kanalen",
"aria/Chat view controls": "Bedieningselementen chatweergave",
+ "aria/Chat view tabs": "Tabbladen chatweergave",
"aria/Chat: {{ channelName }}": "Chat: {{ channelName }}",
+ "aria/Choose default skin tone": "Standaard huidskleur kiezen",
+ "aria/Clear emoji search": "Emoji zoekopdracht wissen",
"aria/Clear search": "Zoekopdracht wissen",
"aria/Close callout dialog": "Calloutdialoog sluiten",
"aria/Close thread": "Draad sluiten",
@@ -270,6 +276,8 @@
"Create a question, add options, and configure poll settings": "Maak een vraag, voeg opties toe en stel de pollinstellingen in",
"Create poll": "Maak peiling",
"Current location": "Huidige locatie",
+ "Dark": "Donker",
+ "Default": "Standaard",
"Delete": "Verwijder",
"Delete chat": "Chat verwijderen",
"Delete for me": "Voor mij verwijderen",
@@ -340,6 +348,7 @@
"Failed to jump to the first unread message": "Niet gelukt om naar het eerste ongelezen bericht te springen",
"Failed to leave channel": "Kanaal verlaten mislukt",
"Failed to load channels": "Kanalen konden niet worden geladen",
+ "Failed to load emojis": "Emoji's konden niet worden geladen",
"Failed to load more channels": "Meer kanalen konden niet worden geladen",
"Failed to mark channel as read": "Kanaal kon niet als gelezen worden gemarkeerd",
"Failed to play the recording": "Kan de opname niet afspelen",
@@ -357,6 +366,9 @@
"fileCount_other": "{{ count }} bestanden",
"Files": "Bestanden",
"Flag": "Markeer",
+ "Flags": "Vlaggen",
+ "Food & Drink": "Eten en drinken",
+ "Frequently used": "Veelgebruikt",
"Generating...": "Genereren...",
"giphy-command-args": "[tekst]",
"giphy-command-description": "Plaats een willekeurige gif in het kanaal",
@@ -430,6 +442,7 @@
"Leave chat": "Kanaal verlaten",
"Left channel": "Kanaal verlaten",
"Let others add options": "Laat anderen opties toevoegen",
+ "Light": "Licht",
"Limit votes per person": "Stemmen per persoon beperken",
"Link": "Link",
"linkCount_one": "Link",
@@ -448,6 +461,9 @@
"Mark as unread": "Markeren als ongelezen",
"Maximum number of votes (from 2 to 10)": "Maximaal aantal stemmen (van 2 tot 10)",
"Maximum votes per person": "Maximum aantal stemmen per persoon",
+ "Medium": "Middel",
+ "Medium-Dark": "Middeldonker",
+ "Medium-Light": "Middellicht",
"Member detail": "Lidgegevens",
"mention/Channel": "Kanaal",
"mention/Channel Description": "Iedereen in dit kanaal informeren",
@@ -478,6 +494,7 @@
"Next image": "Volgende afbeelding",
"No chats here yet…": "Nog geen chats hier...",
"No conversations yet": "Nog geen gesprekken",
+ "No emoji found": "Geen emoji gevonden",
"No files": "Geen bestanden",
"No items exist": "Er zijn geen items",
"No member found": "Geen lid gevonden",
@@ -489,6 +506,7 @@
"Nobody will be able to vote in this poll anymore.": "Niemand kan meer stemmen in deze peiling.",
"Nothing yet...": "Nog niets ...",
"Notify all {{ role }} members": "Alle leden met rol {{ role }} informeren",
+ "Objects": "Objecten",
"Offline": "Offline",
"Ok": "Oké",
"Online": "Online",
@@ -508,6 +526,7 @@
"People matching": "Mensen die matchen",
"Photo": "Foto",
"Photos & videos": "Foto's en video's",
+ "Pick an emoji…": "Kies een emoji…",
"Pin": "Vastmaken",
"Pin a message to see it here": "Maak een bericht vast om het hier te zien",
"Pinned by {{ name }}": "Vastgemaakt door {{ name }}",
@@ -553,6 +572,7 @@
"replyCount_one": "1 antwoord",
"replyCount_other": "{{ count }} antwoorden",
"Resend": "Opnieuw verzenden",
+ "Retry": "Opnieuw proberen",
"Retry upload": "Upload opnieuw proberen",
"Review all options available in this poll": "Bekijk alle beschikbare opties in deze poll",
"Review comments submitted with poll answers": "Bekijk reacties die met pollantwoorden zijn ingediend",
@@ -563,6 +583,7 @@
"Save for later": "Bewaren voor later",
"Saved for later": "Bewaard voor later",
"Search": "Zoeken",
+ "Search emoji": "Emoji zoeken",
"Search GIFs": "GIF's zoeken",
"search-results-header-filter-source-button-label--channels": "kanalen",
"search-results-header-filter-source-button-label--messages": "berichten",
@@ -600,12 +621,14 @@
"Slow mode, wait {{ seconds }}s...": "Langzame modus, wacht {{ seconds }}s...",
"Slow wait, wait {{ seconds }}s": "Langzame modus, wacht {{ seconds }}s",
"Slow wait, wait {{ seconds }}s...": "Langzame modus, wacht {{ seconds }}s...",
+ "Smileys & People": "Smileys en mensen",
"Some of the files will not be accepted": "Sommige bestanden zullen niet worden geaccepteerd",
"Start typing to search": "Begin met typen om te zoeken",
"Stop sharing": "Delen stoppen",
"Submit": "Versturen",
"Suggest a new option to add to this poll": "Stel een nieuwe optie voor om aan deze poll toe te voegen",
"Suggest an option": "Stel een optie voor",
+ "Symbols": "Symbolen",
"Tap to remove": "Tik om te verwijderen",
"Tap to remove: {{ reactionName }}": "Tik om te verwijderen: {{ reactionName }}",
"Thinking...": "Denken...",
@@ -644,6 +667,7 @@
"Translated": "Vertaald",
"Translated from {{ language }}": "Vertaald uit {{ language }}",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Reizen en plaatsen",
"Type a number from 2 to 10": "Typ een getal van 2 tot 10",
"Unarchive": "Uit archief halen",
"unban-command-args": "[@gebruikersnaam]",
diff --git a/src/i18n/pt.json b/src/i18n/pt.json
index 5cff8a41a..e1803f46c 100644
--- a/src/i18n/pt.json
+++ b/src/i18n/pt.json
@@ -53,6 +53,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} votou: {{pollOptionText}}",
"📍Shared location": "📍Localização compartilhada",
"Actions": "Actions",
+ "Activities": "Atividades",
"Add": "Adicionar",
"Add {{ count }} members_one": "Adicionar {{ count }} membro",
"Add {{ count }} members_many": "Adicionar {{ count }} membros",
@@ -76,6 +77,7 @@
"Also sent in channel": "Também enviado no canal",
"An error has occurred during recording": "Ocorreu um erro durante a gravação",
"An error has occurred during the recording processing": "Ocorreu um erro durante o processamento da gravação",
+ "Animals & Nature": "Animais e natureza",
"Anonymous": "Anônimo",
"Anonymous poll": "Enquete anônima",
"Archive": "Arquivar",
@@ -116,8 +118,12 @@
"aria/Channel Actions": "Ações do canal",
"aria/Channel details": "Detalhes do canal",
"aria/Channel list": "Lista de canais",
+ "aria/Channel search results": "Resultados de pesquisa de canais",
"aria/Chat view controls": "Controles da visualização do chat",
+ "aria/Chat view tabs": "Abas da visualização do chat",
"aria/Chat: {{ channelName }}": "Chat: {{ channelName }}",
+ "aria/Choose default skin tone": "Escolher tom de pele padrão",
+ "aria/Clear emoji search": "Limpar pesquisa de emoji",
"aria/Clear search": "Limpar pesquisa",
"aria/Close callout dialog": "Fechar diálogo de destaque",
"aria/Close thread": "Fechar tópico",
@@ -287,6 +293,8 @@
"Create a question, add options, and configure poll settings": "Crie uma pergunta, adicione opções e configure as definições da enquete",
"Create poll": "Criar enquete",
"Current location": "Localização atual",
+ "Dark": "Escuro",
+ "Default": "Padrão",
"Delete": "Excluir",
"Delete chat": "Excluir chat",
"Delete for me": "Excluir para mim",
@@ -357,6 +365,7 @@
"Failed to jump to the first unread message": "Falha ao pular para a primeira mensagem não lida",
"Failed to leave channel": "Falha ao sair do canal",
"Failed to load channels": "Falha ao carregar os canais",
+ "Failed to load emojis": "Falha ao carregar os emojis",
"Failed to load more channels": "Falha ao carregar mais canais",
"Failed to mark channel as read": "Falha ao marcar o canal como lido",
"Failed to play the recording": "Falha ao reproduzir a gravação",
@@ -375,6 +384,9 @@
"fileCount_other": "{{ count }} arquivos",
"Files": "Arquivos",
"Flag": "Reportar",
+ "Flags": "Bandeiras",
+ "Food & Drink": "Comida e bebida",
+ "Frequently used": "Usados com frequência",
"Generating...": "Gerando...",
"giphy-command-args": "[texto]",
"giphy-command-description": "Postar um gif aleatório no canal",
@@ -449,6 +461,7 @@
"Leave chat": "Sair do canal",
"Left channel": "Canal abandonado",
"Let others add options": "Permitir que outros adicionem opções",
+ "Light": "Claro",
"Limit votes per person": "Limitar votos por pessoa",
"Link": "Link",
"linkCount_one": "Link",
@@ -468,6 +481,9 @@
"Mark as unread": "Marcar como não lida",
"Maximum number of votes (from 2 to 10)": "Número máximo de votos (de 2 a 10)",
"Maximum votes per person": "Máximo de votos por pessoa",
+ "Medium": "Médio",
+ "Medium-Dark": "Médio escuro",
+ "Medium-Light": "Médio claro",
"Member detail": "Detalhes do membro",
"mention/Channel": "Canal",
"mention/Channel Description": "Notificar todos neste canal",
@@ -498,6 +514,7 @@
"Next image": "Próxima imagem",
"No chats here yet…": "Ainda não há conversas aqui...",
"No conversations yet": "Ainda não há conversas",
+ "No emoji found": "Nenhum emoji encontrado",
"No files": "Nenhum arquivo",
"No items exist": "Não existem itens",
"No member found": "Nenhum membro encontrado",
@@ -509,6 +526,7 @@
"Nobody will be able to vote in this poll anymore.": "Ninguém mais poderá votar nesta pesquisa.",
"Nothing yet...": "Nada ainda...",
"Notify all {{ role }} members": "Notificar todos os membros com a função {{ role }}",
+ "Objects": "Objetos",
"Offline": "Offline",
"Ok": "OK",
"Online": "Online",
@@ -528,6 +546,7 @@
"People matching": "Pessoas correspondentes",
"Photo": "Foto",
"Photos & videos": "Fotos e vídeos",
+ "Pick an emoji…": "Escolha um emoji…",
"Pin": "Fixar",
"Pin a message to see it here": "Fixe uma mensagem para vê-la aqui",
"Pinned by {{ name }}": "Fixado por {{ name }}",
@@ -576,6 +595,7 @@
"replyCount_many": "{{ count }} respostas",
"replyCount_other": "{{ count }} respostas",
"Resend": "Reenviar",
+ "Retry": "Tentar novamente",
"Retry upload": "Tentar enviar novamente",
"Review all options available in this poll": "Revise todas as opções disponíveis nesta enquete",
"Review comments submitted with poll answers": "Revise comentários enviados com respostas da enquete",
@@ -586,6 +606,7 @@
"Save for later": "Salvar para depois",
"Saved for later": "Salvo para depois",
"Search": "Buscar",
+ "Search emoji": "Pesquisar emoji",
"Search GIFs": "Pesquisar GIFs",
"search-results-header-filter-source-button-label--channels": "canais",
"search-results-header-filter-source-button-label--messages": "mensagens",
@@ -623,12 +644,14 @@
"size limit": "limite de tamanho",
"Slow Mode ON": "Modo lento LIGADO",
"Slow mode, wait {{ seconds }}s...": "Modo lento, aguarde {{ seconds }} s...",
+ "Smileys & People": "Smileys e pessoas",
"Some of the files will not be accepted": "Alguns arquivos não serão aceitos",
"Start typing to search": "Comece a digitar para pesquisar",
"Stop sharing": "Parar de compartilhar",
"Submit": "Enviar",
"Suggest a new option to add to this poll": "Sugira uma nova opção para adicionar a esta enquete",
"Suggest an option": "Sugerir uma opção",
+ "Symbols": "Símbolos",
"Tap to remove": "Toque para remover",
"Tap to remove: {{ reactionName }}": "Toque para remover: {{ reactionName }}",
"Thinking...": "Pensando...",
@@ -669,6 +692,7 @@
"Translated": "Traduzido",
"Translated from {{ language }}": "Traduzido de {{ language }}",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Viagens e lugares",
"Type a number from 2 to 10": "Digite um número de 2 a 10",
"Unarchive": "Desarquivar",
"unban-command-args": "[@nomedeusuário]",
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index f13f1c58f..8f76b9a8a 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -64,6 +64,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} проголосовал(а): {{pollOptionText}}",
"📍Shared location": "📍Общее местоположение",
"Actions": "Actions",
+ "Activities": "Активности",
"Add": "Добавить",
"Add {{ count }} members_one": "Добавить {{ count }} участника",
"Add {{ count }} members_few": "Добавить {{ count }} участников",
@@ -88,6 +89,7 @@
"Also sent in channel": "Также отправлено в канал",
"An error has occurred during recording": "Произошла ошибка во время записи",
"An error has occurred during the recording processing": "Произошла ошибка во время обработки записи",
+ "Animals & Nature": "Животные и природа",
"Anonymous": "Аноним",
"Anonymous poll": "Анонимный опрос",
"Archive": "Aрхивировать",
@@ -133,8 +135,12 @@
"aria/Channel Actions": "Действия канала",
"aria/Channel details": "Сведения о канале",
"aria/Channel list": "Список каналов",
+ "aria/Channel search results": "Результаты поиска по каналам",
"aria/Chat view controls": "Элементы управления видом чата",
+ "aria/Chat view tabs": "Вкладки вида чата",
"aria/Chat: {{ channelName }}": "Чат: {{ channelName }}",
+ "aria/Choose default skin tone": "Выбрать тон кожи по умолчанию",
+ "aria/Clear emoji search": "Очистить поиск эмодзи",
"aria/Clear search": "Очистить поиск",
"aria/Close callout dialog": "Закрыть диалог выноски",
"aria/Close thread": "Закрыть тему",
@@ -305,6 +311,8 @@
"Create a question, add options, and configure poll settings": "Создайте вопрос, добавьте варианты и настройте параметры опроса",
"Create poll": "Создать опрос",
"Current location": "Текущее местоположение",
+ "Dark": "Тёмный",
+ "Default": "По умолчанию",
"Delete": "Удалить",
"Delete chat": "Удалить чат",
"Delete for me": "Удалить для меня",
@@ -375,6 +383,7 @@
"Failed to jump to the first unread message": "Не удалось перейти к первому непрочитанному сообщению",
"Failed to leave channel": "Не удалось покинуть канал",
"Failed to load channels": "Не удалось загрузить каналы",
+ "Failed to load emojis": "Не удалось загрузить эмодзи",
"Failed to load more channels": "Не удалось загрузить больше каналов",
"Failed to mark channel as read": "Не удалось пометить канал как прочитанный",
"Failed to play the recording": "Не удалось воспроизвести запись",
@@ -397,6 +406,9 @@
"fileCount_three": "{{ count }} файла",
"Files": "Файлы",
"Flag": "Пожаловаться",
+ "Flags": "Флаги",
+ "Food & Drink": "Еда и напитки",
+ "Frequently used": "Часто используемые",
"Generating...": "Генерирую...",
"giphy-command-args": "[текст]",
"giphy-command-description": "Опубликовать случайную GIF-анимацию в канале",
@@ -472,6 +484,7 @@
"Leave chat": "Покинуть канал",
"Left channel": "Канал покинут",
"Let others add options": "Разрешить другим добавлять варианты",
+ "Light": "Светлый",
"Limit votes per person": "Ограничить голоса на человека",
"Link": "Линк",
"linkCount_one": "{{ count }} линк",
@@ -492,6 +505,9 @@
"Mark as unread": "Отметить как непрочитанное",
"Maximum number of votes (from 2 to 10)": "Максимальное количество голосов (от 2 до 10)",
"Maximum votes per person": "Максимум голосов на человека",
+ "Medium": "Средний",
+ "Medium-Dark": "Умеренно-тёмный",
+ "Medium-Light": "Умеренно-светлый",
"Member detail": "Сведения об участнике",
"mention/Channel": "Канал",
"mention/Channel Description": "Уведомить всех в этом канале",
@@ -522,6 +538,7 @@
"Next image": "Следующее изображение",
"No chats here yet…": "Здесь еще нет чатов...",
"No conversations yet": "Пока нет бесед",
+ "No emoji found": "Эмодзи не найдены",
"No files": "Нет файлов",
"No items exist": "Элементов нет",
"No member found": "Участник не найден",
@@ -533,6 +550,7 @@
"Nobody will be able to vote in this poll anymore.": "Никто больше не сможет голосовать в этом опросе.",
"Nothing yet...": "Пока ничего нет...",
"Notify all {{ role }} members": "Уведомить всех участников с ролью {{ role }}",
+ "Objects": "Объекты",
"Offline": "Не в сети",
"Ok": "Ок",
"Online": "В сети",
@@ -552,6 +570,7 @@
"People matching": "Совпадающие люди",
"Photo": "Фото",
"Photos & videos": "Фото и видео",
+ "Pick an emoji…": "Выберите эмодзи…",
"Pin": "Закрепить",
"Pin a message to see it here": "Закрепите сообщение, чтобы увидеть его здесь",
"Pinned by {{ name }}": "Закреплено: {{ name }}",
@@ -603,6 +622,7 @@
"replyCount_many": "{{ count }} ответов",
"replyCount_other": "{{ count }} ответов",
"Resend": "Отправить повторно",
+ "Retry": "Повторить",
"Retry upload": "Повторить загрузку",
"Review all options available in this poll": "Просмотрите все варианты, доступные в этом опросе",
"Review comments submitted with poll answers": "Просмотрите комментарии, отправленные вместе с ответами в опросе",
@@ -613,6 +633,7 @@
"Save for later": "Сохранить на потом",
"Saved for later": "Сохранено на потом",
"Search": "Поиск",
+ "Search emoji": "Поиск эмодзи",
"Search GIFs": "Поиск GIF",
"search-results-header-filter-source-button-label--channels": "каналы",
"search-results-header-filter-source-button-label--messages": "сообщения",
@@ -652,12 +673,14 @@
"size limit": "ограничение размера",
"Slow Mode ON": "Медленный режим включен",
"Slow mode, wait {{ seconds }}s...": "Медленный режим: подождите {{ seconds }} с...",
+ "Smileys & People": "Смайлики и люди",
"Some of the files will not be accepted": "Некоторые файлы не будут приняты",
"Start typing to search": "Начните вводить для поиска",
"Stop sharing": "Прекратить делиться",
"Submit": "Отправить",
"Suggest a new option to add to this poll": "Предложите новый вариант для добавления в этот опрос",
"Suggest an option": "Предложить вариант",
+ "Symbols": "Символы",
"Tap to remove": "Нажмите, чтобы удалить",
"Tap to remove: {{ reactionName }}": "Нажмите, чтобы удалить: {{ reactionName }}",
"Thinking...": "Думаю...",
@@ -700,6 +723,7 @@
"Translated": "Переведено",
"Translated from {{ language }}": "Переведено с {{ language }}",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Путешествия и места",
"Type a number from 2 to 10": "Введите число от 2 до 10",
"Unarchive": "Удалить из архива",
"unban-command-args": "[@имяпользователя]",
diff --git a/src/i18n/tr.json b/src/i18n/tr.json
index 962b95ad4..46b53593c 100644
--- a/src/i18n/tr.json
+++ b/src/i18n/tr.json
@@ -43,6 +43,7 @@
"📊 {{votedBy}} voted: {{pollOptionText}}": "📊 {{votedBy}} oy verdi: {{pollOptionText}}",
"📍Shared location": "📍Paylaşılan konum",
"Actions": "Actions",
+ "Activities": "Etkinlikler",
"Add": "Ekle",
"Add {{ count }} members_one": "{{ count }} üye ekle",
"Add {{ count }} members_other": "{{ count }} üye ekle",
@@ -65,6 +66,7 @@
"Also sent in channel": "Kanala da gönderildi",
"An error has occurred during recording": "Kayıt sırasında bir hata oluştu",
"An error has occurred during the recording processing": "Kayıt işlemi sırasında bir hata oluştu",
+ "Animals & Nature": "Hayvanlar ve Doğa",
"Anonymous": "Anonim",
"Anonymous poll": "Anonim anket",
"Archive": "Arşivle",
@@ -100,8 +102,12 @@
"aria/Channel Actions": "Kanal işlemleri",
"aria/Channel details": "Kanal ayrıntıları",
"aria/Channel list": "Kanal listesi",
+ "aria/Channel search results": "Kanal arama sonuçları",
"aria/Chat view controls": "Sohbet görünümü kontrolleri",
+ "aria/Chat view tabs": "Sohbet görünümü sekmeleri",
"aria/Chat: {{ channelName }}": "Sohbet: {{ channelName }}",
+ "aria/Choose default skin tone": "Varsayılan ten rengini seç",
+ "aria/Clear emoji search": "Emoji aramasını temizle",
"aria/Clear search": "Aramayı temizle",
"aria/Close callout dialog": "Bilgi balonu iletişim kutusunu kapat",
"aria/Close thread": "Konuyu kapat",
@@ -270,6 +276,8 @@
"Create a question, add options, and configure poll settings": "Bir soru oluşturun, seçenekler ekleyin ve anket ayarlarını yapılandırın",
"Create poll": "Anket oluştur",
"Current location": "Mevcut konum",
+ "Dark": "Koyu",
+ "Default": "Varsayılan",
"Delete": "Sil",
"Delete chat": "Sohbeti sil",
"Delete for me": "Benim için sil",
@@ -340,6 +348,7 @@
"Failed to jump to the first unread message": "İlk okunmamış mesaja atlamada hata oluştu",
"Failed to leave channel": "Kanaldan çıkılamadı",
"Failed to load channels": "Kanallar yüklenemedi",
+ "Failed to load emojis": "Emojiler yüklenemedi",
"Failed to load more channels": "Daha fazla kanal yüklenemedi",
"Failed to mark channel as read": "Kanalı okundu olarak işaretleme başarısız oldu",
"Failed to play the recording": "Kayıt oynatılamadı",
@@ -357,6 +366,9 @@
"fileCount_other": "{{ count }} dosya",
"Files": "Dosyalar",
"Flag": "Bayrak",
+ "Flags": "Bayraklar",
+ "Food & Drink": "Yiyecek ve İçecek",
+ "Frequently used": "Sık kullanılanlar",
"Generating...": "Oluşturuluyor...",
"giphy-command-args": "[metin]",
"giphy-command-description": "Rastgele bir gif'i kanala gönder",
@@ -430,6 +442,7 @@
"Leave chat": "Kanaldan ayrıl",
"Left channel": "Kanaldan ayrıldınız",
"Let others add options": "Başkalarının seçenek eklemesine izin ver",
+ "Light": "Açık",
"Limit votes per person": "Kişi başına oy sınırı",
"Link": "Bağlantı",
"linkCount_one": "Bağlantı",
@@ -448,6 +461,9 @@
"Mark as unread": "Okunmamış olarak işaretle",
"Maximum number of votes (from 2 to 10)": "Maksimum oy sayısı (2 ile 10 arası)",
"Maximum votes per person": "Kişi başına maksimum oy",
+ "Medium": "Orta",
+ "Medium-Dark": "Orta koyu",
+ "Medium-Light": "Orta açık",
"Member detail": "Üye detayı",
"mention/Channel": "Kanal",
"mention/Channel Description": "Bu kanaldaki herkesi bildir",
@@ -478,6 +494,7 @@
"Next image": "Sonraki görsel",
"No chats here yet…": "Henüz burada sohbet yok...",
"No conversations yet": "Henüz konuşma yok",
+ "No emoji found": "Emoji bulunamadı",
"No files": "Dosya yok",
"No items exist": "Hiç öğe yok",
"No member found": "Üye bulunamadı",
@@ -489,6 +506,7 @@
"Nobody will be able to vote in this poll anymore.": "Artık bu ankette kimse oy kullanamayacak.",
"Nothing yet...": "Şimdilik hiçbir şey...",
"Notify all {{ role }} members": "{{ role }} rolündeki tüm üyelere bildir",
+ "Objects": "Nesneler",
"Offline": "Çevrimdışı",
"Ok": "Tamam",
"Online": "Çevrimiçi",
@@ -508,6 +526,7 @@
"People matching": "Eşleşen kişiler",
"Photo": "Fotoğraf",
"Photos & videos": "Fotoğraflar ve videolar",
+ "Pick an emoji…": "Emoji seç…",
"Pin": "Sabitle",
"Pin a message to see it here": "Burada görmek için bir mesaj sabitle",
"Pinned by {{ name }}": "{{ name }} sabitledi",
@@ -553,6 +572,7 @@
"replyCount_one": "1 cevap",
"replyCount_other": "{{ count }} cevap",
"Resend": "Tekrar gönder",
+ "Retry": "Yeniden dene",
"Retry upload": "Yüklemeyi yeniden dene",
"Review all options available in this poll": "Bu anketteki tüm mevcut seçenekleri inceleyin",
"Review comments submitted with poll answers": "Anket yanıtlarıyla gönderilen yorumları inceleyin",
@@ -563,6 +583,7 @@
"Save for later": "Daha sonra kaydet",
"Saved for later": "Daha sonra kaydedildi",
"Search": "Arama",
+ "Search emoji": "Emoji ara",
"Search GIFs": "GIF ara",
"search-results-header-filter-source-button-label--channels": "kanallar",
"search-results-header-filter-source-button-label--messages": "mesajlar",
@@ -598,12 +619,14 @@
"size limit": "boyut sınırı",
"Slow Mode ON": "Yavaş Mod Açık",
"Slow mode, wait {{ seconds }}s...": "Yavaş mod, {{ seconds }} sn bekleyin...",
+ "Smileys & People": "Suratlar ve İnsanlar",
"Some of the files will not be accepted": "Bazı dosyalar kabul edilmeyecek",
"Start typing to search": "Aramak için yazmaya başlayın",
"Stop sharing": "Paylaşımı durdur",
"Submit": "Gönder",
"Suggest a new option to add to this poll": "Bu ankete eklenecek yeni bir seçenek önerin",
"Suggest an option": "Bir seçenek önerin",
+ "Symbols": "Semboller",
"Tap to remove": "Kaldırmak için dokunun",
"Tap to remove: {{ reactionName }}": "Kaldırmak için dokunun: {{ reactionName }}",
"Thinking...": "Düşünüyor...",
@@ -642,6 +665,7 @@
"Translated": "Çevrildi",
"Translated from {{ language }}": "{{ language }} dilinden çevrildi",
"translationBuilderTopic/notification": "{{value, notification}}",
+ "Travel & Places": "Seyahat ve Yerler",
"Type a number from 2 to 10": "2 ile 10 arasında bir sayı yazın",
"Unarchive": "Arşivden çıkar",
"unban-command-args": "[@kullanıcıadı]",
diff --git a/src/plugins/Emojis/EmojiPicker.tsx b/src/plugins/Emojis/EmojiPicker.tsx
index 4972da647..c83d45f14 100644
--- a/src/plugins/Emojis/EmojiPicker.tsx
+++ b/src/plugins/Emojis/EmojiPicker.tsx
@@ -21,6 +21,9 @@ const Picker =
const isShadowRoot = (node: Node): node is ShadowRoot => !!(node as ShadowRoot).host;
+// Warn at most once per session that this engine is going away.
+let hasWarnedEmojiMartDeprecation = false;
+
export type EmojiPickerProps = {
ButtonIconComponent?: React.ComponentType;
buttonClassName?: string;
@@ -28,8 +31,8 @@ export type EmojiPickerProps = {
wrapperClassName?: string;
closeOnEmojiSelect?: boolean;
/**
- * Untyped [properties](https://github.com/missive/emoji-mart/tree/v5.5.2#options--props) to be
- * passed down to the [emoji-mart `Picker`](https://github.com/missive/emoji-mart/tree/v5.5.2#-picker) component
+ * Untyped [properties](https://github.com/missive/emoji-mart/tree/v5.6.0#options--props) to be
+ * passed down to the [emoji-mart `Picker`](https://github.com/missive/emoji-mart/tree/v5.6.0#-picker) component
*/
pickerProps?: Partial<{ theme: 'auto' | 'light' | 'dark' } & Record>;
/**
@@ -48,9 +51,14 @@ const classNames: Pick<
wrapperClassName: 'str-chat__message-textarea-emoji-picker',
};
+/**
+ * @deprecated The emoji-mart-based `EmojiPicker` will be removed in v15. Switch to
+ * `StreamEmojiPicker` from `stream-chat-react/emojis`, which needs no emoji-mart
+ * packages. See the emoji section of `AI.md` for migration notes.
+ */
export const EmojiPicker = (props: EmojiPickerProps) => {
- const { t } = useTranslationContext('EmojiPicker');
- const { textareaRef } = useMessageComposerContext('EmojiPicker');
+ const { t } = useTranslationContext();
+ const { textareaRef } = useMessageComposerContext();
const { textComposer } = useMessageComposerController();
const isCooldownActive = useIsCooldownActive();
const [displayPicker, setDisplayPicker] = useState(false);
@@ -63,6 +71,15 @@ export const EmojiPicker = (props: EmojiPickerProps) => {
placement: props.placement ?? 'top-end',
});
+ useEffect(() => {
+ if (hasWarnedEmojiMartDeprecation) return;
+ hasWarnedEmojiMartDeprecation = true;
+ console.warn(
+ '[stream-chat-react] The `emoji-mart`-based `EmojiPicker` is deprecated and will be removed in the next major version. ' +
+ 'Switch to `StreamEmojiPicker` from `stream-chat-react/emojis` as it offers the same functionality without 3rd party dependencies.',
+ );
+ }, []);
+
useEffect(() => {
refs.setReference(referenceElement);
}, [referenceElement, refs]);
diff --git a/src/plugins/Emojis/StreamEmojiPicker.tsx b/src/plugins/Emojis/StreamEmojiPicker.tsx
new file mode 100644
index 000000000..b68de3c3d
--- /dev/null
+++ b/src/plugins/Emojis/StreamEmojiPicker.tsx
@@ -0,0 +1,202 @@
+import React, { type CSSProperties, useEffect, useRef, useState } from 'react';
+
+import { useMessageComposerContext, useTranslationContext } from '../../context';
+import {
+ Button,
+ IconEmoji,
+ type PopperLikePlacement,
+ useMessageComposerController,
+} from '../../components';
+import { usePopoverPosition } from '../../components/Dialog/hooks/usePopoverPosition';
+import { useIsCooldownActive } from '../../components/MessageComposer/hooks/useIsCooldownActive';
+import { CategoryNav } from './components/CategoryNav';
+import { EmojiGrid } from './components/EmojiGrid';
+import { EmojiPickerPanel } from './components/EmojiPickerPanel';
+import { EmojiPickerRoot } from './components/EmojiPickerRoot';
+import { PreviewPane } from './components/PreviewPane';
+import { SearchInput } from './components/SearchInput';
+import { SkinToneSelector } from './components/SkinToneSelector';
+import { useFrequentlyUsedEmoji } from './hooks/useFrequentlyUsedEmoji';
+import { useSkinTone } from './hooks/useSkinTone';
+
+const isShadowRoot = (node: Node): node is ShadowRoot => !!(node as ShadowRoot).host;
+
+export type StreamEmojiPickerProps = {
+ ButtonIconComponent?: React.ComponentType;
+ buttonClassName?: string;
+ pickerContainerClassName?: string;
+ wrapperClassName?: string;
+ closeOnEmojiSelect?: boolean;
+ /** Floating UI placement (default: 'top-end') for the picker popover. */
+ placement?: PopperLikePlacement;
+ /** Focus the search input when the picker opens (default `true`). */
+ autoFocus?: boolean;
+ /** Category ids to show, in order. Defaults to the dataset order. `frequent` always prepends. */
+ categories?: string[];
+ /** Emoji ids to exclude from the grid and search. */
+ exceptEmojis?: string[];
+ /** Called when a pointer press lands outside the open picker. */
+ onClickOutside?: () => void;
+ /** Inline styles applied to the picker panel root. */
+ style?: CSSProperties;
+ /** Color theme. 'auto' (default) inherits the ancestor SDK theme; 'light'/'dark' force it. */
+ theme?: 'auto' | 'light' | 'dark';
+ /** Uncontrolled initial skin tone index (0 = default, 1–5 = light → dark). */
+ defaultSkinTone?: number;
+ /**
+ * Controlled ordered list of recently used emoji ids (most recent first). The SDK
+ * does not persist this — provide it (and `onFrequentlyUsedChange`) to control the
+ * "frequently used" section; otherwise it is tracked in memory for the session.
+ */
+ frequentlyUsedEmoji?: string[];
+ /** Called with the updated recently-used list when an emoji is selected. */
+ onFrequentlyUsedChange?: (emojiIds: string[]) => void;
+ /** Called with the new skin tone index when it changes. */
+ onSkinToneChange?: (skinTone: number) => void;
+ /** Controlled skin tone index (0 = default, 1–5 = light → dark). */
+ skinTone?: number;
+};
+
+const defaultButtonClassName = 'str-chat__emoji-picker-button';
+
+const classNames: Pick<
+ StreamEmojiPickerProps,
+ 'pickerContainerClassName' | 'wrapperClassName'
+> = {
+ pickerContainerClassName: 'str-chat__message-textarea-emoji-picker-container',
+ wrapperClassName: 'str-chat__message-textarea-emoji-picker',
+};
+
+const StreamEmojiPickerComponent = (props: StreamEmojiPickerProps) => {
+ const { t } = useTranslationContext();
+ const { textareaRef } = useMessageComposerContext();
+ const { textComposer } = useMessageComposerController();
+ const isCooldownActive = useIsCooldownActive();
+ // Skin tone and frequently-used live here (not in the panel) so they survive the
+ // picker opening/closing — the panel below is mounted only while open.
+ const [skinTone, setSkinTone] = useSkinTone({
+ defaultSkinTone: props.defaultSkinTone,
+ onSkinToneChange: props.onSkinToneChange,
+ skinTone: props.skinTone,
+ });
+ const { frequentlyUsedIds, recordUse } = useFrequentlyUsedEmoji({
+ frequentlyUsedEmoji: props.frequentlyUsedEmoji,
+ onFrequentlyUsedChange: props.onFrequentlyUsedChange,
+ });
+ const [displayPicker, setDisplayPicker] = useState(false);
+ const [referenceElement, setReferenceElement] = useState(
+ null,
+ );
+ const [popperElement, setPopperElement] = useState(null);
+ const { refs, strategy, x, y } = usePopoverPosition({
+ offset: 8,
+ placement: props.placement ?? 'top-end',
+ });
+
+ useEffect(() => {
+ refs.setReference(referenceElement);
+ }, [referenceElement, refs]);
+ useEffect(() => {
+ refs.setFloating(popperElement);
+ }, [popperElement, refs]);
+
+ const { pickerContainerClassName, wrapperClassName } = classNames;
+
+ const { ButtonIconComponent = IconEmoji } = props;
+ // Latest-ref so the click-outside listener isn't re-attached when the callback identity
+ // changes between renders.
+ const onClickOutsideRef = useRef(props.onClickOutside);
+ onClickOutsideRef.current = props.onClickOutside;
+
+ useEffect(() => {
+ if (!popperElement || !referenceElement) return;
+
+ const handlePointerDown = (e: PointerEvent) => {
+ const target = e.target as HTMLElement;
+
+ const rootNode = target.getRootNode();
+
+ if (
+ popperElement.contains(isShadowRoot(rootNode) ? rootNode.host : target) ||
+ referenceElement.contains(target)
+ ) {
+ return;
+ }
+
+ onClickOutsideRef.current?.();
+ setDisplayPicker(false);
+ };
+
+ window.addEventListener('pointerdown', handlePointerDown);
+ return () => window.removeEventListener('pointerdown', handlePointerDown);
+ }, [referenceElement, popperElement]);
+
+ return (
+
+ {displayPicker && (
+
+ {
+ setDisplayPicker(false);
+ referenceElement?.focus();
+ }}
+ onEmojiSelect={(emoji) => {
+ const textarea = textareaRef.current;
+ if (!textarea) return;
+ // Record only once we know the emoji is actually being inserted.
+ recordUse(emoji.id);
+ textComposer.insertText({ text: emoji.native });
+ textarea.focus();
+ if (props.closeOnEmojiSelect) {
+ setDisplayPicker(false);
+ }
+ }}
+ onSkinToneChange={setSkinTone}
+ skinToneIndex={skinTone}
+ style={props.style}
+ theme={props.theme}
+ />
+
+ )}
+
setDisplayPicker((cv) => !cv)}
+ ref={setReferenceElement}
+ size='sm'
+ type='button'
+ variant='secondary'
+ >
+ {ButtonIconComponent && }
+
+
+ );
+};
+
+/**
+ * The built-in emoji picker. Rendered directly, it is the batteries-included preset
+ * (toggle button + popover + the standard panel). For a custom layout, compose the parts
+ * — `StreamEmojiPicker.Root` wrapping any arrangement of `.Nav` / `.Search` / `.Grid` /
+ * `.Preview` / `.SkinTone` (and your own slots via `useEmojiPickerContext`).
+ */
+export const StreamEmojiPicker = Object.assign(StreamEmojiPickerComponent, {
+ Grid: EmojiGrid,
+ Nav: CategoryNav,
+ Preview: PreviewPane,
+ Root: EmojiPickerRoot,
+ Search: SearchInput,
+ SkinTone: SkinToneSelector,
+});
diff --git a/src/plugins/Emojis/__tests__/EmojiPicker.test.tsx b/src/plugins/Emojis/__tests__/EmojiPicker.test.tsx
new file mode 100644
index 000000000..85e7088cc
--- /dev/null
+++ b/src/plugins/Emojis/__tests__/EmojiPicker.test.tsx
@@ -0,0 +1,86 @@
+import type { MouseEventHandler, ReactNode } from 'react';
+import { fireEvent, render, screen } from '@testing-library/react';
+
+// Mock emoji-mart's Picker so jsdom doesn't render the real web component.
+vi.mock('@emoji-mart/react', () => ({
+ default: ({ onEmojiSelect }: { onEmojiSelect: (e: { native: string }) => void }) => (
+
+ onEmojiSelect({ native: '🚀' })} type='button'>
+ pick
+
+
+ ),
+}));
+vi.mock('@emoji-mart/data', () => ({ default: {} }));
+
+const { textareaRef } = vi.hoisted(() => ({
+ textareaRef: {
+ current: document.createElement('textarea') as HTMLTextAreaElement | null,
+ },
+}));
+const insertText = vi.hoisted(() => vi.fn());
+
+vi.mock('../../../context', () => ({
+ useMessageComposerContext: () => ({ textareaRef }),
+ useTranslationContext: () => ({ t: (key: string) => key }),
+}));
+vi.mock('../../../components', async () => {
+ const { forwardRef } = await import('react');
+ return {
+ Button: forwardRef>(
+ function Button(props, ref) {
+ return (
+ | undefined}
+ ref={ref}
+ type='button'
+ >
+ {props.children as ReactNode}
+
+ );
+ },
+ ),
+ IconEmoji: () => emoji ,
+ useMessageComposerController: () => ({ textComposer: { insertText } }),
+ };
+});
+vi.mock('../../../components/Dialog/hooks/usePopoverPosition', () => ({
+ usePopoverPosition: () => ({
+ refs: { setFloating: vi.fn(), setReference: vi.fn() },
+ strategy: 'absolute',
+ x: 0,
+ y: 0,
+ }),
+}));
+vi.mock('../../../components/MessageComposer/hooks/useIsCooldownActive', () => ({
+ useIsCooldownActive: () => false,
+}));
+
+import { EmojiPicker } from '../EmojiPicker';
+
+describe('EmojiPicker (deprecated emoji-mart)', () => {
+ it('warns once about deprecation, naming the successor', () => {
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
+ const { unmount } = render( );
+ expect(warn).toHaveBeenCalledTimes(1);
+ expect(warn.mock.calls[0][0]).toMatch(/deprecated/i);
+ expect(warn.mock.calls[0][0]).toMatch(/StreamEmojiPicker/);
+ expect(warn.mock.calls[0][0]).toMatch(/next major version/i);
+ unmount();
+
+ warn.mockClear();
+ render( ); // module-level flag → no second warning
+ expect(warn).not.toHaveBeenCalled();
+ warn.mockRestore();
+ });
+
+ it('renders emoji-mart Picker when opened and inserts the chosen emoji', () => {
+ vi.spyOn(console, 'warn').mockImplementation(() => {});
+ render( );
+ fireEvent.click(screen.getByLabelText('aria/Emoji picker'));
+ expect(screen.getByTestId('em-picker')).toBeInTheDocument();
+ fireEvent.click(screen.getByText('pick'));
+ expect(insertText).toHaveBeenCalledWith({ text: '🚀' });
+ });
+});
diff --git a/src/plugins/Emojis/__tests__/StreamEmojiPicker.test.tsx b/src/plugins/Emojis/__tests__/StreamEmojiPicker.test.tsx
new file mode 100644
index 000000000..acd35573c
--- /dev/null
+++ b/src/plugins/Emojis/__tests__/StreamEmojiPicker.test.tsx
@@ -0,0 +1,135 @@
+import type { AriaAttributes, MouseEventHandler, ReactNode } from 'react';
+import { fireEvent, render, screen } from '@testing-library/react';
+
+// The panel is mounted only while the picker is open, so mock it to a controllable
+// stub. This lets us assert that the owner (EmojiPicker) preserves skin tone and
+// frequently-used across open/close — without depending on the real panel's
+// virtualized grid + async data load, which don't render reliably in jsdom.
+vi.mock('../components/EmojiPickerPanel', () => ({
+ EmojiPickerPanel: ({
+ frequentlyUsedIds = [],
+ onEmojiSelect,
+ onSkinToneChange,
+ skinToneIndex = 0,
+ }: {
+ frequentlyUsedIds?: string[];
+ onEmojiSelect: (emoji: { id: string; name: string; native: string }) => void;
+ onSkinToneChange?: (skinTone: number) => void;
+ skinToneIndex?: number;
+ }) => (
+
+ {skinToneIndex}
+ {frequentlyUsedIds.join(',')}
+ onSkinToneChange?.(4)} type='button'>
+ set-skin
+
+ onEmojiSelect({ id: 'rocket', name: 'Rocket', native: '🚀' })}
+ type='button'
+ >
+ select-rocket
+
+
+ ),
+}));
+
+// Mutable so a test can simulate "no textarea to insert into" (textareaRef.current null).
+const { textareaRef } = vi.hoisted(() => ({
+ textareaRef: { current: null as HTMLTextAreaElement | null },
+}));
+
+vi.mock('../../../context', () => ({
+ useMessageComposerContext: () => ({ textareaRef }),
+ useTranslationContext: () => ({ t: (key: string) => key }),
+}));
+
+vi.mock('../../../components', async () => {
+ const { forwardRef } = await import('react');
+ return {
+ Button: forwardRef>(
+ function Button(props, ref) {
+ // Forward only the DOM-valid props the test needs; styling props are dropped.
+ return (
+ | undefined}
+ ref={ref}
+ type='button'
+ >
+ {props.children as ReactNode}
+
+ );
+ },
+ ),
+ IconEmoji: () => emoji ,
+ useMessageComposerController: () => ({ textComposer: { insertText: vi.fn() } }),
+ };
+});
+
+vi.mock('../../../components/Dialog/hooks/usePopoverPosition', () => ({
+ usePopoverPosition: () => ({
+ refs: { setFloating: vi.fn(), setReference: vi.fn() },
+ strategy: 'absolute',
+ x: 0,
+ y: 0,
+ }),
+}));
+
+vi.mock('../../../components/MessageComposer/hooks/useIsCooldownActive', () => ({
+ useIsCooldownActive: () => false,
+}));
+
+// Imported after the mocks so the mocked dependencies are in place.
+import { StreamEmojiPicker } from '../StreamEmojiPicker';
+
+const openPicker = () => fireEvent.click(screen.getByLabelText('aria/Emoji picker'));
+
+beforeEach(() => {
+ textareaRef.current = document.createElement('textarea');
+});
+
+describe('StreamEmojiPicker session state', () => {
+ it('keeps skin tone and frequently-used across close and reopen (incl. closeOnEmojiSelect)', () => {
+ render( );
+
+ openPicker();
+ expect(screen.getByTestId('skin-tone')).toHaveTextContent('0');
+ expect(screen.getByTestId('frequently-used')).toHaveTextContent('');
+
+ // Change skin tone, then select an emoji — selecting closes the picker.
+ fireEvent.click(screen.getByText('set-skin'));
+ expect(screen.getByTestId('skin-tone')).toHaveTextContent('4');
+ fireEvent.click(screen.getByText('select-rocket'));
+
+ // Panel (and any state it might have held) is unmounted.
+ expect(screen.queryByTestId('panel')).not.toBeInTheDocument();
+
+ // Reopening shows the retained skin tone and the just-used emoji.
+ openPicker();
+ expect(screen.getByTestId('skin-tone')).toHaveTextContent('4');
+ expect(screen.getByTestId('frequently-used')).toHaveTextContent('rocket');
+ });
+
+ it('does not record a frequently-used emoji when there is no textarea to insert into', () => {
+ textareaRef.current = null;
+ render( );
+
+ openPicker();
+ expect(screen.getByTestId('frequently-used').textContent).toBe('');
+
+ // Selecting can't insert (no textarea), so it must not be recorded as "used".
+ fireEvent.click(screen.getByText('select-rocket'));
+ expect(screen.getByTestId('frequently-used').textContent).toBe('');
+ });
+});
+
+describe('StreamEmojiPicker props', () => {
+ it('calls onClickOutside when a pointer press lands outside the open picker', () => {
+ const onClickOutside = vi.fn();
+ render( );
+ openPicker();
+ fireEvent.pointerDown(document.body);
+ expect(onClickOutside).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/src/plugins/Emojis/__tests__/entry-exports.test.ts b/src/plugins/Emojis/__tests__/entry-exports.test.ts
new file mode 100644
index 000000000..8baef557a
--- /dev/null
+++ b/src/plugins/Emojis/__tests__/entry-exports.test.ts
@@ -0,0 +1,22 @@
+import * as emojis from '../index';
+import { StreamEmojiPicker } from '../StreamEmojiPicker';
+
+describe('emojis entry exports', () => {
+ it('exports both pickers, the compound parts, and the context hook', () => {
+ // Deprecated emoji-mart picker + its built-in successor.
+ expect(typeof emojis.EmojiPicker).toBe('function');
+ expect(typeof emojis.StreamEmojiPicker).toBe('function');
+ // Composition surface.
+ expect(typeof emojis.useEmojiPickerContext).toBe('function');
+ for (const part of [
+ 'Grid',
+ 'Nav',
+ 'Preview',
+ 'Root',
+ 'Search',
+ 'SkinTone',
+ ] as const) {
+ expect(typeof StreamEmojiPicker[part]).toBe('function');
+ }
+ });
+});
diff --git a/src/plugins/Emojis/__tests__/memoizeAsyncWithReset.test.ts b/src/plugins/Emojis/__tests__/memoizeAsyncWithReset.test.ts
new file mode 100644
index 000000000..c4cd49c45
--- /dev/null
+++ b/src/plugins/Emojis/__tests__/memoizeAsyncWithReset.test.ts
@@ -0,0 +1,41 @@
+import { memoizeAsyncWithReset } from '../memoizeAsyncWithReset';
+
+describe('memoizeAsyncWithReset', () => {
+ it('memoizes a successful result so the factory runs once', async () => {
+ let calls = 0;
+ const memoized = memoizeAsyncWithReset(() => {
+ calls += 1;
+ return Promise.resolve('data');
+ });
+
+ await expect(memoized()).resolves.toBe('data');
+ await expect(memoized()).resolves.toBe('data');
+ expect(calls).toBe(1);
+ });
+
+ it('shares a single in-flight promise between concurrent callers', async () => {
+ let calls = 0;
+ const memoized = memoizeAsyncWithReset(() => {
+ calls += 1;
+ return Promise.resolve('data');
+ });
+
+ await Promise.all([memoized(), memoized()]);
+ expect(calls).toBe(1);
+ });
+
+ it('resets after a rejection so the next call retries instead of replaying the failure', async () => {
+ let calls = 0;
+ const memoized = memoizeAsyncWithReset(() => {
+ calls += 1;
+ return calls === 1
+ ? Promise.reject(new Error('chunk load failed'))
+ : Promise.resolve('data');
+ });
+
+ await expect(memoized()).rejects.toThrow('chunk load failed');
+ // A memoized rejection would replay forever; the reset must let the retry succeed.
+ await expect(memoized()).resolves.toBe('data');
+ expect(calls).toBe(2);
+ });
+});
diff --git a/src/plugins/Emojis/__tests__/reactions.test.tsx b/src/plugins/Emojis/__tests__/reactions.test.tsx
new file mode 100644
index 000000000..42a21d584
--- /dev/null
+++ b/src/plugins/Emojis/__tests__/reactions.test.tsx
@@ -0,0 +1,32 @@
+import { render } from '@testing-library/react';
+import { loadDefaultExtendedReactionOptions } from '../reactions';
+import { emojiToUnicode } from '../../../components/Reactions/reactionOptions';
+
+describe('loadDefaultExtendedReactionOptions', () => {
+ it('builds an extended reaction map covering the full emoji dataset', async () => {
+ const extended = await loadDefaultExtendedReactionOptions();
+
+ // The full vendored set (~1,870 emoji) — far beyond the handful of quick reactions,
+ // so the picker's "+" list lets you react with essentially any emoji again.
+ expect(Object.keys(extended).length).toBeGreaterThan(1000);
+ });
+
+ it('keys entries by unicode and renders the native glyph', async () => {
+ const extended = await loadDefaultExtendedReactionOptions();
+ const grinningUnicode = emojiToUnicode('😀'); // U+1F600
+
+ const entry = extended[grinningUnicode];
+ expect(entry).toBeDefined();
+ expect(entry.unicode).toBe(grinningUnicode);
+
+ const { container } = render( );
+ expect(container).toHaveTextContent('😀');
+ });
+
+ it('memoizes: repeated calls resolve the same map (no rebuild per reaction render)', async () => {
+ const first = await loadDefaultExtendedReactionOptions();
+ const second = await loadDefaultExtendedReactionOptions();
+
+ expect(first).toBe(second);
+ });
+});
diff --git a/src/plugins/Emojis/compat.ts b/src/plugins/Emojis/compat.ts
new file mode 100644
index 000000000..2f270ceed
--- /dev/null
+++ b/src/plugins/Emojis/compat.ts
@@ -0,0 +1,9 @@
+/**
+ * @deprecated No longer required. The built-in emoji search index self-initializes,
+ * so this is a no-op kept only so existing `init({ data })` calls keep compiling and
+ * running while migrating away from `emoji-mart`. Safe to remove from your app.
+ */
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export const init = (_options?: unknown): void => {
+ // intentionally empty — kept for backwards compatibility only
+};
diff --git a/src/plugins/Emojis/components/CategoryNav.tsx b/src/plugins/Emojis/components/CategoryNav.tsx
new file mode 100644
index 000000000..7c2402949
--- /dev/null
+++ b/src/plugins/Emojis/components/CategoryNav.tsx
@@ -0,0 +1,64 @@
+import { type KeyboardEvent, useRef } from 'react';
+import clsx from 'clsx';
+import { EMOJI_CATEGORY_META } from './categories';
+import { useEmojiPickerContext } from '../context/EmojiPickerContext';
+
+const NAV_KEYS = ['ArrowRight', 'ArrowLeft', 'Home', 'End'];
+
+/**
+ * Top navigation bar with one tab per category (role="tablist"). Clicking a tab
+ * scrolls its section into view; Left/Right/Home/End move focus between tabs with a
+ * roving tabindex; the active tab reflects the currently visible section. Reads the
+ * category model + active category from context and reports clicks via
+ * `requestScrollToCategory`. The active tab is suppressed during search.
+ */
+export const CategoryNav = () => {
+ const { activeCategoryId, categories, isSearching, requestScrollToCategory } =
+ useEmojiPickerContext();
+ const navRef = useRef(null);
+ const active = isSearching ? undefined : activeCategoryId;
+ const rovingId = active ?? categories[0]?.id;
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ if (!NAV_KEYS.includes(event.key)) return;
+ const tabs = Array.from(
+ navRef.current?.querySelectorAll('[role="tab"]') ?? [],
+ );
+ const index = tabs.findIndex((tab) => tab === document.activeElement);
+ if (index === -1) return;
+ event.preventDefault();
+ const lastIndex = tabs.length - 1;
+ let next = index;
+ if (event.key === 'ArrowRight') next = Math.min(index + 1, lastIndex);
+ else if (event.key === 'ArrowLeft') next = Math.max(index - 1, 0);
+ else if (event.key === 'Home') next = 0;
+ else if (event.key === 'End') next = lastIndex;
+ tabs[next]?.focus();
+ };
+
+ return (
+
+ {categories.map(({ id, label }) => (
+ requestScrollToCategory(id)}
+ role='tab'
+ tabIndex={id === rovingId ? 0 : -1}
+ type='button'
+ >
+ {EMOJI_CATEGORY_META[id]?.glyph ?? '•'}
+
+ ))}
+
+ );
+};
diff --git a/src/plugins/Emojis/components/EmojiButton.tsx b/src/plugins/Emojis/components/EmojiButton.tsx
new file mode 100644
index 000000000..a0ac73886
--- /dev/null
+++ b/src/plugins/Emojis/components/EmojiButton.tsx
@@ -0,0 +1,37 @@
+import { memo } from 'react';
+import { useEmojiPickerCellContext } from '../context/EmojiPickerCellContext';
+import { useEmojiPickerPreviewContext } from '../context/EmojiPickerPreviewContext';
+import type { EmojiDataEmoji } from '../data';
+
+export type EmojiButtonProps = {
+ emoji: EmojiDataEmoji;
+};
+
+/**
+ * A single selectable emoji cell rendering the native unicode glyph for the active
+ * skin tone. Memoized because the grid can render ~1800 of these — and it subscribes to
+ * the cold cell context (not the public picker context) so scroll-spy/search updates,
+ * which a cell reads none of, never re-render the grid.
+ */
+export const EmojiButton = memo(function EmojiButton({ emoji }: EmojiButtonProps) {
+ const { resolveNative, selectEmoji } = useEmojiPickerCellContext();
+ const { setPreviewedEmoji } = useEmojiPickerPreviewContext();
+
+ return (
+ selectEmoji(emoji)}
+ onFocus={() => setPreviewedEmoji(emoji)}
+ onMouseEnter={() => setPreviewedEmoji(emoji)}
+ // Native semantics (not role='gridcell'): the category view is
+ // virtualized, so a valid grid/row/gridcell tree can't be guaranteed. Roving
+ // tabIndex still drives 2D arrow-key navigation (see useGridKeyboardNav).
+ tabIndex={-1}
+ type='button'
+ >
+ {resolveNative(emoji)}
+
+ );
+});
diff --git a/src/plugins/Emojis/components/EmojiGrid.tsx b/src/plugins/Emojis/components/EmojiGrid.tsx
new file mode 100644
index 000000000..ef809a796
--- /dev/null
+++ b/src/plugins/Emojis/components/EmojiGrid.tsx
@@ -0,0 +1,122 @@
+import { useCallback, useEffect, useRef } from 'react';
+import { Virtuoso, type VirtuosoHandle } from 'react-virtuoso';
+import { EmojiButton } from './EmojiButton';
+import { EmptyResults } from './EmptyResults';
+import { useEmojiPickerContext } from '../context/EmojiPickerContext';
+import { useGridKeyboardNav } from '../hooks/useGridKeyboardNav';
+import type { EmojiDataEmoji } from '../data';
+
+export type EmojiPickerCategory = {
+ emojis: EmojiDataEmoji[];
+ id: string;
+ label: string;
+};
+
+const CategorySection = ({ category }: { category: EmojiPickerCategory }) => (
+
+
+ {category.label}
+
+
+ {category.emojis.map((emoji) => (
+
+ ))}
+
+
+);
+
+/**
+ * The context-driven body of the picker: while browsing, a category-grouped grid,
+ * virtualized at the category level with react-virtuoso (only categories in/near the
+ * viewport mount); while searching, a flat result list or the empty state. Scrolls to
+ * the category named by `scrollTarget`, reports the visible category via
+ * `setActiveCategory` (scroll-spy), and owns 2D roving keyboard navigation over its
+ * cells. A custom Grid slot forfeits these mechanics but keeps reading the same context.
+ */
+export const EmojiGrid = () => {
+ const { categories, isSearching, scrollTarget, searchResults, setActiveCategory } =
+ useEmojiPickerContext();
+ const virtuosoRef = useRef(null);
+ const atBottomRef = useRef(false);
+ const bodyRef = useRef(null);
+
+ const scrollToCategory = useCallback(
+ (categoryId: string) => {
+ const index = categories.findIndex((category) => category.id === categoryId);
+ if (index >= 0) virtuosoRef.current?.scrollToIndex({ align: 'start', index });
+ },
+ [categories],
+ );
+
+ // Latest-ref so the scroll effect can key on the `scrollTarget` nonce alone. Depending
+ // on `scrollToCategory` (whose identity changes with `categories`) would re-fire the
+ // scroll on unrelated updates — e.g. selecting an emoji updates frequently-used, which
+ // rebuilds `categories` and would otherwise yank the grid back to the last-scrolled
+ // category.
+ const scrollToCategoryRef = useRef(scrollToCategory);
+ scrollToCategoryRef.current = scrollToCategory;
+
+ // Nav clicks (and any consumer) request a scroll via `scrollTarget`; the nonce makes a
+ // repeat request to the same category re-fire. Deferred a frame so a freshly-mounted
+ // (search → browse) grid has laid out before we scroll to the requested category.
+ useEffect(() => {
+ if (!scrollTarget) return;
+ const frame = requestAnimationFrame(() =>
+ scrollToCategoryRef.current(scrollTarget.categoryId),
+ );
+ return () => cancelAnimationFrame(frame);
+ }, [scrollTarget]);
+
+ // Keyboard nav can target a category that virtualization has unmounted; give it the
+ // category order + a way to scroll one into view so focus can traverse the whole set.
+ const { onKeyDown } = useGridKeyboardNav(bodyRef, { categories, scrollToCategory });
+
+ if (isSearching) {
+ return (
+
+ {searchResults && searchResults.length ? (
+
+
+
+ {searchResults.map((emoji) => (
+
+ ))}
+
+
+
+ ) : (
+
+ )}
+
+ );
+ }
+
+ return (
+
+ {
+ atBottomRef.current = atBottom;
+ // The last category is often short and never reaches the top of the viewport,
+ // so scroll-spy alone would never mark it active — pin it while at the bottom.
+ const last = categories[categories.length - 1];
+ if (atBottom && last) setActiveCategory(last.id);
+ }}
+ className='str-chat__emoji-picker__grid'
+ data={categories}
+ itemContent={(_index, category) => }
+ rangeChanged={({ startIndex }) => {
+ // While pinned at the bottom, atBottomStateChange owns the active category.
+ if (atBottomRef.current) return;
+ const category = categories[startIndex];
+ if (category) setActiveCategory(category.id);
+ }}
+ ref={virtuosoRef}
+ style={{ height: '100%' }}
+ />
+
+ );
+};
diff --git a/src/plugins/Emojis/components/EmojiPickerPanel.tsx b/src/plugins/Emojis/components/EmojiPickerPanel.tsx
new file mode 100644
index 000000000..d30a7d4ff
--- /dev/null
+++ b/src/plugins/Emojis/components/EmojiPickerPanel.tsx
@@ -0,0 +1,29 @@
+import { CategoryNav } from './CategoryNav';
+import { EmojiGrid } from './EmojiGrid';
+import { EmojiPickerRoot, type EmojiPickerRootProps } from './EmojiPickerRoot';
+import { PreviewPane } from './PreviewPane';
+import { SearchInput } from './SearchInput';
+import { SkinToneSelector } from './SkinToneSelector';
+
+export type EmojiPickerPanelProps = Omit & {
+ /** Focus the search input when the panel mounts (default `true`). */
+ autoFocus?: boolean;
+};
+
+/**
+ * The batteries-included emoji picker panel: `EmojiPickerRoot` wired to the standard slot
+ * arrangement (category nav, search, grid, then a footer with the preview and skin-tone
+ * selector). This is the default composition `StreamEmojiPicker` renders; for a custom
+ * layout, render `StreamEmojiPicker.Root` with your own arrangement of slots instead.
+ */
+export const EmojiPickerPanel = (props: EmojiPickerPanelProps) => (
+
+
+
+
+
+
+);
diff --git a/src/plugins/Emojis/components/EmojiPickerRoot.tsx b/src/plugins/Emojis/components/EmojiPickerRoot.tsx
new file mode 100644
index 000000000..8bb7b90ad
--- /dev/null
+++ b/src/plugins/Emojis/components/EmojiPickerRoot.tsx
@@ -0,0 +1,298 @@
+import {
+ type CSSProperties,
+ type ReactNode,
+ useCallback,
+ useMemo,
+ useState,
+} from 'react';
+import clsx from 'clsx';
+import { type EmojiPickerCategory } from './EmojiGrid';
+import { EMOJI_CATEGORY_META } from './categories';
+import { resolveFrequentlyUsedEmoji } from './frequentlyUsed';
+import { SKIN_TONES } from './skinTones';
+import { EmojiPickerCellProvider } from '../context/EmojiPickerCellContext';
+import {
+ type EmojiPickerContextValue,
+ EmojiPickerProvider,
+} from '../context/EmojiPickerContext';
+import { EmojiPickerPreviewProvider } from '../context/EmojiPickerPreviewContext';
+import { useDebouncedValue } from '../hooks/useDebouncedValue';
+import { useEmojiPickerState } from '../hooks/useEmojiPickerState';
+import { buildEmojiSearchData, runSearch } from '../search';
+import type { EmojiDataEmoji } from '../data';
+import { filterEmojiData } from '../data/filterEmojiData';
+import { useTranslationContext } from '../../../context';
+
+// The grid renders 9 emoji per row by default; integrators change the column count via
+// the `--str-chat__emoji-picker-per-line` CSS token (the SCSS falls back to 9). The
+// "frequently used" section is capped to a single row.
+const DEFAULT_COLUMNS = 9;
+const FREQUENT_ROWS = 1;
+
+export type EmojiSelection = {
+ id: string;
+ name: string;
+ native: string;
+};
+
+export type EmojiPickerRootProps = {
+ onEmojiSelect: (emoji: EmojiSelection) => void;
+ /** Category ids to show, in order. Defaults to the dataset order. `frequent` always prepends. */
+ categories?: string[];
+ /** The picker slots to render (nav / search / grid / preview / skin-tone, in any arrangement). */
+ children?: ReactNode;
+ className?: string;
+ /** Emoji ids to exclude from the grid and search. */
+ exceptEmojis?: string[];
+ /**
+ * Ordered list of recently used emoji ids (most recent first), rendered as the
+ * "frequently used" section. This is a controlled value — the owner (EmojiPicker)
+ * holds it above the panel's mount so it survives the picker opening/closing.
+ */
+ frequentlyUsedIds?: string[];
+ /** Called when the picker requests to close (e.g. the Escape key). */
+ onClose?: () => void;
+ /** Called with the new skin tone index when the user changes it. */
+ onSkinToneChange?: (skinTone: number) => void;
+ /** Active skin tone index (0 = default, 1–5 = light → dark). Controlled by the owner. */
+ skinToneIndex?: number;
+ style?: CSSProperties;
+ theme?: 'auto' | 'light' | 'dark';
+};
+
+const noop = () => undefined;
+
+/**
+ * Maps the `theme` prop to the class applied on the panel root. `light`/`dark` force
+ * an absolute theme (the forced-light case is backed by a full light-variable override
+ * in EmojiPicker.scss, since the SDK has no `.str-chat__theme-light` variable set);
+ * `auto`/undefined applies no class and inherits the ancestor `.str-chat__theme-*`.
+ * Exported for testing the class contract the theme CSS relies on.
+ */
+export const themeClassName = (theme: EmojiPickerRootProps['theme']) => {
+ if (theme === 'light') return 'str-chat__theme-light';
+ if (theme === 'dark') return 'str-chat__theme-dark';
+ // 'auto' (default): inherit the ancestor `.str-chat__theme-*`.
+ return undefined;
+};
+
+/**
+ * The provider + dialog container for the emoji picker. Loads the vendored dataset, owns
+ * all shared picker state, and exposes it to its slot `children` via EmojiPickerContext
+ * (plus an internal preview context for hover state). Also owns the container-level a11y
+ * that survives any recomposition: `role="dialog"`, Escape-to-close, and the theme class.
+ * While the dataset is loading or failed, it renders a loading / error+retry region in
+ * place of the slots. `StreamEmojiPicker` renders this with the default slot arrangement;
+ * integrators can render it directly with a custom arrangement of slots.
+ *
+ * Skin tone and frequently-used are fully controlled (`skinToneIndex`,
+ * `frequentlyUsedIds`, `onSkinToneChange`): the picker is mounted only while open, so
+ * this session state is owned by the always-mounted shell rather than held here.
+ */
+export const EmojiPickerRoot = ({
+ categories: categoryFilter,
+ children,
+ className,
+ exceptEmojis,
+ frequentlyUsedIds = [],
+ onClose,
+ onEmojiSelect,
+ onSkinToneChange,
+ skinToneIndex = 0,
+ style,
+ theme,
+}: EmojiPickerRootProps) => {
+ const { t } = useTranslationContext();
+ const { data, error, retry } = useEmojiPickerState();
+ const status: 'error' | 'loading' | 'ready' = data
+ ? 'ready'
+ : error
+ ? 'error'
+ : 'loading';
+ // One filtered view of the dataset feeds both the grid and the search index so
+ // exclusions apply consistently. Returns the same reference when no filter is set.
+ const filteredData = useMemo(
+ () => (data ? filterEmojiData(data, { exceptEmojis }) : data),
+ [data, exceptEmojis],
+ );
+ const [previewedEmoji, setPreviewedEmoji] = useState(null);
+ const [activeCategoryId, setActiveCategoryId] = useState(undefined);
+ const [query, setQuery] = useState('');
+ const [scrollTarget, setScrollTarget] = useState<{
+ categoryId: string;
+ nonce: number;
+ } | null>(null);
+ // Debounce the query that drives the search so typing doesn't re-scan the index and
+ // re-render up to 90 result cells on every keystroke (clearing still exits at once).
+ const debouncedQuery = useDebouncedValue(query, 120);
+
+ const baseCategories = useMemo(() => {
+ if (!filteredData) return [];
+ const built = filteredData.categories.map((category) => ({
+ emojis: category.emojis.map((id) => filteredData.emojis[id]).filter(Boolean),
+ id: category.id,
+ label: t(EMOJI_CATEGORY_META[category.id]?.labelKey ?? category.id),
+ }));
+ // `categories` option: keep only the requested ids, in the requested order.
+ if (!categoryFilter) return built;
+ const byId = new Map(built.map((category) => [category.id, category]));
+ return categoryFilter
+ .map((id) => {
+ if (!byId.has(id)) {
+ console.warn(
+ `[stream-chat-react] EmojiPicker: unknown category id "${id}" ignored.`,
+ );
+ }
+ return byId.get(id);
+ })
+ .filter((category): category is EmojiPickerCategory => Boolean(category));
+ }, [filteredData, categoryFilter, t]);
+
+ const categories = useMemo(() => {
+ if (!filteredData || !frequentlyUsedIds.length) return baseCategories;
+ const frequent: EmojiPickerCategory = {
+ // Capped to a single row so the section stays one row wide as more emoji are used.
+ emojis: resolveFrequentlyUsedEmoji(
+ filteredData,
+ frequentlyUsedIds,
+ DEFAULT_COLUMNS * FREQUENT_ROWS,
+ ),
+ id: 'frequent',
+ label: t(EMOJI_CATEGORY_META.frequent.labelKey),
+ };
+ return frequent.emojis.length ? [frequent, ...baseCategories] : baseCategories;
+ }, [baseCategories, filteredData, frequentlyUsedIds, t]);
+
+ const searchIndex = useMemo(
+ () => (filteredData ? buildEmojiSearchData(filteredData) : []),
+ [filteredData],
+ );
+
+ // `null` when not searching; otherwise the (possibly empty) list of matches. Clearing
+ // the field (empty live `query`) exits search immediately; a non-empty query is taken
+ // from the debounced value.
+ const searchedEmojis = useMemo(() => {
+ const trimmed = query.trim() && debouncedQuery.trim();
+ if (!trimmed || !filteredData) return null;
+ return (runSearch(searchIndex, trimmed) ?? [])
+ .map((result) => filteredData.emojis[result.id])
+ .filter(Boolean);
+ }, [debouncedQuery, filteredData, query, searchIndex]);
+
+ const isSearching = searchedEmojis !== null;
+
+ const resolveNative = useCallback(
+ (emoji: EmojiDataEmoji) =>
+ emoji.skins[skinToneIndex]?.native ?? emoji.skins[0]?.native ?? '',
+ [skinToneIndex],
+ );
+
+ const selectEmoji = useCallback(
+ (emoji: EmojiDataEmoji) => {
+ const native = resolveNative(emoji);
+ if (native) onEmojiSelect({ id: emoji.id, name: emoji.name, native });
+ },
+ [onEmojiSelect, resolveNative],
+ );
+
+ const setActiveCategory = useCallback(
+ (categoryId: string) => setActiveCategoryId(categoryId),
+ [],
+ );
+
+ const requestScrollToCategory = useCallback((categoryId: string) => {
+ setQuery(''); // navigating a category exits search
+ setActiveCategoryId(categoryId);
+ // A "scroll here" signal for the grid; the nonce re-fires a repeat of the same id.
+ setScrollTarget((prev) => ({ categoryId, nonce: (prev?.nonce ?? 0) + 1 }));
+ }, []);
+
+ const contextValue = useMemo(
+ () => ({
+ activeCategoryId: activeCategoryId ?? categories[0]?.id ?? '',
+ categories,
+ isSearching,
+ query,
+ requestScrollToCategory,
+ resolveNative,
+ retry,
+ scrollTarget,
+ searchResults: searchedEmojis,
+ selectEmoji,
+ setActiveCategory,
+ setQuery,
+ setSkinTone: onSkinToneChange ?? noop,
+ skinToneIndex,
+ skinTones: SKIN_TONES,
+ status,
+ }),
+ [
+ activeCategoryId,
+ categories,
+ isSearching,
+ onSkinToneChange,
+ query,
+ requestScrollToCategory,
+ resolveNative,
+ retry,
+ scrollTarget,
+ searchedEmojis,
+ selectEmoji,
+ setActiveCategory,
+ skinToneIndex,
+ status,
+ ],
+ );
+
+ const previewValue = useMemo(
+ () => ({ previewedEmoji, setPreviewedEmoji }),
+ [previewedEmoji],
+ );
+
+ // The cold subset the default cell subscribes to, so the grid's ~hundreds of cells
+ // don't re-render on hot state (scroll-spy active category, live query, scroll target).
+ const cellValue = useMemo(
+ () => ({ resolveNative, selectEmoji }),
+ [resolveNative, selectEmoji],
+ );
+
+ return (
+
+
+
+ {
+ if (event.key === 'Escape') {
+ event.stopPropagation();
+ onClose?.();
+ }
+ }}
+ role='dialog'
+ style={style}
+ >
+ {status === 'ready' ? (
+ children
+ ) : status === 'error' ? (
+
+
+ {t('Failed to load emojis')}
+
+
+ {t('Retry')}
+
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+};
diff --git a/src/plugins/Emojis/components/EmptyResults.tsx b/src/plugins/Emojis/components/EmptyResults.tsx
new file mode 100644
index 000000000..7a6557d67
--- /dev/null
+++ b/src/plugins/Emojis/components/EmptyResults.tsx
@@ -0,0 +1,24 @@
+import { useTranslationContext } from '../../../context';
+
+export type EmptyResultsProps = {
+ /** Native glyph shown above the "no results" text (from the `noResultsEmoji` option). */
+ emoji?: string;
+};
+
+/**
+ * Shown in place of the emoji grid when a search yields no matches.
+ */
+export const EmptyResults = ({ emoji }: EmptyResultsProps) => {
+ const { t } = useTranslationContext();
+
+ return (
+
+ {emoji ? (
+
+ {emoji}
+
+ ) : null}
+ {t('No emoji found')}
+
+ );
+};
diff --git a/src/plugins/Emojis/components/PreviewPane.tsx b/src/plugins/Emojis/components/PreviewPane.tsx
new file mode 100644
index 000000000..aedca5708
--- /dev/null
+++ b/src/plugins/Emojis/components/PreviewPane.tsx
@@ -0,0 +1,32 @@
+import { useEmojiPickerContext } from '../context/EmojiPickerContext';
+import { useEmojiPickerPreviewContext } from '../context/EmojiPickerPreviewContext';
+import { useTranslationContext } from '../../../context';
+
+/**
+ * Footer preview of the hovered/focused emoji: a large glyph, its name, and its
+ * `:shortcode:` (so users learn the token that drives `:` autocomplete). Falls back to
+ * a "Pick an emoji…" placeholder (like emoji-mart) so the footer is never empty. Reads
+ * the previewed emoji from the internal preview context (kept out of the public context
+ * so hovering does not re-render the emoji grid).
+ */
+export const PreviewPane = () => {
+ const { t } = useTranslationContext();
+ const { resolveNative } = useEmojiPickerContext();
+ const { previewedEmoji } = useEmojiPickerPreviewContext();
+
+ return (
+
+
+ {previewedEmoji ? resolveNative(previewedEmoji) : '☝️'}
+
+
+
+ {previewedEmoji ? previewedEmoji.name : t('Pick an emoji…')}
+
+ {previewedEmoji ? (
+ {`:${previewedEmoji.id}:`}
+ ) : null}
+
+
+ );
+};
diff --git a/src/plugins/Emojis/components/SearchInput.tsx b/src/plugins/Emojis/components/SearchInput.tsx
new file mode 100644
index 000000000..15bf8530d
--- /dev/null
+++ b/src/plugins/Emojis/components/SearchInput.tsx
@@ -0,0 +1,68 @@
+import { type KeyboardEvent, useEffect, useRef } from 'react';
+import { Button, IconSearch, IconXCircle, VisuallyHidden } from '../../../components';
+import { useStableId } from '../../../components/UtilityComponents/useStableId';
+import { useEmojiPickerContext } from '../context/EmojiPickerContext';
+import { useTranslationContext } from '../../../context';
+
+export type SearchInputProps = {
+ /** Focus the input on mount when the picker opens (default `true`). */
+ autoFocus?: boolean;
+};
+
+/**
+ * Search box for the emoji picker. Mirrors the SDK's SearchBar structure (icon +
+ * labelled input + clear button) and receives focus when the picker opens. Reads/reports
+ * the query through context; ArrowDown moves focus to the first emoji cell within the
+ * enclosing picker dialog (the default grid's DOM contract).
+ */
+export const SearchInput = ({ autoFocus = true }: SearchInputProps) => {
+ const { t } = useTranslationContext();
+ const { query, setQuery } = useEmojiPickerContext();
+ const inputId = useStableId();
+ const inputRef = useRef(null);
+
+ useEffect(() => {
+ if (autoFocus) inputRef.current?.focus();
+ }, [autoFocus]);
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ if (event.key !== 'ArrowDown') return;
+ event.preventDefault();
+ const dialog = event.currentTarget.closest('[role="dialog"]');
+ dialog?.querySelector('.str-chat__emoji-picker__emoji')?.focus();
+ };
+
+ return (
+
+
+ {t('Search emoji')}
+
+
+ setQuery(event.target.value)}
+ onKeyDown={onKeyDown}
+ placeholder={t('Search emoji')}
+ ref={inputRef}
+ type='text'
+ value={query}
+ />
+ {query ? (
+ setQuery('')}
+ size='xs'
+ type='button'
+ variant='secondary'
+ >
+
+
+ ) : null}
+
+ );
+};
diff --git a/src/plugins/Emojis/components/SkinToneSelector.tsx b/src/plugins/Emojis/components/SkinToneSelector.tsx
new file mode 100644
index 000000000..5b579a320
--- /dev/null
+++ b/src/plugins/Emojis/components/SkinToneSelector.tsx
@@ -0,0 +1,116 @@
+import { type KeyboardEvent, useEffect, useRef, useState } from 'react';
+import clsx from 'clsx';
+import { useEmojiPickerContext } from '../context/EmojiPickerContext';
+import { useTranslationContext } from '../../../context';
+
+const ARROW_KEYS = ['ArrowRight', 'ArrowLeft', 'ArrowDown', 'ArrowUp', 'Home', 'End'];
+
+/**
+ * Skin-tone picker rendered in the footer. Collapsed to the active tone; expands to a
+ * WAI-ARIA radiogroup: focus moves onto the checked tone on open, a roving tabindex keeps
+ * one tone tab-reachable, arrow/Home/End keys move the selection (selection follows
+ * focus), and Escape collapses back to the toggle without closing the whole picker.
+ * Reads the active tone + available tones from context and reports changes via
+ * `setSkinTone`.
+ */
+export const SkinToneSelector = () => {
+ const { t } = useTranslationContext();
+ const { setSkinTone, skinToneIndex, skinTones } = useEmojiPickerContext();
+ const maxIndex = skinTones.length - 1;
+ const [expanded, setExpanded] = useState(false);
+ const toggleRef = useRef(null);
+ const groupRef = useRef(null);
+ const returnFocusToToggle = useRef(false);
+ const activeTone = skinTones[skinToneIndex] ?? skinTones[0];
+
+ const radios = () =>
+ Array.from(
+ groupRef.current?.querySelectorAll('[role="radio"]') ?? [],
+ );
+
+ useEffect(() => {
+ if (expanded) {
+ // Move focus into the group, onto the checked tone, when it opens.
+ radios()[skinToneIndex]?.focus();
+ } else if (returnFocusToToggle.current) {
+ returnFocusToToggle.current = false;
+ toggleRef.current?.focus();
+ }
+ // Focus is managed on open/close only; arrow navigation focuses the target directly.
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [expanded]);
+
+ if (!expanded) {
+ return (
+ setExpanded(true)}
+ ref={toggleRef}
+ type='button'
+ >
+ {activeTone.glyph}
+
+ );
+ }
+
+ const collapse = (returnFocus: boolean) => {
+ returnFocusToToggle.current = returnFocus;
+ setExpanded(false);
+ };
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ if (event.key === 'Escape') {
+ event.stopPropagation(); // collapse the group, not the whole picker
+ collapse(true);
+ return;
+ }
+ if (!ARROW_KEYS.includes(event.key)) return;
+ event.preventDefault();
+
+ let next = skinToneIndex;
+ if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {
+ next = skinToneIndex >= maxIndex ? 0 : skinToneIndex + 1;
+ } else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {
+ next = skinToneIndex <= 0 ? maxIndex : skinToneIndex - 1;
+ } else if (event.key === 'Home') {
+ next = 0;
+ } else if (event.key === 'End') {
+ next = maxIndex;
+ }
+
+ // All tones are mounted, so focus the target now; selection follows focus.
+ radios()[next]?.focus();
+ setSkinTone(next);
+ };
+
+ return (
+
+ {skinTones.map((tone, index) => (
+ {
+ setSkinTone(index);
+ collapse(true);
+ }}
+ role='radio'
+ tabIndex={index === skinToneIndex ? 0 : -1}
+ type='button'
+ >
+ {tone.glyph}
+
+ ))}
+
+ );
+};
diff --git a/src/plugins/Emojis/components/__tests__/EmojiButton.test.tsx b/src/plugins/Emojis/components/__tests__/EmojiButton.test.tsx
new file mode 100644
index 000000000..65974d9f5
--- /dev/null
+++ b/src/plugins/Emojis/components/__tests__/EmojiButton.test.tsx
@@ -0,0 +1,117 @@
+import { useMemo, useState } from 'react';
+import { fireEvent, render, screen } from '@testing-library/react';
+import { EmojiButton } from '../EmojiButton';
+import {
+ type EmojiPickerContextValue,
+ EmojiPickerProvider,
+} from '../../context/EmojiPickerContext';
+import { EmojiPickerCellProvider } from '../../context/EmojiPickerCellContext';
+import { EmojiPickerPreviewProvider } from '../../context/EmojiPickerPreviewContext';
+
+type Emoji = { skins: { native: string }[] };
+
+const emoji = (id: string, native: string, name = id) => ({
+ id,
+ keywords: [],
+ name,
+ skins: [{ native, unified: '' }],
+ version: 1,
+});
+
+const STABLE_EMOJI = emoji('grinning', '😀', 'Grinning');
+const selectEmoji = vi.fn();
+// Called once per EmojiButton render (in its body via resolveNative), so its call count
+// is a render counter that survives the resolveNative reference changing (skin tone).
+const renderProbe = vi.fn();
+const countingResolveNative = (e: Emoji) => {
+ renderProbe();
+ return e.skins[0]?.native ?? '';
+};
+
+const previewValue = { previewedEmoji: null, setPreviewedEmoji: vi.fn() };
+
+const baseMain = (activeCategoryId: string): EmojiPickerContextValue => ({
+ activeCategoryId,
+ categories: [],
+ isSearching: false,
+ query: '',
+ requestScrollToCategory: vi.fn(),
+ resolveNative: countingResolveNative,
+ retry: vi.fn(),
+ scrollTarget: null,
+ searchResults: null,
+ selectEmoji,
+ setActiveCategory: vi.fn(),
+ setQuery: vi.fn(),
+ setSkinTone: vi.fn(),
+ skinToneIndex: 0,
+ skinTones: [],
+ status: 'ready',
+});
+
+// `resolveNative`/`selectEmoji` live in BOTH the public context (custom grids) and the
+// cell context (the default cell); a cell must subscribe to the cold cell context so hot
+// state changes never reach it. `scroll-spy` mutates only hot public state; `skin-tone`
+// bumps the tone the cell resolver closes over, changing its identity — mirroring Root,
+// where resolveNative is a useCallback keyed on skinToneIndex.
+function Harness() {
+ const [hotCategory, setHotCategory] = useState('people');
+ const [tone, setTone] = useState(0);
+ const mainValue = useMemo(() => baseMain(hotCategory), [hotCategory]);
+ const cellResolveNative = useMemo(
+ () => (e: Emoji) => {
+ renderProbe();
+ return e.skins[tone]?.native ?? e.skins[0]?.native ?? '';
+ },
+ [tone],
+ );
+ const cellValue = useMemo(
+ () => ({ resolveNative: cellResolveNative, selectEmoji }),
+ [cellResolveNative],
+ );
+
+ return (
+
+
+
+ setHotCategory((c) => (c === 'people' ? 'flags' : 'people'))}
+ type='button'
+ >
+ scroll-spy
+
+ setTone((v) => v + 1)} type='button'>
+ skin-tone
+
+
+
+
+
+ );
+}
+
+describe('EmojiButton context subscription', () => {
+ beforeEach(() => {
+ renderProbe.mockClear();
+ });
+
+ it('does not re-render when hot picker state (scroll-spy active category) changes', () => {
+ render( );
+ const initial = renderProbe.mock.calls.length;
+ expect(initial).toBeGreaterThan(0);
+
+ fireEvent.click(screen.getByRole('button', { name: 'scroll-spy' }));
+
+ // The cell reads none of the hot fields, so a scroll-spy update must not re-render it.
+ expect(renderProbe).toHaveBeenCalledTimes(initial);
+ });
+
+ it('re-renders when the resolved glyph changes (skin tone)', () => {
+ render( );
+ const initial = renderProbe.mock.calls.length;
+
+ fireEvent.click(screen.getByRole('button', { name: 'skin-tone' }));
+
+ expect(renderProbe.mock.calls.length).toBeGreaterThan(initial);
+ });
+});
diff --git a/src/plugins/Emojis/components/__tests__/EmojiGrid.test.tsx b/src/plugins/Emojis/components/__tests__/EmojiGrid.test.tsx
new file mode 100644
index 000000000..df4c04a08
--- /dev/null
+++ b/src/plugins/Emojis/components/__tests__/EmojiGrid.test.tsx
@@ -0,0 +1,170 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+
+// Capture the Virtuoso scroll callbacks + imperative scroll so scroll-spy and
+// scroll-to-category are testable, and render items synchronously so the browse view's
+// a11y tree is assertable (jsdom has no layout).
+const { virtuoso } = vi.hoisted(() => ({
+ virtuoso: { scrollToIndex: vi.fn() } as {
+ atBottomStateChange?: (atBottom: boolean) => void;
+ rangeChanged?: (range: { endIndex: number; startIndex: number }) => void;
+ scrollToIndex: ReturnType;
+ },
+}));
+
+vi.mock('react-virtuoso', async () => {
+ const { forwardRef, useImperativeHandle } = await import('react');
+ return {
+ Virtuoso: forwardRef(function Virtuoso(
+ {
+ atBottomStateChange,
+ data = [],
+ itemContent,
+ rangeChanged,
+ }: {
+ atBottomStateChange?: (atBottom: boolean) => void;
+ data?: unknown[];
+ itemContent?: (index: number, item: unknown) => React.ReactNode;
+ rangeChanged?: (range: { endIndex: number; startIndex: number }) => void;
+ },
+ ref,
+ ) {
+ virtuoso.atBottomStateChange = atBottomStateChange;
+ virtuoso.rangeChanged = rangeChanged;
+ useImperativeHandle(ref, () => ({ scrollToIndex: virtuoso.scrollToIndex }));
+ return (
+
+ {data.map((item, index) => (
+ {itemContent?.(index, item)}
+ ))}
+
+ );
+ }),
+ };
+});
+
+const { ctx, preview } = vi.hoisted(() => ({
+ ctx: {} as Record,
+ preview: { previewedEmoji: null, setPreviewedEmoji: vi.fn() },
+}));
+vi.mock('../../context/EmojiPickerContext', () => ({
+ useEmojiPickerContext: () => ctx,
+}));
+vi.mock('../../context/EmojiPickerCellContext', () => ({
+ useEmojiPickerCellContext: () => ctx,
+}));
+vi.mock('../../context/EmojiPickerPreviewContext', () => ({
+ useEmojiPickerPreviewContext: () => preview,
+}));
+vi.mock('../../../../context', () => ({
+ useTranslationContext: () => ({ t: (key: string) => key }),
+}));
+
+import { EmojiGrid, type EmojiPickerCategory } from '../EmojiGrid';
+
+const emoji = (id: string, native: string, name = id) => ({
+ id,
+ keywords: [],
+ name,
+ skins: [{ native, unified: '' }],
+ version: 1,
+});
+
+const base = () => ({
+ categories: [] as EmojiPickerCategory[],
+ isSearching: false,
+ resolveNative: (e: { skins: { native: string }[] }) => e.skins[0]?.native ?? '',
+ scrollTarget: null as { categoryId: string; nonce: number } | null,
+ searchResults: null,
+ selectEmoji: vi.fn(),
+ setActiveCategory: vi.fn(),
+});
+
+beforeEach(() => {
+ Object.assign(ctx, base());
+});
+
+describe('EmojiGrid browse view', () => {
+ it('renders emojis as labeled buttons under labeled category regions, with no orphaned grid roles', () => {
+ ctx.categories = [
+ {
+ emojis: [emoji('grinning', '😀', 'Grinning')],
+ id: 'people',
+ label: 'Smileys & People',
+ },
+ ];
+ render( );
+
+ // Native button semantics — no invalid ARIA grid/row/gridcell in the virtualized view.
+ expect(screen.queryAllByRole('grid')).toHaveLength(0);
+ expect(screen.queryAllByRole('row')).toHaveLength(0);
+ expect(screen.queryAllByRole('gridcell')).toHaveLength(0);
+ expect(screen.getByRole('button', { name: 'Grinning' })).toBeInTheDocument();
+ expect(screen.getByRole('region', { name: 'Smileys & People' })).toBeInTheDocument();
+ });
+});
+
+describe('EmojiGrid scroll-spy', () => {
+ beforeEach(() => {
+ ctx.categories = [
+ { emojis: [emoji('grinning', '😀')], id: 'people', label: 'People' },
+ { emojis: [emoji('checkered_flag', '🏁')], id: 'flags', label: 'Flags' },
+ ];
+ });
+
+ it('marks the category at the top of the viewport active as the list scrolls', () => {
+ render( );
+ virtuoso.rangeChanged?.({ endIndex: 1, startIndex: 1 });
+ expect(ctx.setActiveCategory).toHaveBeenLastCalledWith('flags');
+ });
+
+ it('pins the last category active at the bottom, even when a short final category never reaches the top', () => {
+ render( );
+ virtuoso.rangeChanged?.({ endIndex: 1, startIndex: 0 });
+ virtuoso.atBottomStateChange?.(true);
+ expect(ctx.setActiveCategory).toHaveBeenLastCalledWith('flags');
+ // Range changes while pinned at the bottom must not steal the active category back.
+ virtuoso.rangeChanged?.({ endIndex: 1, startIndex: 0 });
+ expect(ctx.setActiveCategory).toHaveBeenLastCalledWith('flags');
+ });
+});
+
+describe('EmojiGrid scroll-to-category', () => {
+ beforeEach(() => {
+ // Run the scroll's requestAnimationFrame defer synchronously so it's assertable.
+ vi.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => {
+ cb(0);
+ return 0;
+ });
+ vi.spyOn(window, 'cancelAnimationFrame').mockImplementation(() => undefined);
+ virtuoso.scrollToIndex.mockClear();
+ });
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ it('scrolls to a requested category once, and not when categories change', () => {
+ ctx.categories = [
+ { emojis: [emoji('grinning', '😀')], id: 'people', label: 'People' },
+ { emojis: [emoji('checkered_flag', '🏁')], id: 'flags', label: 'Flags' },
+ ];
+ ctx.scrollTarget = { categoryId: 'flags', nonce: 1 };
+ const { rerender } = render( );
+ expect(virtuoso.scrollToIndex).toHaveBeenCalledTimes(1);
+ expect(virtuoso.scrollToIndex).toHaveBeenLastCalledWith({ align: 'start', index: 1 });
+
+ // A categories change (e.g. frequently-used updating after a selection) must NOT
+ // re-fire the scroll — otherwise the grid jumps back to the last-requested category.
+ ctx.categories = [
+ { emojis: [emoji('clock', '🕐')], id: 'frequent', label: 'Frequently used' },
+ ...(ctx.categories as EmojiPickerCategory[]),
+ ];
+ rerender( );
+ expect(virtuoso.scrollToIndex).toHaveBeenCalledTimes(1);
+
+ // A fresh scroll request (new nonce) does scroll again.
+ ctx.scrollTarget = { categoryId: 'flags', nonce: 2 };
+ rerender( );
+ expect(virtuoso.scrollToIndex).toHaveBeenCalledTimes(2);
+ });
+});
diff --git a/src/plugins/Emojis/components/__tests__/EmojiPickerPanel.test.tsx b/src/plugins/Emojis/components/__tests__/EmojiPickerPanel.test.tsx
new file mode 100644
index 000000000..180d27ef8
--- /dev/null
+++ b/src/plugins/Emojis/components/__tests__/EmojiPickerPanel.test.tsx
@@ -0,0 +1,199 @@
+import React from 'react';
+import { fireEvent, render, screen, waitFor } from '@testing-library/react';
+
+const { hookState } = vi.hoisted(() => ({
+ hookState: {
+ data: null as unknown,
+ error: false,
+ retry: vi.fn(),
+ },
+}));
+
+vi.mock('../../hooks/useEmojiPickerState', () => ({
+ useEmojiPickerState: () => hookState,
+}));
+
+vi.mock('../../../../context', () => ({
+ useTranslationContext: () => ({ t: (key: string) => key }),
+}));
+
+// Mock ONLY react-virtuoso (it renders nothing without layout in jsdom) and render items
+// eagerly, so the panel exercises the REAL slots (nav, search, grid, preview, skin tone)
+// against real context — an integration harness, not per-slot mocks.
+vi.mock('react-virtuoso', () => ({
+ Virtuoso: ({
+ data = [],
+ itemContent,
+ }: {
+ data?: unknown[];
+ itemContent?: (index: number, item: unknown) => React.ReactNode;
+ }) => (
+
+ {data.map((item, index) => (
+ {itemContent?.(index, item)}
+ ))}
+
+ ),
+}));
+
+import { EmojiPickerPanel } from '../EmojiPickerPanel';
+import { themeClassName } from '../EmojiPickerRoot';
+
+const DATA = {
+ aliases: {},
+ categories: [
+ { emojis: ['grinning', 'smile'], id: 'people' },
+ { emojis: ['dog'], id: 'nature' },
+ ],
+ emojis: {
+ dog: {
+ id: 'dog',
+ keywords: [],
+ name: 'Dog',
+ skins: [{ native: '🐶', unified: '1f436' }],
+ version: 1,
+ },
+ grinning: {
+ id: 'grinning',
+ keywords: [],
+ name: 'Grinning',
+ skins: [{ native: '😀', unified: '1f600' }],
+ version: 1,
+ },
+ smile: {
+ id: 'smile',
+ keywords: [],
+ name: 'Smile',
+ skins: [{ native: '😄', unified: '1f604' }],
+ version: 1,
+ },
+ },
+};
+
+const emojiButton = (name: string) => screen.queryByRole('button', { name });
+
+// The picker's theme CSS keys off the class this maps to: a forced `light`/`dark` must
+// emit an SDK theme class on the panel root so the forced-light variable override in
+// EmojiPicker.scss can win over an ancestor `.str-chat__theme-dark`.
+describe('themeClassName', () => {
+ it('maps forced light/dark to the SDK theme class, and nothing for auto/undefined', () => {
+ expect(themeClassName('light')).toBe('str-chat__theme-light');
+ expect(themeClassName('dark')).toBe('str-chat__theme-dark');
+ expect(themeClassName('auto')).toBeUndefined();
+ expect(themeClassName(undefined)).toBeUndefined();
+ });
+});
+
+describe('EmojiPickerPanel dataset loading', () => {
+ beforeEach(() => {
+ hookState.data = null;
+ hookState.error = false;
+ hookState.retry.mockClear();
+ });
+
+ it('renders a recoverable error (not a permanent spinner) when the dataset fails to load', () => {
+ hookState.error = true;
+ render( {}} />);
+
+ // No stuck aria-busy loading region…
+ expect(document.querySelector('[aria-busy="true"]')).toBeNull();
+ // …an announced error with a working retry instead.
+ expect(screen.getByRole('alert')).toBeInTheDocument();
+ fireEvent.click(screen.getByRole('button', { name: 'Retry' }));
+ expect(hookState.retry).toHaveBeenCalledTimes(1);
+ });
+
+ it('shows the loading region while the dataset is still loading', () => {
+ render( {}} />);
+
+ expect(document.querySelector('[aria-busy="true"]')).toBeInTheDocument();
+ expect(screen.queryByRole('alert')).not.toBeInTheDocument();
+ });
+});
+
+// Integration: the default composition rendered with real slots + real context.
+describe('EmojiPickerPanel (default composition)', () => {
+ beforeEach(() => {
+ hookState.data = DATA;
+ hookState.error = false;
+ });
+
+ it('excludes exceptEmojis from the grid, keeping the rest', () => {
+ render( {}} />);
+ expect(emojiButton('Grinning')).toBeInTheDocument();
+ expect(emojiButton('Dog')).toBeInTheDocument();
+ expect(emojiButton('Smile')).not.toBeInTheDocument();
+ });
+
+ it('shows only the requested categories, in order', () => {
+ render( {}} />);
+ expect(screen.getAllByRole('tab')).toHaveLength(1);
+ expect(emojiButton('Dog')).toBeInTheDocument();
+ expect(emojiButton('Grinning')).not.toBeInTheDocument();
+ });
+
+ it('does not autofocus the search input when autoFocus is false', () => {
+ render( {}} />);
+ expect(screen.getByPlaceholderText('Search emoji')).not.toHaveFocus();
+ });
+
+ it('moves focus from the search box into the grid on ArrowDown', () => {
+ render( {}} />);
+ fireEvent.keyDown(screen.getByPlaceholderText('Search emoji'), { key: 'ArrowDown' });
+ expect(screen.getByRole('button', { name: 'Grinning' })).toHaveFocus();
+ });
+
+ it('activates a category when its nav tab is clicked (nav ↔ grid via context)', () => {
+ render( {}} />);
+ const nature = screen.getByRole('tab', { name: 'Animals & Nature' });
+ expect(nature).toHaveAttribute('aria-selected', 'false');
+
+ fireEvent.click(nature);
+ expect(nature).toHaveAttribute('aria-selected', 'true');
+ expect(screen.getByRole('tab', { name: 'Smileys & People' })).toHaveAttribute(
+ 'aria-selected',
+ 'false',
+ );
+ });
+
+ it('reports the selected emoji (with its resolved native glyph)', () => {
+ const onEmojiSelect = vi.fn();
+ render( );
+
+ fireEvent.click(screen.getByRole('button', { name: 'Grinning' }));
+ expect(onEmojiSelect).toHaveBeenCalledWith({
+ id: 'grinning',
+ name: 'Grinning',
+ native: '😀',
+ });
+ });
+
+ it('previews the hovered emoji, falling back to a placeholder when nothing is hovered', () => {
+ render( {}} />);
+
+ expect(screen.getByText('Pick an emoji…')).toBeInTheDocument();
+
+ fireEvent.mouseEnter(screen.getByRole('button', { name: 'Grinning' }));
+ expect(screen.getByText('Grinning')).toBeInTheDocument();
+ expect(screen.getByText(':grinning:')).toBeInTheDocument();
+ expect(screen.queryByText('Pick an emoji…')).not.toBeInTheDocument();
+ });
+
+ it('filters to matching emoji while searching, and restores browse on clear', async () => {
+ render( {}} />);
+ const input = screen.getByPlaceholderText('Search emoji');
+
+ fireEvent.change(input, { target: { value: 'grin' } });
+ // Search is debounced; the non-matching emoji drops out once it catches up.
+ await waitFor(() => expect(emojiButton('Dog')).not.toBeInTheDocument());
+ expect(emojiButton('Grinning')).toBeInTheDocument();
+ // No category is active while searching.
+ expect(screen.getByRole('tab', { name: 'Smileys & People' })).toHaveAttribute(
+ 'aria-selected',
+ 'false',
+ );
+
+ fireEvent.change(input, { target: { value: '' } });
+ expect(emojiButton('Dog')).toBeInTheDocument();
+ });
+});
diff --git a/src/plugins/Emojis/components/__tests__/SkinToneSelector.test.tsx b/src/plugins/Emojis/components/__tests__/SkinToneSelector.test.tsx
new file mode 100644
index 000000000..d7fdff8e6
--- /dev/null
+++ b/src/plugins/Emojis/components/__tests__/SkinToneSelector.test.tsx
@@ -0,0 +1,77 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+import { SKIN_TONES } from '../skinTones';
+
+const { ctx } = vi.hoisted(() => ({
+ ctx: {
+ setSkinTone: vi.fn(),
+ skinToneIndex: 0,
+ skinTones: [] as { glyph: string; labelKey: string }[],
+ },
+}));
+vi.mock('../../context/EmojiPickerContext', () => ({
+ useEmojiPickerContext: () => ctx,
+}));
+vi.mock('../../../../context', () => ({
+ useTranslationContext: () => ({ t: (key: string) => key }),
+}));
+
+import { SkinToneSelector } from '../SkinToneSelector';
+
+const setup = (skinToneIndex: number) => {
+ ctx.skinToneIndex = skinToneIndex;
+ ctx.skinTones = SKIN_TONES;
+ vi.spyOn(ctx, 'setSkinTone').mockImplementation();
+ return ctx.setSkinTone;
+};
+
+const openGroup = () =>
+ fireEvent.click(screen.getByRole('button', { name: 'aria/Choose default skin tone' }));
+
+describe('SkinToneSelector radiogroup keyboard navigation', () => {
+ it('moves focus to the checked tone when the group opens, with roving tabindex', () => {
+ setup(2);
+ render( );
+ openGroup();
+
+ const radios = screen.getAllByRole('radio');
+ expect(radios[2]).toHaveFocus();
+ expect(radios[2]).toHaveAttribute('tabindex', '0');
+ expect(radios[0]).toHaveAttribute('tabindex', '-1');
+ });
+
+ it('moves the selection with Arrow/Home/End keys (selection follows focus)', () => {
+ const setSkinTone = setup(0);
+ render( );
+ openGroup();
+
+ const group = screen.getByRole('radiogroup');
+ fireEvent.keyDown(group, { key: 'ArrowRight' });
+ expect(setSkinTone).toHaveBeenLastCalledWith(1);
+ fireEvent.keyDown(group, { key: 'ArrowLeft' });
+ expect(setSkinTone).toHaveBeenLastCalledWith(5); // wraps from 0 to the last tone
+ fireEvent.keyDown(group, { key: 'End' });
+ expect(setSkinTone).toHaveBeenLastCalledWith(5);
+ fireEvent.keyDown(group, { key: 'Home' });
+ expect(setSkinTone).toHaveBeenLastCalledWith(0);
+ });
+
+ it('collapses on Escape without bubbling to close the whole picker', () => {
+ setup(0);
+ const onOuterKeyDown = vi.fn();
+ render(
+
+
+
,
+ );
+ openGroup();
+
+ fireEvent.keyDown(screen.getByRole('radiogroup'), { key: 'Escape' });
+
+ expect(screen.queryByRole('radiogroup')).not.toBeInTheDocument();
+ expect(
+ screen.getByRole('button', { name: 'aria/Choose default skin tone' }),
+ ).toBeInTheDocument();
+ // Escape stayed inside the selector — it must not reach the picker's Escape handler.
+ expect(onOuterKeyDown).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/plugins/Emojis/components/__tests__/frequentlyUsed.test.ts b/src/plugins/Emojis/components/__tests__/frequentlyUsed.test.ts
new file mode 100644
index 000000000..46e4bbf21
--- /dev/null
+++ b/src/plugins/Emojis/components/__tests__/frequentlyUsed.test.ts
@@ -0,0 +1,45 @@
+import { FREQUENTLY_USED_LIMIT, resolveFrequentlyUsedEmoji } from '../frequentlyUsed';
+import type { EmojiData, EmojiDataEmoji } from '../../data';
+
+const makeEmoji = (id: string): EmojiDataEmoji => ({
+ id,
+ keywords: [],
+ name: id,
+ skins: [{ native: id, unified: id }],
+ version: 1,
+});
+
+const data = {
+ aliases: {},
+ categories: [],
+ emojis: Object.fromEntries(
+ Array.from({ length: 30 }, (_, i) => `e${i}`).map((id) => [id, makeEmoji(id)]),
+ ),
+} as unknown as EmojiData;
+
+describe('resolveFrequentlyUsedEmoji', () => {
+ it('caps the frequently-used list to a single row so it never wraps', () => {
+ const ids = Array.from({ length: 30 }, (_, i) => `e${i}`);
+ const result = resolveFrequentlyUsedEmoji(data, ids);
+
+ expect(result).toHaveLength(FREQUENTLY_USED_LIMIT);
+ });
+
+ it('preserves most-recent-first order', () => {
+ const result = resolveFrequentlyUsedEmoji(data, ['e2', 'e0', 'e1']);
+
+ expect(result.map((emoji) => emoji.id)).toEqual(['e2', 'e0', 'e1']);
+ });
+
+ it('drops ids missing from the dataset', () => {
+ const result = resolveFrequentlyUsedEmoji(data, ['e0', 'does-not-exist', 'e1']);
+
+ expect(result.map((emoji) => emoji.id)).toEqual(['e0', 'e1']);
+ });
+
+ it('honors an explicit limit (perLine × maxFrequentRows)', () => {
+ const ids = Array.from({ length: 30 }, (_, i) => `e${i}`);
+
+ expect(resolveFrequentlyUsedEmoji(data, ids, 14)).toHaveLength(14);
+ });
+});
diff --git a/src/plugins/Emojis/components/categories.ts b/src/plugins/Emojis/components/categories.ts
new file mode 100644
index 000000000..b006a47dd
--- /dev/null
+++ b/src/plugins/Emojis/components/categories.ts
@@ -0,0 +1,15 @@
+// Category metadata for the emoji picker navigation. We use representative native
+// emoji glyphs for the nav tabs (avoids shipping ~8 additional SVG icon assets)
+// plus an i18n label key per category. Keys match the vendored dataset's category
+// ids, with `frequent` reserved for the synthetic "frequently used" section.
+export const EMOJI_CATEGORY_META: Record = {
+ activity: { glyph: '⚽', labelKey: 'Activities' },
+ flags: { glyph: '🏁', labelKey: 'Flags' },
+ foods: { glyph: '🍎', labelKey: 'Food & Drink' },
+ frequent: { glyph: '🕐', labelKey: 'Frequently used' },
+ nature: { glyph: '🌸', labelKey: 'Animals & Nature' },
+ objects: { glyph: '💡', labelKey: 'Objects' },
+ people: { glyph: '😀', labelKey: 'Smileys & People' },
+ places: { glyph: '✈️', labelKey: 'Travel & Places' },
+ symbols: { glyph: '🔣', labelKey: 'Symbols' },
+};
diff --git a/src/plugins/Emojis/components/frequentlyUsed.ts b/src/plugins/Emojis/components/frequentlyUsed.ts
new file mode 100644
index 000000000..ab37a9456
--- /dev/null
+++ b/src/plugins/Emojis/components/frequentlyUsed.ts
@@ -0,0 +1,27 @@
+import type { EmojiData, EmojiDataEmoji } from '../data';
+
+/**
+ * How many recently-used emoji the "frequently used" section shows. Matches the
+ * default grid's column count, so the section stays a single row.
+ *
+ * Kept in sync with the fixed column count in EmojiPicker.scss
+ * (`[data-category-id='frequent'] .str-chat__emoji-picker__category-emojis`): the
+ * slice caps the item count and the CSS pins the columns, together guaranteeing one
+ * row regardless of how many emoji have been used.
+ */
+export const FREQUENTLY_USED_LIMIT = 9;
+
+/**
+ * Resolves an ordered (most-recent-first) list of emoji ids to dataset entries for the
+ * "frequently used" section: drops ids missing from the dataset and caps the result to
+ * a single row (`FREQUENTLY_USED_LIMIT`).
+ */
+export const resolveFrequentlyUsedEmoji = (
+ data: EmojiData,
+ frequentlyUsedIds: string[],
+ limit = FREQUENTLY_USED_LIMIT,
+): EmojiDataEmoji[] =>
+ frequentlyUsedIds
+ .map((id) => data.emojis[id])
+ .filter(Boolean)
+ .slice(0, limit);
diff --git a/src/plugins/Emojis/components/index.ts b/src/plugins/Emojis/components/index.ts
new file mode 100644
index 000000000..e6d3637f2
--- /dev/null
+++ b/src/plugins/Emojis/components/index.ts
@@ -0,0 +1,3 @@
+export * from './EmojiPickerPanel';
+export * from './EmojiPickerRoot';
+export type { EmojiPickerCategory } from './EmojiGrid';
diff --git a/src/plugins/Emojis/components/skinTones.ts b/src/plugins/Emojis/components/skinTones.ts
new file mode 100644
index 000000000..3fd248258
--- /dev/null
+++ b/src/plugins/Emojis/components/skinTones.ts
@@ -0,0 +1,15 @@
+// Skin-tone swatches for the picker. Index 0 is the default (no modifier); 1–5 are
+// light → dark. The glyph is a hand emoji carrying the matching Fitzpatrick skin
+// tone modifier, mirroring emoji-mart's selector. `labelKey` is translated via t().
+export type SkinTone = { glyph: string; labelKey: string };
+
+export const SKIN_TONES: SkinTone[] = [
+ { glyph: '✋', labelKey: 'Default' },
+ { glyph: '✋🏻', labelKey: 'Light' },
+ { glyph: '✋🏼', labelKey: 'Medium-Light' },
+ { glyph: '✋🏽', labelKey: 'Medium' },
+ { glyph: '✋🏾', labelKey: 'Medium-Dark' },
+ { glyph: '✋🏿', labelKey: 'Dark' },
+];
+
+export const MAX_SKIN_TONE_INDEX = SKIN_TONES.length - 1;
diff --git a/src/plugins/Emojis/context/EmojiPickerCellContext.tsx b/src/plugins/Emojis/context/EmojiPickerCellContext.tsx
new file mode 100644
index 000000000..544248b09
--- /dev/null
+++ b/src/plugins/Emojis/context/EmojiPickerCellContext.tsx
@@ -0,0 +1,36 @@
+import { createContext, useContext } from 'react';
+import type { EmojiDataEmoji } from '../data';
+
+export type EmojiPickerCellContextValue = {
+ /** Resolves an emoji's native glyph for the active skin tone. */
+ resolveNative: (emoji: EmojiDataEmoji) => string;
+ /** Report the user's emoji choice back to the SDK (inserts it). */
+ selectEmoji: (emoji: EmojiDataEmoji) => void;
+};
+
+const EmojiPickerCellContext = createContext(
+ undefined,
+);
+
+export const EmojiPickerCellProvider = EmojiPickerCellContext.Provider;
+
+/**
+ * Internal (NOT exported from the `emojis` entry): the cold subset of the picker
+ * contract the default emoji cell needs — resolving a glyph and reporting a selection.
+ * The grid can mount hundreds of cells, and React context has no partial subscription:
+ * a cell reading the public `EmojiPickerContext` would re-render on every change to its
+ * hot fields (scroll-spy `activeCategoryId`, the live `query`, `scrollTarget`), even
+ * though the cell reads none of them. These two values change only when the skin tone or
+ * `onEmojiSelect` changes — the cases where a cell genuinely must re-render — so the
+ * default `EmojiButton` subscribes here instead. The same values remain on the public
+ * `EmojiPickerContext` for custom grid slots.
+ */
+export const useEmojiPickerCellContext = () => {
+ const context = useContext(EmojiPickerCellContext);
+ if (!context) {
+ throw new Error(
+ 'Emoji picker cells must be rendered within a StreamEmojiPicker.Root.',
+ );
+ }
+ return context;
+};
diff --git a/src/plugins/Emojis/context/EmojiPickerContext.tsx b/src/plugins/Emojis/context/EmojiPickerContext.tsx
new file mode 100644
index 000000000..a7e47f8e7
--- /dev/null
+++ b/src/plugins/Emojis/context/EmojiPickerContext.tsx
@@ -0,0 +1,60 @@
+import { createContext, useContext } from 'react';
+import type { EmojiDataEmoji } from '../data';
+import type { EmojiPickerCategory } from '../components/EmojiGrid';
+import type { SkinTone } from '../components/skinTones';
+
+export type EmojiPickerContextValue = {
+ /** Currently-focused category id (browse mode). Always a valid id; never empty once loaded. */
+ activeCategoryId: string;
+ /** The browse model — filtered dataset, `frequent` prepended. */
+ categories: EmojiPickerCategory[];
+ /** `true` while a search query is active (=== `searchResults !== null`). */
+ isSearching: boolean;
+ /** The live search query. */
+ query: string;
+ /** Focus + scroll a category into view (sets active, bumps `scrollTarget`, clears search). */
+ requestScrollToCategory: (categoryId: string) => void;
+ /** Resolves an emoji's native glyph for the active skin tone. */
+ resolveNative: (emoji: EmojiDataEmoji) => string;
+ /** Retry loading the dataset after an error. */
+ retry: () => void;
+ /** Advanced: a "scroll here" signal for a scrolling grid (nonce re-fires repeats). May evolve. */
+ scrollTarget: { categoryId: string; nonce: number } | null;
+ /** Search matches, or `null` when not searching (`[]` = no matches). */
+ searchResults: EmojiDataEmoji[] | null;
+ /** Report the user's emoji choice back to the SDK (inserts it). */
+ selectEmoji: (emoji: EmojiDataEmoji) => void;
+ /** Set the active (highlighted) category without scrolling — used by scroll-spy. */
+ setActiveCategory: (categoryId: string) => void;
+ /** Feed the search query. */
+ setQuery: (query: string) => void;
+ /** Feed the active skin tone index. */
+ setSkinTone: (skinToneIndex: number) => void;
+ /** Active skin tone index (0 = default, 1–5 = light → dark). */
+ skinToneIndex: number;
+ /** The available skin tones (glyph + i18n key) for a skin-tone selector. */
+ skinTones: SkinTone[];
+ /** Dataset load status. */
+ status: 'error' | 'loading' | 'ready';
+};
+
+const EmojiPickerContext = createContext(undefined);
+
+export const EmojiPickerProvider = EmojiPickerContext.Provider;
+
+/**
+ * The public emoji-picker contract shared with every slot (`useEmojiPickerContext()`).
+ * Exposes the data the SDK owns + the report-back setters a slot feeds; deliberately
+ * carries no behavioral coordination (scroll mechanics, keyboard, hover) — those stay
+ * private to each slot. Hover-preview state lives in a separate internal context so
+ * consuming this one does not re-render the emoji grid.
+ */
+export const useEmojiPickerContext = () => {
+ const context = useContext(EmojiPickerContext);
+ if (!context) {
+ throw new Error(
+ 'Emoji picker slots must be rendered within a StreamEmojiPicker.Root.',
+ );
+ }
+ return context;
+};
diff --git a/src/plugins/Emojis/context/EmojiPickerPreviewContext.tsx b/src/plugins/Emojis/context/EmojiPickerPreviewContext.tsx
new file mode 100644
index 000000000..615f54597
--- /dev/null
+++ b/src/plugins/Emojis/context/EmojiPickerPreviewContext.tsx
@@ -0,0 +1,30 @@
+import { createContext, useContext } from 'react';
+import type { EmojiDataEmoji } from '../data';
+
+export type EmojiPickerPreviewContextValue = {
+ previewedEmoji: EmojiDataEmoji | null;
+ setPreviewedEmoji: (emoji: EmojiDataEmoji | null) => void;
+};
+
+const EmojiPickerPreviewContext = createContext<
+ EmojiPickerPreviewContextValue | undefined
+>(undefined);
+
+export const EmojiPickerPreviewProvider = EmojiPickerPreviewContext.Provider;
+
+/**
+ * Internal (NOT exported from the `emojis` entry): the hovered/focused emoji shared
+ * between the default grid (writes) and the default preview (reads). Kept out of the
+ * public `EmojiPickerContext` so hover changes don't re-render the grid, and so a custom
+ * grid does not implicitly drive the default preview — hover-preview is a private
+ * mechanic of the default components.
+ */
+export const useEmojiPickerPreviewContext = () => {
+ const context = useContext(EmojiPickerPreviewContext);
+ if (!context) {
+ throw new Error(
+ 'Emoji preview components must be rendered within a StreamEmojiPicker.Root.',
+ );
+ }
+ return context;
+};
diff --git a/src/plugins/Emojis/context/__tests__/EmojiPickerContext.test.tsx b/src/plugins/Emojis/context/__tests__/EmojiPickerContext.test.tsx
new file mode 100644
index 000000000..0021c90fc
--- /dev/null
+++ b/src/plugins/Emojis/context/__tests__/EmojiPickerContext.test.tsx
@@ -0,0 +1,108 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+
+const { hookState } = vi.hoisted(() => ({
+ hookState: { data: null as unknown, error: false, retry: vi.fn() },
+}));
+vi.mock('../../hooks/useEmojiPickerState', () => ({
+ useEmojiPickerState: () => hookState,
+}));
+vi.mock('../../../../context', () => ({
+ useTranslationContext: () => ({ t: (k: string) => k }),
+}));
+
+import { EmojiPickerRoot } from '../../components/EmojiPickerRoot';
+import { useEmojiPickerContext } from '../EmojiPickerContext';
+
+// `grinning` has no skin variants; `wave` has all six, so resolveNative can be exercised
+// across tones (this is where the skin-tone resolution lives now, not in EmojiButton).
+const DATA = {
+ aliases: {},
+ categories: [{ emojis: ['grinning', 'wave'], id: 'people' }],
+ emojis: {
+ grinning: {
+ id: 'grinning',
+ keywords: [],
+ name: 'Grinning',
+ skins: [{ native: '😀', unified: '1f600' }],
+ version: 1,
+ },
+ wave: {
+ id: 'wave',
+ keywords: [],
+ name: 'Waving Hand',
+ skins: [
+ { native: '👋', unified: '1f44b' },
+ { native: '👋🏻', unified: '1f44b-1f3fb' },
+ { native: '👋🏼', unified: '1f44b-1f3fc' },
+ { native: '👋🏽', unified: '1f44b-1f3fd' },
+ { native: '👋🏾', unified: '1f44b-1f3fe' },
+ { native: '👋🏿', unified: '1f44b-1f3ff' },
+ ],
+ version: 1,
+ },
+ },
+};
+
+const ContractProbe = () => {
+ const ctx = useEmojiPickerContext();
+ return (
+ <>
+ {ctx.status}
+ {ctx.categories.map((c) => c.id).join(',')}
+ {ctx.skinTones.length}
+ >
+ );
+};
+
+const NativeProbe = () => {
+ const { categories, resolveNative } = useEmojiPickerContext();
+ return (
+
+ {categories[0]?.emojis.map((e) => (
+
+ {resolveNative(e)}
+
+ ))}
+
+ );
+};
+
+describe('EmojiPickerRoot context', () => {
+ beforeEach(() => {
+ hookState.data = DATA;
+ hookState.error = false;
+ });
+
+ it('exposes the full contract to slot consumers', () => {
+ render(
+ {}}>
+
+ ,
+ );
+ expect(screen.getByTestId('status')).toHaveTextContent('ready');
+ expect(screen.getByTestId('cats')).toHaveTextContent('people');
+ expect(screen.getByTestId('tones')).toHaveTextContent('6');
+ });
+
+ it('resolveNative returns the toned glyph for skin-capable emoji, the default otherwise', () => {
+ render(
+ {}} skinToneIndex={5}>
+
+ ,
+ );
+ expect(screen.getByTestId('native-wave')).toHaveTextContent('👋🏿');
+ // No skin variants → falls back to skins[0] regardless of the active tone.
+ expect(screen.getByTestId('native-grinning')).toHaveTextContent('😀');
+ });
+
+ it('closes on Escape from the dialog container', () => {
+ const onClose = vi.fn();
+ render(
+ {}}>
+ slot
+ ,
+ );
+ fireEvent.keyDown(screen.getByRole('dialog'), { key: 'Escape' });
+ expect(onClose).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/src/plugins/Emojis/data/LICENSE b/src/plugins/Emojis/data/LICENSE
new file mode 100644
index 000000000..a82512e98
--- /dev/null
+++ b/src/plugins/Emojis/data/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) Missive.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/plugins/Emojis/data/__tests__/emoji-data.test.ts b/src/plugins/Emojis/data/__tests__/emoji-data.test.ts
new file mode 100644
index 000000000..202f9c40e
--- /dev/null
+++ b/src/plugins/Emojis/data/__tests__/emoji-data.test.ts
@@ -0,0 +1,34 @@
+import emojiData from '../emoji-data.json';
+import type { EmojiData } from '../types';
+
+const data = emojiData as unknown as EmojiData;
+
+describe('vendored emoji-data.json', () => {
+ it('has exactly the aliases/categories/emojis top-level keys (no spritesheet)', () => {
+ expect(Object.keys(data).sort()).toEqual(['aliases', 'categories', 'emojis']);
+ expect((data as Record).sheet).toBeUndefined();
+ });
+
+ it('has the 8 standard categories in the expected order', () => {
+ expect(data.categories.map((category) => category.id)).toEqual([
+ 'people',
+ 'nature',
+ 'foods',
+ 'activity',
+ 'places',
+ 'objects',
+ 'symbols',
+ 'flags',
+ ]);
+ });
+
+ it('every emoji has an id, a name and at least one native skin', () => {
+ const emojis = Object.values(data.emojis);
+ expect(emojis.length).toBeGreaterThan(1800);
+ for (const emoji of emojis) {
+ expect(typeof emoji.id).toBe('string');
+ expect(typeof emoji.name).toBe('string');
+ expect(typeof emoji.skins?.[0]?.native).toBe('string');
+ }
+ });
+});
diff --git a/src/plugins/Emojis/data/__tests__/filterEmojiData.test.ts b/src/plugins/Emojis/data/__tests__/filterEmojiData.test.ts
new file mode 100644
index 000000000..6ba2a3a35
--- /dev/null
+++ b/src/plugins/Emojis/data/__tests__/filterEmojiData.test.ts
@@ -0,0 +1,60 @@
+import type { EmojiData } from '../types';
+import { filterEmojiData } from '../filterEmojiData';
+
+const DATA: EmojiData = {
+ aliases: {},
+ categories: [
+ { emojis: ['grinning', 'smile'], id: 'people' },
+ { emojis: ['us', 'checkered_flag'], id: 'flags' },
+ ],
+ emojis: {
+ checkered_flag: {
+ id: 'checkered_flag',
+ keywords: [],
+ name: 'Checkered Flag',
+ skins: [{ native: '🏁', unified: '1f3c1' }],
+ version: 1,
+ },
+ grinning: {
+ id: 'grinning',
+ keywords: [],
+ name: 'Grinning',
+ skins: [{ native: '😀', unified: '1f600' }],
+ version: 1,
+ },
+ smile: {
+ id: 'smile',
+ keywords: [],
+ name: 'Smile',
+ skins: [{ native: '😄', unified: '1f604' }],
+ version: 13,
+ },
+ us: {
+ id: 'us',
+ keywords: [],
+ name: 'United States',
+ skins: [{ native: '🇺🇸', unified: '1f1fa-1f1f8' }],
+ version: 1,
+ },
+ },
+};
+
+describe('filterEmojiData', () => {
+ it('returns the same reference when nothing is excluded', () => {
+ expect(filterEmojiData(DATA, {})).toBe(DATA);
+ expect(filterEmojiData(DATA, { exceptEmojis: [] })).toBe(DATA);
+ });
+
+ it('drops exceptEmojis and prunes them from their category', () => {
+ const out = filterEmojiData(DATA, { exceptEmojis: ['smile'] });
+ expect(out.emojis.smile).toBeUndefined();
+ expect(out.emojis.grinning).toBeDefined();
+ expect(out.categories.find((c) => c.id === 'people')?.emojis).toEqual(['grinning']);
+ });
+
+ it('removes a category entirely when all its emoji are excluded', () => {
+ const out = filterEmojiData(DATA, { exceptEmojis: ['us', 'checkered_flag'] });
+ expect(out.categories.find((c) => c.id === 'flags')).toBeUndefined();
+ expect(out.categories.find((c) => c.id === 'people')).toBeDefined();
+ });
+});
diff --git a/src/plugins/Emojis/data/emoji-data.json b/src/plugins/Emojis/data/emoji-data.json
new file mode 100644
index 000000000..ce24d7519
--- /dev/null
+++ b/src/plugins/Emojis/data/emoji-data.json
@@ -0,0 +1 @@
+{"categories":[{"id":"people","emojis":["grinning","smiley","smile","grin","laughing","sweat_smile","rolling_on_the_floor_laughing","joy","slightly_smiling_face","upside_down_face","melting_face","wink","blush","innocent","smiling_face_with_3_hearts","heart_eyes","star-struck","kissing_heart","kissing","relaxed","kissing_closed_eyes","kissing_smiling_eyes","smiling_face_with_tear","yum","stuck_out_tongue","stuck_out_tongue_winking_eye","zany_face","stuck_out_tongue_closed_eyes","money_mouth_face","hugging_face","face_with_hand_over_mouth","face_with_open_eyes_and_hand_over_mouth","face_with_peeking_eye","shushing_face","thinking_face","saluting_face","zipper_mouth_face","face_with_raised_eyebrow","neutral_face","expressionless","no_mouth","dotted_line_face","face_in_clouds","smirk","unamused","face_with_rolling_eyes","grimacing","face_exhaling","lying_face","shaking_face","relieved","pensive","sleepy","drooling_face","sleeping","mask","face_with_thermometer","face_with_head_bandage","nauseated_face","face_vomiting","sneezing_face","hot_face","cold_face","woozy_face","dizzy_face","face_with_spiral_eyes","exploding_head","face_with_cowboy_hat","partying_face","disguised_face","sunglasses","nerd_face","face_with_monocle","confused","face_with_diagonal_mouth","worried","slightly_frowning_face","white_frowning_face","open_mouth","hushed","astonished","flushed","pleading_face","face_holding_back_tears","frowning","anguished","fearful","cold_sweat","disappointed_relieved","cry","sob","scream","confounded","persevere","disappointed","sweat","weary","tired_face","yawning_face","triumph","rage","angry","face_with_symbols_on_mouth","smiling_imp","imp","skull","skull_and_crossbones","hankey","clown_face","japanese_ogre","japanese_goblin","ghost","alien","space_invader","wave","raised_back_of_hand","raised_hand_with_fingers_splayed","hand","spock-hand","rightwards_hand","leftwards_hand","palm_down_hand","palm_up_hand","leftwards_pushing_hand","rightwards_pushing_hand","ok_hand","pinched_fingers","pinching_hand","v","crossed_fingers","hand_with_index_finger_and_thumb_crossed","i_love_you_hand_sign","the_horns","call_me_hand","point_left","point_right","point_up_2","middle_finger","point_down","point_up","index_pointing_at_the_viewer","+1","-1","fist","facepunch","left-facing_fist","right-facing_fist","clap","raised_hands","heart_hands","open_hands","palms_up_together","handshake","pray","writing_hand","nail_care","selfie","muscle","mechanical_arm","mechanical_leg","leg","foot","ear","ear_with_hearing_aid","nose","brain","anatomical_heart","lungs","tooth","bone","eyes","eye","tongue","lips","biting_lip","baby","child","boy","girl","adult","person_with_blond_hair","man","bearded_person","man_with_beard","woman_with_beard","red_haired_man","curly_haired_man","white_haired_man","bald_man","woman","red_haired_woman","red_haired_person","curly_haired_woman","curly_haired_person","white_haired_woman","white_haired_person","bald_woman","bald_person","blond-haired-woman","blond-haired-man","older_adult","older_man","older_woman","person_frowning","man-frowning","woman-frowning","person_with_pouting_face","man-pouting","woman-pouting","no_good","man-gesturing-no","woman-gesturing-no","ok_woman","man-gesturing-ok","woman-gesturing-ok","information_desk_person","man-tipping-hand","woman-tipping-hand","raising_hand","man-raising-hand","woman-raising-hand","deaf_person","deaf_man","deaf_woman","bow","man-bowing","woman-bowing","face_palm","man-facepalming","woman-facepalming","shrug","man-shrugging","woman-shrugging","health_worker","male-doctor","female-doctor","student","male-student","female-student","teacher","male-teacher","female-teacher","judge","male-judge","female-judge","farmer","male-farmer","female-farmer","cook","male-cook","female-cook","mechanic","male-mechanic","female-mechanic","factory_worker","male-factory-worker","female-factory-worker","office_worker","male-office-worker","female-office-worker","scientist","male-scientist","female-scientist","technologist","male-technologist","female-technologist","singer","male-singer","female-singer","artist","male-artist","female-artist","pilot","male-pilot","female-pilot","astronaut","male-astronaut","female-astronaut","firefighter","male-firefighter","female-firefighter","cop","male-police-officer","female-police-officer","sleuth_or_spy","male-detective","female-detective","guardsman","male-guard","female-guard","ninja","construction_worker","male-construction-worker","female-construction-worker","person_with_crown","prince","princess","man_with_turban","man-wearing-turban","woman-wearing-turban","man_with_gua_pi_mao","person_with_headscarf","person_in_tuxedo","man_in_tuxedo","woman_in_tuxedo","bride_with_veil","man_with_veil","woman_with_veil","pregnant_woman","pregnant_man","pregnant_person","breast-feeding","woman_feeding_baby","man_feeding_baby","person_feeding_baby","angel","santa","mrs_claus","mx_claus","superhero","male_superhero","female_superhero","supervillain","male_supervillain","female_supervillain","mage","male_mage","female_mage","fairy","male_fairy","female_fairy","vampire","male_vampire","female_vampire","merperson","merman","mermaid","elf","male_elf","female_elf","genie","male_genie","female_genie","zombie","male_zombie","female_zombie","troll","massage","man-getting-massage","woman-getting-massage","haircut","man-getting-haircut","woman-getting-haircut","walking","man-walking","woman-walking","standing_person","man_standing","woman_standing","kneeling_person","man_kneeling","woman_kneeling","person_with_probing_cane","man_with_probing_cane","woman_with_probing_cane","person_in_motorized_wheelchair","man_in_motorized_wheelchair","woman_in_motorized_wheelchair","person_in_manual_wheelchair","man_in_manual_wheelchair","woman_in_manual_wheelchair","runner","man-running","woman-running","dancer","man_dancing","man_in_business_suit_levitating","dancers","men-with-bunny-ears-partying","women-with-bunny-ears-partying","person_in_steamy_room","man_in_steamy_room","woman_in_steamy_room","person_climbing","man_climbing","woman_climbing","fencer","horse_racing","skier","snowboarder","golfer","man-golfing","woman-golfing","surfer","man-surfing","woman-surfing","rowboat","man-rowing-boat","woman-rowing-boat","swimmer","man-swimming","woman-swimming","person_with_ball","man-bouncing-ball","woman-bouncing-ball","weight_lifter","man-lifting-weights","woman-lifting-weights","bicyclist","man-biking","woman-biking","mountain_bicyclist","man-mountain-biking","woman-mountain-biking","person_doing_cartwheel","man-cartwheeling","woman-cartwheeling","wrestlers","man-wrestling","woman-wrestling","water_polo","man-playing-water-polo","woman-playing-water-polo","handball","man-playing-handball","woman-playing-handball","juggling","man-juggling","woman-juggling","person_in_lotus_position","man_in_lotus_position","woman_in_lotus_position","bath","sleeping_accommodation","people_holding_hands","two_women_holding_hands","man_and_woman_holding_hands","two_men_holding_hands","couplekiss","woman-kiss-man","man-kiss-man","woman-kiss-woman","couple_with_heart","woman-heart-man","man-heart-man","woman-heart-woman","family","man-woman-boy","man-woman-girl","man-woman-girl-boy","man-woman-boy-boy","man-woman-girl-girl","man-man-boy","man-man-girl","man-man-girl-boy","man-man-boy-boy","man-man-girl-girl","woman-woman-boy","woman-woman-girl","woman-woman-girl-boy","woman-woman-boy-boy","woman-woman-girl-girl","man-boy","man-boy-boy","man-girl","man-girl-boy","man-girl-girl","woman-boy","woman-boy-boy","woman-girl","woman-girl-boy","woman-girl-girl","speaking_head_in_silhouette","bust_in_silhouette","busts_in_silhouette","people_hugging","footprints","robot_face","smiley_cat","smile_cat","joy_cat","heart_eyes_cat","smirk_cat","kissing_cat","scream_cat","crying_cat_face","pouting_cat","see_no_evil","hear_no_evil","speak_no_evil","love_letter","cupid","gift_heart","sparkling_heart","heartpulse","heartbeat","revolving_hearts","two_hearts","heart_decoration","heavy_heart_exclamation_mark_ornament","broken_heart","heart_on_fire","mending_heart","heart","pink_heart","orange_heart","yellow_heart","green_heart","blue_heart","light_blue_heart","purple_heart","brown_heart","black_heart","grey_heart","white_heart","kiss","100","anger","boom","dizzy","sweat_drops","dash","hole","speech_balloon","eye-in-speech-bubble","left_speech_bubble","right_anger_bubble","thought_balloon","zzz"]},{"id":"nature","emojis":["monkey_face","monkey","gorilla","orangutan","dog","dog2","guide_dog","service_dog","poodle","wolf","fox_face","raccoon","cat","cat2","black_cat","lion_face","tiger","tiger2","leopard","horse","moose","donkey","racehorse","unicorn_face","zebra_face","deer","bison","cow","ox","water_buffalo","cow2","pig","pig2","boar","pig_nose","ram","sheep","goat","dromedary_camel","camel","llama","giraffe_face","elephant","mammoth","rhinoceros","hippopotamus","mouse","mouse2","rat","hamster","rabbit","rabbit2","chipmunk","beaver","hedgehog","bat","bear","polar_bear","koala","panda_face","sloth","otter","skunk","kangaroo","badger","feet","turkey","chicken","rooster","hatching_chick","baby_chick","hatched_chick","bird","penguin","dove_of_peace","eagle","duck","swan","owl","dodo","feather","flamingo","peacock","parrot","wing","black_bird","goose","frog","crocodile","turtle","lizard","snake","dragon_face","dragon","sauropod","t-rex","whale","whale2","dolphin","seal","fish","tropical_fish","blowfish","shark","octopus","shell","coral","jellyfish","snail","butterfly","bug","ant","bee","beetle","ladybug","cricket","cockroach","spider","spider_web","scorpion","mosquito","fly","worm","microbe","bouquet","cherry_blossom","white_flower","lotus","rosette","rose","wilted_flower","hibiscus","sunflower","blossom","tulip","hyacinth","seedling","potted_plant","evergreen_tree","deciduous_tree","palm_tree","cactus","ear_of_rice","herb","shamrock","four_leaf_clover","maple_leaf","fallen_leaf","leaves","empty_nest","nest_with_eggs","mushroom"]},{"id":"foods","emojis":["grapes","melon","watermelon","tangerine","lemon","banana","pineapple","mango","apple","green_apple","pear","peach","cherries","strawberry","blueberries","kiwifruit","tomato","olive","coconut","avocado","eggplant","potato","carrot","corn","hot_pepper","bell_pepper","cucumber","leafy_green","broccoli","garlic","onion","peanuts","beans","chestnut","ginger_root","pea_pod","bread","croissant","baguette_bread","flatbread","pretzel","bagel","pancakes","waffle","cheese_wedge","meat_on_bone","poultry_leg","cut_of_meat","bacon","hamburger","fries","pizza","hotdog","sandwich","taco","burrito","tamale","stuffed_flatbread","falafel","egg","fried_egg","shallow_pan_of_food","stew","fondue","bowl_with_spoon","green_salad","popcorn","butter","salt","canned_food","bento","rice_cracker","rice_ball","rice","curry","ramen","spaghetti","sweet_potato","oden","sushi","fried_shrimp","fish_cake","moon_cake","dango","dumpling","fortune_cookie","takeout_box","crab","lobster","shrimp","squid","oyster","icecream","shaved_ice","ice_cream","doughnut","cookie","birthday","cake","cupcake","pie","chocolate_bar","candy","lollipop","custard","honey_pot","baby_bottle","glass_of_milk","coffee","teapot","tea","sake","champagne","wine_glass","cocktail","tropical_drink","beer","beers","clinking_glasses","tumbler_glass","pouring_liquid","cup_with_straw","bubble_tea","beverage_box","mate_drink","ice_cube","chopsticks","knife_fork_plate","fork_and_knife","spoon","hocho","jar","amphora"]},{"id":"activity","emojis":["jack_o_lantern","christmas_tree","fireworks","sparkler","firecracker","sparkles","balloon","tada","confetti_ball","tanabata_tree","bamboo","dolls","flags","wind_chime","rice_scene","red_envelope","ribbon","gift","reminder_ribbon","admission_tickets","ticket","medal","trophy","sports_medal","first_place_medal","second_place_medal","third_place_medal","soccer","baseball","softball","basketball","volleyball","football","rugby_football","tennis","flying_disc","bowling","cricket_bat_and_ball","field_hockey_stick_and_ball","ice_hockey_stick_and_puck","lacrosse","table_tennis_paddle_and_ball","badminton_racquet_and_shuttlecock","boxing_glove","martial_arts_uniform","goal_net","golf","ice_skate","fishing_pole_and_fish","diving_mask","running_shirt_with_sash","ski","sled","curling_stone","dart","yo-yo","kite","gun","8ball","crystal_ball","magic_wand","video_game","joystick","slot_machine","game_die","jigsaw","teddy_bear","pinata","mirror_ball","nesting_dolls","spades","hearts","diamonds","clubs","chess_pawn","black_joker","mahjong","flower_playing_cards","performing_arts","frame_with_picture","art","thread","sewing_needle","yarn","knot"]},{"id":"places","emojis":["earth_africa","earth_americas","earth_asia","globe_with_meridians","world_map","japan","compass","snow_capped_mountain","mountain","volcano","mount_fuji","camping","beach_with_umbrella","desert","desert_island","national_park","stadium","classical_building","building_construction","bricks","rock","wood","hut","house_buildings","derelict_house_building","house","house_with_garden","office","post_office","european_post_office","hospital","bank","hotel","love_hotel","convenience_store","school","department_store","factory","japanese_castle","european_castle","wedding","tokyo_tower","statue_of_liberty","church","mosque","hindu_temple","synagogue","shinto_shrine","kaaba","fountain","tent","foggy","night_with_stars","cityscape","sunrise_over_mountains","sunrise","city_sunset","city_sunrise","bridge_at_night","hotsprings","carousel_horse","playground_slide","ferris_wheel","roller_coaster","barber","circus_tent","steam_locomotive","railway_car","bullettrain_side","bullettrain_front","train2","metro","light_rail","station","tram","monorail","mountain_railway","train","bus","oncoming_bus","trolleybus","minibus","ambulance","fire_engine","police_car","oncoming_police_car","taxi","oncoming_taxi","car","oncoming_automobile","blue_car","pickup_truck","truck","articulated_lorry","tractor","racing_car","racing_motorcycle","motor_scooter","manual_wheelchair","motorized_wheelchair","auto_rickshaw","bike","scooter","skateboard","roller_skate","busstop","motorway","railway_track","oil_drum","fuelpump","wheel","rotating_light","traffic_light","vertical_traffic_light","octagonal_sign","construction","anchor","ring_buoy","boat","canoe","speedboat","passenger_ship","ferry","motor_boat","ship","airplane","small_airplane","airplane_departure","airplane_arriving","parachute","seat","helicopter","suspension_railway","mountain_cableway","aerial_tramway","satellite","rocket","flying_saucer","bellhop_bell","luggage","hourglass","hourglass_flowing_sand","watch","alarm_clock","stopwatch","timer_clock","mantelpiece_clock","clock12","clock1230","clock1","clock130","clock2","clock230","clock3","clock330","clock4","clock430","clock5","clock530","clock6","clock630","clock7","clock730","clock8","clock830","clock9","clock930","clock10","clock1030","clock11","clock1130","new_moon","waxing_crescent_moon","first_quarter_moon","moon","full_moon","waning_gibbous_moon","last_quarter_moon","waning_crescent_moon","crescent_moon","new_moon_with_face","first_quarter_moon_with_face","last_quarter_moon_with_face","thermometer","sunny","full_moon_with_face","sun_with_face","ringed_planet","star","star2","stars","milky_way","cloud","partly_sunny","thunder_cloud_and_rain","mostly_sunny","barely_sunny","partly_sunny_rain","rain_cloud","snow_cloud","lightning","tornado","fog","wind_blowing_face","cyclone","rainbow","closed_umbrella","umbrella","umbrella_with_rain_drops","umbrella_on_ground","zap","snowflake","snowman","snowman_without_snow","comet","fire","droplet","ocean"]},{"id":"objects","emojis":["eyeglasses","dark_sunglasses","goggles","lab_coat","safety_vest","necktie","shirt","jeans","scarf","gloves","coat","socks","dress","kimono","sari","one-piece_swimsuit","briefs","shorts","bikini","womans_clothes","folding_hand_fan","purse","handbag","pouch","shopping_bags","school_satchel","thong_sandal","mans_shoe","athletic_shoe","hiking_boot","womans_flat_shoe","high_heel","sandal","ballet_shoes","boot","hair_pick","crown","womans_hat","tophat","mortar_board","billed_cap","military_helmet","helmet_with_white_cross","prayer_beads","lipstick","ring","gem","mute","speaker","sound","loud_sound","loudspeaker","mega","postal_horn","bell","no_bell","musical_score","musical_note","notes","studio_microphone","level_slider","control_knobs","microphone","headphones","radio","saxophone","accordion","guitar","musical_keyboard","trumpet","violin","banjo","drum_with_drumsticks","long_drum","maracas","flute","iphone","calling","phone","telephone_receiver","pager","fax","battery","low_battery","electric_plug","computer","desktop_computer","printer","keyboard","three_button_mouse","trackball","minidisc","floppy_disk","cd","dvd","abacus","movie_camera","film_frames","film_projector","clapper","tv","camera","camera_with_flash","video_camera","vhs","mag","mag_right","candle","bulb","flashlight","izakaya_lantern","diya_lamp","notebook_with_decorative_cover","closed_book","book","green_book","blue_book","orange_book","books","notebook","ledger","page_with_curl","scroll","page_facing_up","newspaper","rolled_up_newspaper","bookmark_tabs","bookmark","label","moneybag","coin","yen","dollar","euro","pound","money_with_wings","credit_card","receipt","chart","email","e-mail","incoming_envelope","envelope_with_arrow","outbox_tray","inbox_tray","package","mailbox","mailbox_closed","mailbox_with_mail","mailbox_with_no_mail","postbox","ballot_box_with_ballot","pencil2","black_nib","lower_left_fountain_pen","lower_left_ballpoint_pen","lower_left_paintbrush","lower_left_crayon","memo","briefcase","file_folder","open_file_folder","card_index_dividers","date","calendar","spiral_note_pad","spiral_calendar_pad","card_index","chart_with_upwards_trend","chart_with_downwards_trend","bar_chart","clipboard","pushpin","round_pushpin","paperclip","linked_paperclips","straight_ruler","triangular_ruler","scissors","card_file_box","file_cabinet","wastebasket","lock","unlock","lock_with_ink_pen","closed_lock_with_key","key","old_key","hammer","axe","pick","hammer_and_pick","hammer_and_wrench","dagger_knife","crossed_swords","bomb","boomerang","bow_and_arrow","shield","carpentry_saw","wrench","screwdriver","nut_and_bolt","gear","compression","scales","probing_cane","link","chains","hook","toolbox","magnet","ladder","alembic","test_tube","petri_dish","dna","microscope","telescope","satellite_antenna","syringe","drop_of_blood","pill","adhesive_bandage","crutch","stethoscope","x-ray","door","elevator","mirror","window","bed","couch_and_lamp","chair","toilet","plunger","shower","bathtub","mouse_trap","razor","lotion_bottle","safety_pin","broom","basket","roll_of_paper","bucket","soap","bubbles","toothbrush","sponge","fire_extinguisher","shopping_trolley","smoking","coffin","headstone","funeral_urn","nazar_amulet","hamsa","moyai","placard","identification_card"]},{"id":"symbols","emojis":["atm","put_litter_in_its_place","potable_water","wheelchair","mens","womens","restroom","baby_symbol","wc","passport_control","customs","baggage_claim","left_luggage","warning","children_crossing","no_entry","no_entry_sign","no_bicycles","no_smoking","do_not_litter","non-potable_water","no_pedestrians","no_mobile_phones","underage","radioactive_sign","biohazard_sign","arrow_up","arrow_upper_right","arrow_right","arrow_lower_right","arrow_down","arrow_lower_left","arrow_left","arrow_upper_left","arrow_up_down","left_right_arrow","leftwards_arrow_with_hook","arrow_right_hook","arrow_heading_up","arrow_heading_down","arrows_clockwise","arrows_counterclockwise","back","end","on","soon","top","place_of_worship","atom_symbol","om_symbol","star_of_david","wheel_of_dharma","yin_yang","latin_cross","orthodox_cross","star_and_crescent","peace_symbol","menorah_with_nine_branches","six_pointed_star","khanda","aries","taurus","gemini","cancer","leo","virgo","libra","scorpius","sagittarius","capricorn","aquarius","pisces","ophiuchus","twisted_rightwards_arrows","repeat","repeat_one","arrow_forward","fast_forward","black_right_pointing_double_triangle_with_vertical_bar","black_right_pointing_triangle_with_double_vertical_bar","arrow_backward","rewind","black_left_pointing_double_triangle_with_vertical_bar","arrow_up_small","arrow_double_up","arrow_down_small","arrow_double_down","double_vertical_bar","black_square_for_stop","black_circle_for_record","eject","cinema","low_brightness","high_brightness","signal_strength","wireless","vibration_mode","mobile_phone_off","female_sign","male_sign","transgender_symbol","heavy_multiplication_x","heavy_plus_sign","heavy_minus_sign","heavy_division_sign","heavy_equals_sign","infinity","bangbang","interrobang","question","grey_question","grey_exclamation","exclamation","wavy_dash","currency_exchange","heavy_dollar_sign","medical_symbol","recycle","fleur_de_lis","trident","name_badge","beginner","o","white_check_mark","ballot_box_with_check","heavy_check_mark","x","negative_squared_cross_mark","curly_loop","loop","part_alternation_mark","eight_spoked_asterisk","eight_pointed_black_star","sparkle","copyright","registered","tm","hash","keycap_star","zero","one","two","three","four","five","six","seven","eight","nine","keycap_ten","capital_abcd","abcd","1234","symbols","abc","a","ab","b","cl","cool","free","information_source","id","m","new","ng","o2","ok","parking","sos","up","vs","koko","sa","u6708","u6709","u6307","ideograph_advantage","u5272","u7121","u7981","accept","u7533","u5408","u7a7a","congratulations","secret","u55b6","u6e80","red_circle","large_orange_circle","large_yellow_circle","large_green_circle","large_blue_circle","large_purple_circle","large_brown_circle","black_circle","white_circle","large_red_square","large_orange_square","large_yellow_square","large_green_square","large_blue_square","large_purple_square","large_brown_square","black_large_square","white_large_square","black_medium_square","white_medium_square","black_medium_small_square","white_medium_small_square","black_small_square","white_small_square","large_orange_diamond","large_blue_diamond","small_orange_diamond","small_blue_diamond","small_red_triangle","small_red_triangle_down","diamond_shape_with_a_dot_inside","radio_button","white_square_button","black_square_button"]},{"id":"flags","emojis":["checkered_flag","cn","crossed_flags","de","es","flag-ac","flag-ad","flag-ae","flag-af","flag-ag","flag-ai","flag-al","flag-am","flag-ao","flag-aq","flag-ar","flag-as","flag-at","flag-au","flag-aw","flag-ax","flag-az","flag-ba","flag-bb","flag-bd","flag-be","flag-bf","flag-bg","flag-bh","flag-bi","flag-bj","flag-bl","flag-bm","flag-bn","flag-bo","flag-bq","flag-br","flag-bs","flag-bt","flag-bv","flag-bw","flag-by","flag-bz","flag-ca","flag-cc","flag-cd","flag-cf","flag-cg","flag-ch","flag-ci","flag-ck","flag-cl","flag-cm","flag-co","flag-cp","flag-cr","flag-cu","flag-cv","flag-cw","flag-cx","flag-cy","flag-cz","flag-dg","flag-dj","flag-dk","flag-dm","flag-do","flag-dz","flag-ea","flag-ec","flag-ee","flag-eg","flag-eh","flag-england","flag-er","flag-et","flag-eu","flag-fi","flag-fj","flag-fk","flag-fm","flag-fo","flag-ga","flag-gd","flag-ge","flag-gf","flag-gg","flag-gh","flag-gi","flag-gl","flag-gm","flag-gn","flag-gp","flag-gq","flag-gr","flag-gs","flag-gt","flag-gu","flag-gw","flag-gy","flag-hk","flag-hm","flag-hn","flag-hr","flag-ht","flag-hu","flag-ic","flag-id","flag-ie","flag-il","flag-im","flag-in","flag-io","flag-iq","flag-ir","flag-is","flag-je","flag-jm","flag-jo","flag-ke","flag-kg","flag-kh","flag-ki","flag-km","flag-kn","flag-kp","flag-kw","flag-ky","flag-kz","flag-la","flag-lb","flag-lc","flag-li","flag-lk","flag-lr","flag-ls","flag-lt","flag-lu","flag-lv","flag-ly","flag-ma","flag-mc","flag-md","flag-me","flag-mf","flag-mg","flag-mh","flag-mk","flag-ml","flag-mm","flag-mn","flag-mo","flag-mp","flag-mq","flag-mr","flag-ms","flag-mt","flag-mu","flag-mv","flag-mw","flag-mx","flag-my","flag-mz","flag-na","flag-nc","flag-ne","flag-nf","flag-ng","flag-ni","flag-nl","flag-no","flag-np","flag-nr","flag-nu","flag-nz","flag-om","flag-pa","flag-pe","flag-pf","flag-pg","flag-ph","flag-pk","flag-pl","flag-pm","flag-pn","flag-pr","flag-ps","flag-pt","flag-pw","flag-py","flag-qa","flag-re","flag-ro","flag-rs","flag-rw","flag-sa","flag-sb","flag-sc","flag-scotland","flag-sd","flag-se","flag-sg","flag-sh","flag-si","flag-sj","flag-sk","flag-sl","flag-sm","flag-sn","flag-so","flag-sr","flag-ss","flag-st","flag-sv","flag-sx","flag-sy","flag-sz","flag-ta","flag-tc","flag-td","flag-tf","flag-tg","flag-th","flag-tj","flag-tk","flag-tl","flag-tm","flag-tn","flag-to","flag-tr","flag-tt","flag-tv","flag-tw","flag-tz","flag-ua","flag-ug","flag-um","flag-un","flag-uy","flag-uz","flag-va","flag-vc","flag-ve","flag-vg","flag-vi","flag-vn","flag-vu","flag-wales","flag-wf","flag-ws","flag-xk","flag-ye","flag-yt","flag-za","flag-zm","flag-zw","fr","gb","it","jp","kr","pirate_flag","rainbow-flag","ru","transgender_flag","triangular_flag_on_post","us","waving_black_flag","waving_white_flag"]}],"emojis":{"100":{"id":"100","name":"Hundred Points","keywords":["100","score","perfect","numbers","century","exam","quiz","test","pass"],"skins":[{"unified":"1f4af","native":"💯"}],"version":1},"1234":{"id":"1234","name":"Input Numbers","keywords":["1234","blue","square","1","2","3","4"],"skins":[{"unified":"1f522","native":"🔢"}],"version":1},"grinning":{"id":"grinning","name":"Grinning Face","emoticons":[":D"],"keywords":["smile","happy","joy",":D","grin"],"skins":[{"unified":"1f600","native":"😀"}],"version":1},"smiley":{"id":"smiley","name":"Grinning Face with Big Eyes","emoticons":[":)","=)","=-)"],"keywords":["smiley","happy","joy","haha",":D",":)","smile","funny"],"skins":[{"unified":"1f603","native":"😃"}],"version":1},"smile":{"id":"smile","name":"Grinning Face with Smiling Eyes","emoticons":[":)","C:","c:",":D",":-D"],"keywords":["smile","happy","joy","funny","haha","laugh","like",":D",":)"],"skins":[{"unified":"1f604","native":"😄"}],"version":1},"grin":{"id":"grin","name":"Beaming Face with Smiling Eyes","keywords":["grin","happy","smile","joy","kawaii"],"skins":[{"unified":"1f601","native":"😁"}],"version":1},"laughing":{"id":"laughing","name":"Grinning Squinting Face","emoticons":[":>",":->"],"keywords":["laughing","satisfied","happy","joy","lol","haha","glad","XD","laugh"],"skins":[{"unified":"1f606","native":"😆"}],"version":1},"sweat_smile":{"id":"sweat_smile","name":"Grinning Face with Sweat","keywords":["smile","hot","happy","laugh","relief"],"skins":[{"unified":"1f605","native":"😅"}],"version":1},"rolling_on_the_floor_laughing":{"id":"rolling_on_the_floor_laughing","name":"Rolling on the Floor Laughing","keywords":["face","lol","haha","rofl"],"skins":[{"unified":"1f923","native":"🤣"}],"version":3},"joy":{"id":"joy","name":"Face with Tears of Joy","keywords":["cry","weep","happy","happytears","haha"],"skins":[{"unified":"1f602","native":"😂"}],"version":1},"slightly_smiling_face":{"id":"slightly_smiling_face","name":"Slightly Smiling Face","emoticons":[":)","(:",":-)"],"keywords":["smile"],"skins":[{"unified":"1f642","native":"🙂"}],"version":1},"upside_down_face":{"id":"upside_down_face","name":"Upside-Down Face","keywords":["upside","down","flipped","silly","smile"],"skins":[{"unified":"1f643","native":"🙃"}],"version":1},"melting_face":{"id":"melting_face","name":"Melting Face","keywords":["hot","heat"],"skins":[{"unified":"1fae0","native":"🫠"}],"version":14},"wink":{"id":"wink","name":"Winking Face","emoticons":[";)",";-)"],"keywords":["wink","happy","mischievous","secret",";)","smile","eye"],"skins":[{"unified":"1f609","native":"😉"}],"version":1},"blush":{"id":"blush","name":"Smiling Face with Smiling Eyes","emoticons":[":)"],"keywords":["blush","smile","happy","flushed","crush","embarrassed","shy","joy"],"skins":[{"unified":"1f60a","native":"😊"}],"version":1},"innocent":{"id":"innocent","name":"Smiling Face with Halo","keywords":["innocent","angel","heaven"],"skins":[{"unified":"1f607","native":"😇"}],"version":1},"smiling_face_with_3_hearts":{"id":"smiling_face_with_3_hearts","name":"Smiling Face with Hearts","keywords":["3","love","like","affection","valentines","infatuation","crush","adore"],"skins":[{"unified":"1f970","native":"🥰"}],"version":11},"heart_eyes":{"id":"heart_eyes","name":"Smiling Face with Heart-Eyes","keywords":["heart","eyes","love","like","affection","valentines","infatuation","crush"],"skins":[{"unified":"1f60d","native":"😍"}],"version":1},"star-struck":{"id":"star-struck","name":"Star-Struck","keywords":["star","struck","grinning","face","with","eyes","smile","starry"],"skins":[{"unified":"1f929","native":"🤩"}],"version":5},"kissing_heart":{"id":"kissing_heart","name":"Face Blowing a Kiss","emoticons":[":*",":-*"],"keywords":["kissing","heart","love","like","affection","valentines","infatuation"],"skins":[{"unified":"1f618","native":"😘"}],"version":1},"kissing":{"id":"kissing","name":"Kissing Face","keywords":["love","like","3","valentines","infatuation","kiss"],"skins":[{"unified":"1f617","native":"😗"}],"version":1},"relaxed":{"id":"relaxed","name":"Smiling Face","keywords":["relaxed","blush","massage","happiness"],"skins":[{"unified":"263a-fe0f","native":"☺️"}],"version":1},"kissing_closed_eyes":{"id":"kissing_closed_eyes","name":"Kissing Face with Closed Eyes","keywords":["love","like","affection","valentines","infatuation","kiss"],"skins":[{"unified":"1f61a","native":"😚"}],"version":1},"kissing_smiling_eyes":{"id":"kissing_smiling_eyes","name":"Kissing Face with Smiling Eyes","keywords":["affection","valentines","infatuation","kiss"],"skins":[{"unified":"1f619","native":"😙"}],"version":1},"smiling_face_with_tear":{"id":"smiling_face_with_tear","name":"Smiling Face with Tear","keywords":["sad","cry","pretend"],"skins":[{"unified":"1f972","native":"🥲"}],"version":13},"yum":{"id":"yum","name":"Face Savoring Food","keywords":["yum","happy","joy","tongue","smile","silly","yummy","nom","delicious","savouring"],"skins":[{"unified":"1f60b","native":"😋"}],"version":1},"stuck_out_tongue":{"id":"stuck_out_tongue","name":"Face with Tongue","emoticons":[":p",":-p",":P",":-P",":b",":-b"],"keywords":["stuck","out","prank","childish","playful","mischievous","smile"],"skins":[{"unified":"1f61b","native":"😛"}],"version":1},"stuck_out_tongue_winking_eye":{"id":"stuck_out_tongue_winking_eye","name":"Winking Face with Tongue","emoticons":[";p",";-p",";b",";-b",";P",";-P"],"keywords":["stuck","out","eye","prank","childish","playful","mischievous","smile","wink"],"skins":[{"unified":"1f61c","native":"😜"}],"version":1},"zany_face":{"id":"zany_face","name":"Zany Face","keywords":["grinning","with","one","large","and","small","eye","goofy","crazy"],"skins":[{"unified":"1f92a","native":"🤪"}],"version":5},"stuck_out_tongue_closed_eyes":{"id":"stuck_out_tongue_closed_eyes","name":"Squinting Face with Tongue","keywords":["stuck","out","closed","eyes","prank","playful","mischievous","smile"],"skins":[{"unified":"1f61d","native":"😝"}],"version":1},"money_mouth_face":{"id":"money_mouth_face","name":"Money-Mouth Face","keywords":["money","mouth","rich","dollar"],"skins":[{"unified":"1f911","native":"🤑"}],"version":1},"hugging_face":{"id":"hugging_face","name":"Hugging Face","keywords":["smile","hug"],"skins":[{"unified":"1f917","native":"🤗"}],"version":1},"face_with_hand_over_mouth":{"id":"face_with_hand_over_mouth","name":"Face with Hand over Mouth","keywords":["smiling","eyes","and","covering","whoops","shock","surprise"],"skins":[{"unified":"1f92d","native":"🤭"}],"version":5},"face_with_open_eyes_and_hand_over_mouth":{"id":"face_with_open_eyes_and_hand_over_mouth","name":"Face with Open Eyes and Hand over Mouth","keywords":["silence","secret","shock","surprise"],"skins":[{"unified":"1fae2","native":"🫢"}],"version":14},"face_with_peeking_eye":{"id":"face_with_peeking_eye","name":"Face with Peeking Eye","keywords":["scared","frightening","embarrassing","shy"],"skins":[{"unified":"1fae3","native":"🫣"}],"version":14},"shushing_face":{"id":"shushing_face","name":"Shushing Face","keywords":["with","finger","covering","closed","lips","quiet","shhh"],"skins":[{"unified":"1f92b","native":"🤫"}],"version":5},"thinking_face":{"id":"thinking_face","name":"Thinking Face","keywords":["hmmm","think","consider"],"skins":[{"unified":"1f914","native":"🤔"}],"version":1},"saluting_face":{"id":"saluting_face","name":"Saluting Face","keywords":["respect","salute"],"skins":[{"unified":"1fae1","native":"🫡"}],"version":14},"zipper_mouth_face":{"id":"zipper_mouth_face","name":"Zipper-Mouth Face","keywords":["zipper","mouth","sealed","secret"],"skins":[{"unified":"1f910","native":"🤐"}],"version":1},"face_with_raised_eyebrow":{"id":"face_with_raised_eyebrow","name":"Face with Raised Eyebrow","keywords":["one","distrust","scepticism","disapproval","disbelief","surprise"],"skins":[{"unified":"1f928","native":"🤨"}],"version":5},"neutral_face":{"id":"neutral_face","name":"Neutral Face","emoticons":[":|",":-|"],"keywords":["indifference","meh",":",""],"skins":[{"unified":"1f610","native":"😐"}],"version":1},"expressionless":{"id":"expressionless","name":"Expressionless Face","emoticons":["-_-"],"keywords":["indifferent","-","","meh","deadpan"],"skins":[{"unified":"1f611","native":"😑"}],"version":1},"no_mouth":{"id":"no_mouth","name":"Face Without Mouth","keywords":["no","hellokitty"],"skins":[{"unified":"1f636","native":"😶"}],"version":1},"dotted_line_face":{"id":"dotted_line_face","name":"Dotted Line Face","keywords":["invisible","lonely","isolation","depression"],"skins":[{"unified":"1fae5","native":"🫥"}],"version":14},"face_in_clouds":{"id":"face_in_clouds","name":"Face in Clouds","keywords":["shower","steam","dream"],"skins":[{"unified":"1f636-200d-1f32b-fe0f","native":"😶🌫️"}],"version":13.1},"smirk":{"id":"smirk","name":"Smirking Face","keywords":["smirk","smile","mean","prank","smug","sarcasm"],"skins":[{"unified":"1f60f","native":"😏"}],"version":1},"unamused":{"id":"unamused","name":"Unamused Face","emoticons":[":("],"keywords":["indifference","bored","straight","serious","sarcasm","unimpressed","skeptical","dubious","side","eye"],"skins":[{"unified":"1f612","native":"😒"}],"version":1},"face_with_rolling_eyes":{"id":"face_with_rolling_eyes","name":"Face with Rolling Eyes","keywords":["eyeroll","frustrated"],"skins":[{"unified":"1f644","native":"🙄"}],"version":1},"grimacing":{"id":"grimacing","name":"Grimacing Face","keywords":["grimace","teeth"],"skins":[{"unified":"1f62c","native":"😬"}],"version":1},"face_exhaling":{"id":"face_exhaling","name":"Face Exhaling","keywords":["relieve","relief","tired","sigh"],"skins":[{"unified":"1f62e-200d-1f4a8","native":"😮💨"}],"version":13.1},"lying_face":{"id":"lying_face","name":"Lying Face","keywords":["lie","pinocchio"],"skins":[{"unified":"1f925","native":"🤥"}],"version":3},"shaking_face":{"id":"shaking_face","name":"Shaking Face","keywords":["dizzy","shock","blurry","earthquake"],"skins":[{"unified":"1fae8","native":"🫨"}],"version":15},"relieved":{"id":"relieved","name":"Relieved Face","keywords":["relaxed","phew","massage","happiness"],"skins":[{"unified":"1f60c","native":"😌"}],"version":1},"pensive":{"id":"pensive","name":"Pensive Face","keywords":["sad","depressed","upset"],"skins":[{"unified":"1f614","native":"😔"}],"version":1},"sleepy":{"id":"sleepy","name":"Sleepy Face","keywords":["tired","rest","nap"],"skins":[{"unified":"1f62a","native":"😪"}],"version":1},"drooling_face":{"id":"drooling_face","name":"Drooling Face","keywords":[],"skins":[{"unified":"1f924","native":"🤤"}],"version":3},"sleeping":{"id":"sleeping","name":"Sleeping Face","keywords":["tired","sleepy","night","zzz"],"skins":[{"unified":"1f634","native":"😴"}],"version":1},"mask":{"id":"mask","name":"Face with Medical Mask","keywords":["sick","ill","disease","covid"],"skins":[{"unified":"1f637","native":"😷"}],"version":1},"face_with_thermometer":{"id":"face_with_thermometer","name":"Face with Thermometer","keywords":["sick","temperature","cold","fever","covid"],"skins":[{"unified":"1f912","native":"🤒"}],"version":1},"face_with_head_bandage":{"id":"face_with_head_bandage","name":"Face with Head-Bandage","keywords":["head","bandage","injured","clumsy","hurt"],"skins":[{"unified":"1f915","native":"🤕"}],"version":1},"nauseated_face":{"id":"nauseated_face","name":"Nauseated Face","keywords":["vomit","gross","green","sick","throw","up","ill"],"skins":[{"unified":"1f922","native":"🤢"}],"version":3},"face_vomiting":{"id":"face_vomiting","name":"Face Vomiting","keywords":["with","open","mouth","sick"],"skins":[{"unified":"1f92e","native":"🤮"}],"version":5},"sneezing_face":{"id":"sneezing_face","name":"Sneezing Face","keywords":["gesundheit","sneeze","sick","allergy"],"skins":[{"unified":"1f927","native":"🤧"}],"version":3},"hot_face":{"id":"hot_face","name":"Hot Face","keywords":["feverish","heat","red","sweating"],"skins":[{"unified":"1f975","native":"🥵"}],"version":11},"cold_face":{"id":"cold_face","name":"Cold Face","keywords":["blue","freezing","frozen","frostbite","icicles"],"skins":[{"unified":"1f976","native":"🥶"}],"version":11},"woozy_face":{"id":"woozy_face","name":"Woozy Face","keywords":["dizzy","intoxicated","tipsy","wavy"],"skins":[{"unified":"1f974","native":"🥴"}],"version":11},"dizzy_face":{"id":"dizzy_face","name":"Dizzy Face","keywords":["spent","unconscious","xox"],"skins":[{"unified":"1f635","native":"😵"}],"version":1},"face_with_spiral_eyes":{"id":"face_with_spiral_eyes","name":"Face with Spiral Eyes","keywords":["sick","ill","confused","nauseous","nausea"],"skins":[{"unified":"1f635-200d-1f4ab","native":"😵💫"}],"version":13.1},"exploding_head":{"id":"exploding_head","name":"Exploding Head","keywords":["shocked","face","with","mind","blown"],"skins":[{"unified":"1f92f","native":"🤯"}],"version":5},"face_with_cowboy_hat":{"id":"face_with_cowboy_hat","name":"Cowboy Hat Face","keywords":["with","cowgirl"],"skins":[{"unified":"1f920","native":"🤠"}],"version":3},"partying_face":{"id":"partying_face","name":"Partying Face","keywords":["celebration","woohoo"],"skins":[{"unified":"1f973","native":"🥳"}],"version":11},"disguised_face":{"id":"disguised_face","name":"Disguised Face","keywords":["pretent","brows","glasses","moustache"],"skins":[{"unified":"1f978","native":"🥸"}],"version":13},"sunglasses":{"id":"sunglasses","name":"Smiling Face with Sunglasses","emoticons":["8)"],"keywords":["cool","smile","summer","beach","sunglass"],"skins":[{"unified":"1f60e","native":"😎"}],"version":1},"nerd_face":{"id":"nerd_face","name":"Nerd Face","keywords":["nerdy","geek","dork"],"skins":[{"unified":"1f913","native":"🤓"}],"version":1},"face_with_monocle":{"id":"face_with_monocle","name":"Face with Monocle","keywords":["stuffy","wealthy"],"skins":[{"unified":"1f9d0","native":"🧐"}],"version":5},"confused":{"id":"confused","name":"Confused Face","emoticons":[":\\",":-\\",":/",":-/"],"keywords":["indifference","huh","weird","hmmm",":/"],"skins":[{"unified":"1f615","native":"😕"}],"version":1},"face_with_diagonal_mouth":{"id":"face_with_diagonal_mouth","name":"Face with Diagonal Mouth","keywords":["skeptic","confuse","frustrated","indifferent"],"skins":[{"unified":"1fae4","native":"🫤"}],"version":14},"worried":{"id":"worried","name":"Worried Face","keywords":["concern","nervous",":("],"skins":[{"unified":"1f61f","native":"😟"}],"version":1},"slightly_frowning_face":{"id":"slightly_frowning_face","name":"Slightly Frowning Face","keywords":["disappointed","sad","upset"],"skins":[{"unified":"1f641","native":"🙁"}],"version":1},"white_frowning_face":{"id":"white_frowning_face","name":"Frowning Face","keywords":["white","sad","upset","frown"],"skins":[{"unified":"2639-fe0f","native":"☹️"}],"version":1},"open_mouth":{"id":"open_mouth","name":"Face with Open Mouth","emoticons":[":o",":-o",":O",":-O"],"keywords":["surprise","impressed","wow","whoa",":O"],"skins":[{"unified":"1f62e","native":"😮"}],"version":1},"hushed":{"id":"hushed","name":"Hushed Face","keywords":["woo","shh"],"skins":[{"unified":"1f62f","native":"😯"}],"version":1},"astonished":{"id":"astonished","name":"Astonished Face","keywords":["xox","surprised","poisoned"],"skins":[{"unified":"1f632","native":"😲"}],"version":1},"flushed":{"id":"flushed","name":"Flushed Face","keywords":["blush","shy","flattered"],"skins":[{"unified":"1f633","native":"😳"}],"version":1},"pleading_face":{"id":"pleading_face","name":"Pleading Face","keywords":["begging","mercy","cry","tears","sad","grievance"],"skins":[{"unified":"1f97a","native":"🥺"}],"version":11},"face_holding_back_tears":{"id":"face_holding_back_tears","name":"Face Holding Back Tears","keywords":["touched","gratitude","cry"],"skins":[{"unified":"1f979","native":"🥹"}],"version":14},"frowning":{"id":"frowning","name":"Frowning Face with Open Mouth","keywords":["aw","what"],"skins":[{"unified":"1f626","native":"😦"}],"version":1},"anguished":{"id":"anguished","name":"Anguished Face","emoticons":["D:"],"keywords":["stunned","nervous"],"skins":[{"unified":"1f627","native":"😧"}],"version":1},"fearful":{"id":"fearful","name":"Fearful Face","keywords":["scared","terrified","nervous"],"skins":[{"unified":"1f628","native":"😨"}],"version":1},"cold_sweat":{"id":"cold_sweat","name":"Anxious Face with Sweat","keywords":["cold","nervous"],"skins":[{"unified":"1f630","native":"😰"}],"version":1},"disappointed_relieved":{"id":"disappointed_relieved","name":"Sad but Relieved Face","keywords":["disappointed","phew","sweat","nervous"],"skins":[{"unified":"1f625","native":"😥"}],"version":1},"cry":{"id":"cry","name":"Crying Face","emoticons":[":'("],"keywords":["cry","tears","sad","depressed","upset",":'("],"skins":[{"unified":"1f622","native":"😢"}],"version":1},"sob":{"id":"sob","name":"Loudly Crying Face","emoticons":[":'("],"keywords":["sob","cry","tears","sad","upset","depressed"],"skins":[{"unified":"1f62d","native":"😭"}],"version":1},"scream":{"id":"scream","name":"Face Screaming in Fear","keywords":["scream","munch","scared","omg"],"skins":[{"unified":"1f631","native":"😱"}],"version":1},"confounded":{"id":"confounded","name":"Confounded Face","keywords":["confused","sick","unwell","oops",":S"],"skins":[{"unified":"1f616","native":"😖"}],"version":1},"persevere":{"id":"persevere","name":"Persevering Face","keywords":["persevere","sick","no","upset","oops"],"skins":[{"unified":"1f623","native":"😣"}],"version":1},"disappointed":{"id":"disappointed","name":"Disappointed Face","emoticons":["):",":(",":-("],"keywords":["sad","upset","depressed",":("],"skins":[{"unified":"1f61e","native":"😞"}],"version":1},"sweat":{"id":"sweat","name":"Face with Cold Sweat","keywords":["downcast","hot","sad","tired","exercise"],"skins":[{"unified":"1f613","native":"😓"}],"version":1},"weary":{"id":"weary","name":"Weary Face","keywords":["tired","sleepy","sad","frustrated","upset"],"skins":[{"unified":"1f629","native":"😩"}],"version":1},"tired_face":{"id":"tired_face","name":"Tired Face","keywords":["sick","whine","upset","frustrated"],"skins":[{"unified":"1f62b","native":"😫"}],"version":1},"yawning_face":{"id":"yawning_face","name":"Yawning Face","keywords":["tired","sleepy"],"skins":[{"unified":"1f971","native":"🥱"}],"version":12},"triumph":{"id":"triumph","name":"Face with Look of Triumph","keywords":["steam","from","nose","gas","phew","proud","pride"],"skins":[{"unified":"1f624","native":"😤"}],"version":1},"rage":{"id":"rage","name":"Pouting Face","keywords":["rage","angry","mad","hate","despise"],"skins":[{"unified":"1f621","native":"😡"}],"version":1},"angry":{"id":"angry","name":"Angry Face","emoticons":[">:(",">:-("],"keywords":["mad","annoyed","frustrated"],"skins":[{"unified":"1f620","native":"😠"}],"version":1},"face_with_symbols_on_mouth":{"id":"face_with_symbols_on_mouth","name":"Face with Symbols on Mouth","keywords":["serious","covering","swearing","cursing","cussing","profanity","expletive"],"skins":[{"unified":"1f92c","native":"🤬"}],"version":5},"smiling_imp":{"id":"smiling_imp","name":"Smiling Face with Horns","keywords":["imp","devil"],"skins":[{"unified":"1f608","native":"😈"}],"version":1},"imp":{"id":"imp","name":"Imp","keywords":["angry","face","with","horns","devil"],"skins":[{"unified":"1f47f","native":"👿"}],"version":1},"skull":{"id":"skull","name":"Skull","keywords":["dead","skeleton","creepy","death"],"skins":[{"unified":"1f480","native":"💀"}],"version":1},"skull_and_crossbones":{"id":"skull_and_crossbones","name":"Skull and Crossbones","keywords":["poison","danger","deadly","scary","death","pirate","evil"],"skins":[{"unified":"2620-fe0f","native":"☠️"}],"version":1},"hankey":{"id":"hankey","name":"Pile of Poo","keywords":["hankey","poop","shit","shitface","fail","turd"],"skins":[{"unified":"1f4a9","native":"💩"}],"version":1},"clown_face":{"id":"clown_face","name":"Clown Face","keywords":[],"skins":[{"unified":"1f921","native":"🤡"}],"version":3},"japanese_ogre":{"id":"japanese_ogre","name":"Ogre","keywords":["japanese","monster","red","mask","halloween","scary","creepy","devil","demon"],"skins":[{"unified":"1f479","native":"👹"}],"version":1},"japanese_goblin":{"id":"japanese_goblin","name":"Goblin","keywords":["japanese","red","evil","mask","monster","scary","creepy"],"skins":[{"unified":"1f47a","native":"👺"}],"version":1},"ghost":{"id":"ghost","name":"Ghost","keywords":["halloween","spooky","scary"],"skins":[{"unified":"1f47b","native":"👻"}],"version":1},"alien":{"id":"alien","name":"Alien","keywords":["UFO","paul","weird","outer","space"],"skins":[{"unified":"1f47d","native":"👽"}],"version":1},"space_invader":{"id":"space_invader","name":"Alien Monster","keywords":["space","invader","game","arcade","play"],"skins":[{"unified":"1f47e","native":"👾"}],"version":1},"robot_face":{"id":"robot_face","name":"Robot","keywords":["face","computer","machine","bot"],"skins":[{"unified":"1f916","native":"🤖"}],"version":1},"smiley_cat":{"id":"smiley_cat","name":"Grinning Cat","keywords":["smiley","animal","cats","happy","smile"],"skins":[{"unified":"1f63a","native":"😺"}],"version":1},"smile_cat":{"id":"smile_cat","name":"Grinning Cat with Smiling Eyes","keywords":["smile","animal","cats"],"skins":[{"unified":"1f638","native":"😸"}],"version":1},"joy_cat":{"id":"joy_cat","name":"Cat with Tears of Joy","keywords":["animal","cats","haha","happy"],"skins":[{"unified":"1f639","native":"😹"}],"version":1},"heart_eyes_cat":{"id":"heart_eyes_cat","name":"Smiling Cat with Heart-Eyes","keywords":["heart","eyes","animal","love","like","affection","cats","valentines"],"skins":[{"unified":"1f63b","native":"😻"}],"version":1},"smirk_cat":{"id":"smirk_cat","name":"Cat with Wry Smile","keywords":["smirk","animal","cats"],"skins":[{"unified":"1f63c","native":"😼"}],"version":1},"kissing_cat":{"id":"kissing_cat","name":"Kissing Cat","keywords":["animal","cats","kiss"],"skins":[{"unified":"1f63d","native":"😽"}],"version":1},"scream_cat":{"id":"scream_cat","name":"Weary Cat","keywords":["scream","animal","cats","munch","scared"],"skins":[{"unified":"1f640","native":"🙀"}],"version":1},"crying_cat_face":{"id":"crying_cat_face","name":"Crying Cat","keywords":["face","animal","tears","weep","sad","cats","upset","cry"],"skins":[{"unified":"1f63f","native":"😿"}],"version":1},"pouting_cat":{"id":"pouting_cat","name":"Pouting Cat","keywords":["animal","cats"],"skins":[{"unified":"1f63e","native":"😾"}],"version":1},"see_no_evil":{"id":"see_no_evil","name":"See-No-Evil Monkey","keywords":["see","no","evil","animal","nature","haha"],"skins":[{"unified":"1f648","native":"🙈"}],"version":1},"hear_no_evil":{"id":"hear_no_evil","name":"Hear-No-Evil Monkey","keywords":["hear","no","evil","animal","nature"],"skins":[{"unified":"1f649","native":"🙉"}],"version":1},"speak_no_evil":{"id":"speak_no_evil","name":"Speak-No-Evil Monkey","keywords":["speak","no","evil","animal","nature","omg"],"skins":[{"unified":"1f64a","native":"🙊"}],"version":1},"love_letter":{"id":"love_letter","name":"Love Letter","keywords":["email","like","affection","envelope","valentines"],"skins":[{"unified":"1f48c","native":"💌"}],"version":1},"cupid":{"id":"cupid","name":"Heart with Arrow","keywords":["cupid","love","like","affection","valentines"],"skins":[{"unified":"1f498","native":"💘"}],"version":1},"gift_heart":{"id":"gift_heart","name":"Heart with Ribbon","keywords":["gift","love","valentines"],"skins":[{"unified":"1f49d","native":"💝"}],"version":1},"sparkling_heart":{"id":"sparkling_heart","name":"Sparkling Heart","keywords":["love","like","affection","valentines"],"skins":[{"unified":"1f496","native":"💖"}],"version":1},"heartpulse":{"id":"heartpulse","name":"Growing Heart","keywords":["heartpulse","like","love","affection","valentines","pink"],"skins":[{"unified":"1f497","native":"💗"}],"version":1},"heartbeat":{"id":"heartbeat","name":"Beating Heart","keywords":["heartbeat","love","like","affection","valentines","pink"],"skins":[{"unified":"1f493","native":"💓"}],"version":1},"revolving_hearts":{"id":"revolving_hearts","name":"Revolving Hearts","keywords":["love","like","affection","valentines"],"skins":[{"unified":"1f49e","native":"💞"}],"version":1},"two_hearts":{"id":"two_hearts","name":"Two Hearts","keywords":["love","like","affection","valentines","heart"],"skins":[{"unified":"1f495","native":"💕"}],"version":1},"heart_decoration":{"id":"heart_decoration","name":"Heart Decoration","keywords":["purple","square","love","like"],"skins":[{"unified":"1f49f","native":"💟"}],"version":1},"heavy_heart_exclamation_mark_ornament":{"id":"heavy_heart_exclamation_mark_ornament","name":"Heart Exclamation","keywords":["heavy","mark","ornament","decoration","love"],"skins":[{"unified":"2763-fe0f","native":"❣️"}],"version":1},"broken_heart":{"id":"broken_heart","name":"Broken Heart","emoticons":["3"],"keywords":["sad","sorry","break","heartbreak"],"skins":[{"unified":"1f494","native":"💔"}],"version":1},"heart_on_fire":{"id":"heart_on_fire","name":"Heart on Fire","keywords":["passionate","enthusiastic"],"skins":[{"unified":"2764-fe0f-200d-1f525","native":"❤️🔥"}],"version":13.1},"mending_heart":{"id":"mending_heart","name":"Mending Heart","keywords":["broken","bandage","wounded"],"skins":[{"unified":"2764-fe0f-200d-1fa79","native":"❤️🩹"}],"version":13.1},"heart":{"id":"heart","name":"Red Heart","emoticons":["<3"],"keywords":["love","like","valentines"],"skins":[{"unified":"2764-fe0f","native":"❤️"}],"version":1},"pink_heart":{"id":"pink_heart","name":"Pink Heart","keywords":["valentines"],"skins":[{"unified":"1fa77","native":"🩷"}],"version":15},"orange_heart":{"id":"orange_heart","name":"Orange Heart","keywords":["love","like","affection","valentines"],"skins":[{"unified":"1f9e1","native":"🧡"}],"version":5},"yellow_heart":{"id":"yellow_heart","name":"Yellow Heart","emoticons":["<3"],"keywords":["love","like","affection","valentines"],"skins":[{"unified":"1f49b","native":"💛"}],"version":1},"green_heart":{"id":"green_heart","name":"Green Heart","emoticons":["<3"],"keywords":["love","like","affection","valentines"],"skins":[{"unified":"1f49a","native":"💚"}],"version":1},"blue_heart":{"id":"blue_heart","name":"Blue Heart","emoticons":["<3"],"keywords":["love","like","affection","valentines"],"skins":[{"unified":"1f499","native":"💙"}],"version":1},"light_blue_heart":{"id":"light_blue_heart","name":"Light Blue Heart","keywords":["ice","baby"],"skins":[{"unified":"1fa75","native":"🩵"}],"version":15},"purple_heart":{"id":"purple_heart","name":"Purple Heart","emoticons":["<3"],"keywords":["love","like","affection","valentines"],"skins":[{"unified":"1f49c","native":"💜"}],"version":1},"brown_heart":{"id":"brown_heart","name":"Brown Heart","keywords":["coffee"],"skins":[{"unified":"1f90e","native":"🤎"}],"version":12},"black_heart":{"id":"black_heart","name":"Black Heart","keywords":["evil"],"skins":[{"unified":"1f5a4","native":"🖤"}],"version":3},"grey_heart":{"id":"grey_heart","name":"Grey Heart","keywords":["silver","monochrome"],"skins":[{"unified":"1fa76","native":"🩶"}],"version":15},"white_heart":{"id":"white_heart","name":"White Heart","keywords":["pure"],"skins":[{"unified":"1f90d","native":"🤍"}],"version":12},"kiss":{"id":"kiss","name":"Kiss Mark","keywords":["face","lips","love","like","affection","valentines"],"skins":[{"unified":"1f48b","native":"💋"}],"version":1},"anger":{"id":"anger","name":"Anger Symbol","keywords":["angry","mad"],"skins":[{"unified":"1f4a2","native":"💢"}],"version":1},"boom":{"id":"boom","name":"Collision","keywords":["boom","bomb","explode","explosion","blown"],"skins":[{"unified":"1f4a5","native":"💥"}],"version":1},"dizzy":{"id":"dizzy","name":"Dizzy","keywords":["star","sparkle","shoot","magic"],"skins":[{"unified":"1f4ab","native":"💫"}],"version":1},"sweat_drops":{"id":"sweat_drops","name":"Sweat Droplets","keywords":["drops","water","drip","oops"],"skins":[{"unified":"1f4a6","native":"💦"}],"version":1},"dash":{"id":"dash","name":"Dash Symbol","keywords":["dashing","away","wind","air","fast","shoo","fart","smoke","puff"],"skins":[{"unified":"1f4a8","native":"💨"}],"version":1},"hole":{"id":"hole","name":"Hole","keywords":["embarrassing"],"skins":[{"unified":"1f573-fe0f","native":"🕳️"}],"version":1},"speech_balloon":{"id":"speech_balloon","name":"Speech Balloon","keywords":["bubble","words","message","talk","chatting"],"skins":[{"unified":"1f4ac","native":"💬"}],"version":1},"eye-in-speech-bubble":{"id":"eye-in-speech-bubble","name":"Eye in Speech Bubble","keywords":["in-speech-bubble","info"],"skins":[{"unified":"1f441-fe0f-200d-1f5e8-fe0f","native":"👁️🗨️"}],"version":2},"left_speech_bubble":{"id":"left_speech_bubble","name":"Left Speech Bubble","keywords":["words","message","talk","chatting"],"skins":[{"unified":"1f5e8-fe0f","native":"🗨️"}],"version":2},"right_anger_bubble":{"id":"right_anger_bubble","name":"Right Anger Bubble","keywords":["caption","speech","thinking","mad"],"skins":[{"unified":"1f5ef-fe0f","native":"🗯️"}],"version":1},"thought_balloon":{"id":"thought_balloon","name":"Thought Balloon","keywords":["bubble","cloud","speech","thinking","dream"],"skins":[{"unified":"1f4ad","native":"💭"}],"version":1},"zzz":{"id":"zzz","name":"Zzz","keywords":["sleepy","tired","dream"],"skins":[{"unified":"1f4a4","native":"💤"}],"version":1},"wave":{"id":"wave","name":"Waving Hand","keywords":["wave","hands","gesture","goodbye","solong","farewell","hello","hi","palm"],"skins":[{"unified":"1f44b","native":"👋"},{"unified":"1f44b-1f3fb","native":"👋🏻"},{"unified":"1f44b-1f3fc","native":"👋🏼"},{"unified":"1f44b-1f3fd","native":"👋🏽"},{"unified":"1f44b-1f3fe","native":"👋🏾"},{"unified":"1f44b-1f3ff","native":"👋🏿"}],"version":1},"raised_back_of_hand":{"id":"raised_back_of_hand","name":"Raised Back of Hand","keywords":["fingers","backhand"],"skins":[{"unified":"1f91a","native":"🤚"},{"unified":"1f91a-1f3fb","native":"🤚🏻"},{"unified":"1f91a-1f3fc","native":"🤚🏼"},{"unified":"1f91a-1f3fd","native":"🤚🏽"},{"unified":"1f91a-1f3fe","native":"🤚🏾"},{"unified":"1f91a-1f3ff","native":"🤚🏿"}],"version":3},"raised_hand_with_fingers_splayed":{"id":"raised_hand_with_fingers_splayed","name":"Hand with Fingers Splayed","keywords":["raised","palm"],"skins":[{"unified":"1f590-fe0f","native":"🖐️"},{"unified":"1f590-1f3fb","native":"🖐🏻"},{"unified":"1f590-1f3fc","native":"🖐🏼"},{"unified":"1f590-1f3fd","native":"🖐🏽"},{"unified":"1f590-1f3fe","native":"🖐🏾"},{"unified":"1f590-1f3ff","native":"🖐🏿"}],"version":1},"hand":{"id":"hand","name":"Raised Hand","keywords":["fingers","stop","highfive","high","five","palm","ban"],"skins":[{"unified":"270b","native":"✋"},{"unified":"270b-1f3fb","native":"✋🏻"},{"unified":"270b-1f3fc","native":"✋🏼"},{"unified":"270b-1f3fd","native":"✋🏽"},{"unified":"270b-1f3fe","native":"✋🏾"},{"unified":"270b-1f3ff","native":"✋🏿"}],"version":1},"spock-hand":{"id":"spock-hand","name":"Vulcan Salute","keywords":["spock","hand","fingers","star","trek"],"skins":[{"unified":"1f596","native":"🖖"},{"unified":"1f596-1f3fb","native":"🖖🏻"},{"unified":"1f596-1f3fc","native":"🖖🏼"},{"unified":"1f596-1f3fd","native":"🖖🏽"},{"unified":"1f596-1f3fe","native":"🖖🏾"},{"unified":"1f596-1f3ff","native":"🖖🏿"}],"version":1},"rightwards_hand":{"id":"rightwards_hand","name":"Rightwards Hand","keywords":["palm","offer"],"skins":[{"unified":"1faf1","native":"🫱"},{"unified":"1faf1-1f3fb","native":"🫱🏻"},{"unified":"1faf1-1f3fc","native":"🫱🏼"},{"unified":"1faf1-1f3fd","native":"🫱🏽"},{"unified":"1faf1-1f3fe","native":"🫱🏾"},{"unified":"1faf1-1f3ff","native":"🫱🏿"}],"version":14},"leftwards_hand":{"id":"leftwards_hand","name":"Leftwards Hand","keywords":["palm","offer"],"skins":[{"unified":"1faf2","native":"🫲"},{"unified":"1faf2-1f3fb","native":"🫲🏻"},{"unified":"1faf2-1f3fc","native":"🫲🏼"},{"unified":"1faf2-1f3fd","native":"🫲🏽"},{"unified":"1faf2-1f3fe","native":"🫲🏾"},{"unified":"1faf2-1f3ff","native":"🫲🏿"}],"version":14},"palm_down_hand":{"id":"palm_down_hand","name":"Palm Down Hand","keywords":["drop"],"skins":[{"unified":"1faf3","native":"🫳"},{"unified":"1faf3-1f3fb","native":"🫳🏻"},{"unified":"1faf3-1f3fc","native":"🫳🏼"},{"unified":"1faf3-1f3fd","native":"🫳🏽"},{"unified":"1faf3-1f3fe","native":"🫳🏾"},{"unified":"1faf3-1f3ff","native":"🫳🏿"}],"version":14},"palm_up_hand":{"id":"palm_up_hand","name":"Palm Up Hand","keywords":["lift","offer","demand"],"skins":[{"unified":"1faf4","native":"🫴"},{"unified":"1faf4-1f3fb","native":"🫴🏻"},{"unified":"1faf4-1f3fc","native":"🫴🏼"},{"unified":"1faf4-1f3fd","native":"🫴🏽"},{"unified":"1faf4-1f3fe","native":"🫴🏾"},{"unified":"1faf4-1f3ff","native":"🫴🏿"}],"version":14},"leftwards_pushing_hand":{"id":"leftwards_pushing_hand","name":"Leftwards Pushing Hand","keywords":["highfive","high","five","pressing","stop"],"skins":[{"unified":"1faf7","native":"🫷"},{"unified":"1faf7-1f3fb","native":"🫷🏻"},{"unified":"1faf7-1f3fc","native":"🫷🏼"},{"unified":"1faf7-1f3fd","native":"🫷🏽"},{"unified":"1faf7-1f3fe","native":"🫷🏾"},{"unified":"1faf7-1f3ff","native":"🫷🏿"}],"version":15},"rightwards_pushing_hand":{"id":"rightwards_pushing_hand","name":"Rightwards Pushing Hand","keywords":["highfive","high","five","pressing","stop"],"skins":[{"unified":"1faf8","native":"🫸"},{"unified":"1faf8-1f3fb","native":"🫸🏻"},{"unified":"1faf8-1f3fc","native":"🫸🏼"},{"unified":"1faf8-1f3fd","native":"🫸🏽"},{"unified":"1faf8-1f3fe","native":"🫸🏾"},{"unified":"1faf8-1f3ff","native":"🫸🏿"}],"version":15},"ok_hand":{"id":"ok_hand","name":"Ok Hand","keywords":["fingers","limbs","perfect","okay"],"skins":[{"unified":"1f44c","native":"👌"},{"unified":"1f44c-1f3fb","native":"👌🏻"},{"unified":"1f44c-1f3fc","native":"👌🏼"},{"unified":"1f44c-1f3fd","native":"👌🏽"},{"unified":"1f44c-1f3fe","native":"👌🏾"},{"unified":"1f44c-1f3ff","native":"👌🏿"}],"version":1},"pinched_fingers":{"id":"pinched_fingers","name":"Pinched Fingers","keywords":["size","tiny","small"],"skins":[{"unified":"1f90c","native":"🤌"},{"unified":"1f90c-1f3fb","native":"🤌🏻"},{"unified":"1f90c-1f3fc","native":"🤌🏼"},{"unified":"1f90c-1f3fd","native":"🤌🏽"},{"unified":"1f90c-1f3fe","native":"🤌🏾"},{"unified":"1f90c-1f3ff","native":"🤌🏿"}],"version":13},"pinching_hand":{"id":"pinching_hand","name":"Pinching Hand","keywords":["tiny","small","size"],"skins":[{"unified":"1f90f","native":"🤏"},{"unified":"1f90f-1f3fb","native":"🤏🏻"},{"unified":"1f90f-1f3fc","native":"🤏🏼"},{"unified":"1f90f-1f3fd","native":"🤏🏽"},{"unified":"1f90f-1f3fe","native":"🤏🏾"},{"unified":"1f90f-1f3ff","native":"🤏🏿"}],"version":12},"v":{"id":"v","name":"Victory Hand","keywords":["v","fingers","ohyeah","peace","two"],"skins":[{"unified":"270c-fe0f","native":"✌️"},{"unified":"270c-1f3fb","native":"✌🏻"},{"unified":"270c-1f3fc","native":"✌🏼"},{"unified":"270c-1f3fd","native":"✌🏽"},{"unified":"270c-1f3fe","native":"✌🏾"},{"unified":"270c-1f3ff","native":"✌🏿"}],"version":1},"crossed_fingers":{"id":"crossed_fingers","name":"Crossed Fingers","keywords":["hand","with","index","and","middle","good","lucky"],"skins":[{"unified":"1f91e","native":"🤞"},{"unified":"1f91e-1f3fb","native":"🤞🏻"},{"unified":"1f91e-1f3fc","native":"🤞🏼"},{"unified":"1f91e-1f3fd","native":"🤞🏽"},{"unified":"1f91e-1f3fe","native":"🤞🏾"},{"unified":"1f91e-1f3ff","native":"🤞🏿"}],"version":3},"hand_with_index_finger_and_thumb_crossed":{"id":"hand_with_index_finger_and_thumb_crossed","name":"Hand with Index Finger and Thumb Crossed","keywords":["heart","love","money","expensive"],"skins":[{"unified":"1faf0","native":"🫰"},{"unified":"1faf0-1f3fb","native":"🫰🏻"},{"unified":"1faf0-1f3fc","native":"🫰🏼"},{"unified":"1faf0-1f3fd","native":"🫰🏽"},{"unified":"1faf0-1f3fe","native":"🫰🏾"},{"unified":"1faf0-1f3ff","native":"🫰🏿"}],"version":14},"i_love_you_hand_sign":{"id":"i_love_you_hand_sign","name":"Love-You Gesture","keywords":["i","love","you","hand","sign","fingers"],"skins":[{"unified":"1f91f","native":"🤟"},{"unified":"1f91f-1f3fb","native":"🤟🏻"},{"unified":"1f91f-1f3fc","native":"🤟🏼"},{"unified":"1f91f-1f3fd","native":"🤟🏽"},{"unified":"1f91f-1f3fe","native":"🤟🏾"},{"unified":"1f91f-1f3ff","native":"🤟🏿"}],"version":5},"the_horns":{"id":"the_horns","name":"Sign of the Horns","keywords":["hand","fingers","evil","eye","rock","on"],"skins":[{"unified":"1f918","native":"🤘"},{"unified":"1f918-1f3fb","native":"🤘🏻"},{"unified":"1f918-1f3fc","native":"🤘🏼"},{"unified":"1f918-1f3fd","native":"🤘🏽"},{"unified":"1f918-1f3fe","native":"🤘🏾"},{"unified":"1f918-1f3ff","native":"🤘🏿"}],"version":1},"call_me_hand":{"id":"call_me_hand","name":"Call Me Hand","keywords":["hands","gesture","shaka"],"skins":[{"unified":"1f919","native":"🤙"},{"unified":"1f919-1f3fb","native":"🤙🏻"},{"unified":"1f919-1f3fc","native":"🤙🏼"},{"unified":"1f919-1f3fd","native":"🤙🏽"},{"unified":"1f919-1f3fe","native":"🤙🏾"},{"unified":"1f919-1f3ff","native":"🤙🏿"}],"version":3},"point_left":{"id":"point_left","name":"Backhand Index Pointing Left","keywords":["point","direction","fingers","hand"],"skins":[{"unified":"1f448","native":"👈"},{"unified":"1f448-1f3fb","native":"👈🏻"},{"unified":"1f448-1f3fc","native":"👈🏼"},{"unified":"1f448-1f3fd","native":"👈🏽"},{"unified":"1f448-1f3fe","native":"👈🏾"},{"unified":"1f448-1f3ff","native":"👈🏿"}],"version":1},"point_right":{"id":"point_right","name":"Backhand Index Pointing Right","keywords":["point","fingers","hand","direction"],"skins":[{"unified":"1f449","native":"👉"},{"unified":"1f449-1f3fb","native":"👉🏻"},{"unified":"1f449-1f3fc","native":"👉🏼"},{"unified":"1f449-1f3fd","native":"👉🏽"},{"unified":"1f449-1f3fe","native":"👉🏾"},{"unified":"1f449-1f3ff","native":"👉🏿"}],"version":1},"point_up_2":{"id":"point_up_2","name":"Backhand Index Pointing Up","keywords":["point","2","fingers","hand","direction"],"skins":[{"unified":"1f446","native":"👆"},{"unified":"1f446-1f3fb","native":"👆🏻"},{"unified":"1f446-1f3fc","native":"👆🏼"},{"unified":"1f446-1f3fd","native":"👆🏽"},{"unified":"1f446-1f3fe","native":"👆🏾"},{"unified":"1f446-1f3ff","native":"👆🏿"}],"version":1},"middle_finger":{"id":"middle_finger","name":"Middle Finger","keywords":["reversed","hand","with","extended","fingers","rude","flipping"],"skins":[{"unified":"1f595","native":"🖕"},{"unified":"1f595-1f3fb","native":"🖕🏻"},{"unified":"1f595-1f3fc","native":"🖕🏼"},{"unified":"1f595-1f3fd","native":"🖕🏽"},{"unified":"1f595-1f3fe","native":"🖕🏾"},{"unified":"1f595-1f3ff","native":"🖕🏿"}],"version":1},"point_down":{"id":"point_down","name":"Backhand Index Pointing Down","keywords":["point","fingers","hand","direction"],"skins":[{"unified":"1f447","native":"👇"},{"unified":"1f447-1f3fb","native":"👇🏻"},{"unified":"1f447-1f3fc","native":"👇🏼"},{"unified":"1f447-1f3fd","native":"👇🏽"},{"unified":"1f447-1f3fe","native":"👇🏾"},{"unified":"1f447-1f3ff","native":"👇🏿"}],"version":1},"point_up":{"id":"point_up","name":"Index Pointing Up","keywords":["point","hand","fingers","direction"],"skins":[{"unified":"261d-fe0f","native":"☝️"},{"unified":"261d-1f3fb","native":"☝🏻"},{"unified":"261d-1f3fc","native":"☝🏼"},{"unified":"261d-1f3fd","native":"☝🏽"},{"unified":"261d-1f3fe","native":"☝🏾"},{"unified":"261d-1f3ff","native":"☝🏿"}],"version":1},"index_pointing_at_the_viewer":{"id":"index_pointing_at_the_viewer","name":"Index Pointing at the Viewer","keywords":["you","recruit"],"skins":[{"unified":"1faf5","native":"🫵"},{"unified":"1faf5-1f3fb","native":"🫵🏻"},{"unified":"1faf5-1f3fc","native":"🫵🏼"},{"unified":"1faf5-1f3fd","native":"🫵🏽"},{"unified":"1faf5-1f3fe","native":"🫵🏾"},{"unified":"1faf5-1f3ff","native":"🫵🏿"}],"version":14},"+1":{"id":"+1","name":"Thumbs Up","keywords":["+1","thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],"skins":[{"unified":"1f44d","native":"👍"},{"unified":"1f44d-1f3fb","native":"👍🏻"},{"unified":"1f44d-1f3fc","native":"👍🏼"},{"unified":"1f44d-1f3fd","native":"👍🏽"},{"unified":"1f44d-1f3fe","native":"👍🏾"},{"unified":"1f44d-1f3ff","native":"👍🏿"}],"version":1},"-1":{"id":"-1","name":"Thumbs Down","keywords":["-1","thumbsdown","no","dislike","hand"],"skins":[{"unified":"1f44e","native":"👎"},{"unified":"1f44e-1f3fb","native":"👎🏻"},{"unified":"1f44e-1f3fc","native":"👎🏼"},{"unified":"1f44e-1f3fd","native":"👎🏽"},{"unified":"1f44e-1f3fe","native":"👎🏾"},{"unified":"1f44e-1f3ff","native":"👎🏿"}],"version":1},"fist":{"id":"fist","name":"Raised Fist","keywords":["fingers","hand","grasp"],"skins":[{"unified":"270a","native":"✊"},{"unified":"270a-1f3fb","native":"✊🏻"},{"unified":"270a-1f3fc","native":"✊🏼"},{"unified":"270a-1f3fd","native":"✊🏽"},{"unified":"270a-1f3fe","native":"✊🏾"},{"unified":"270a-1f3ff","native":"✊🏿"}],"version":1},"facepunch":{"id":"facepunch","name":"Oncoming Fist","keywords":["facepunch","punch","angry","violence","hit","attack","hand"],"skins":[{"unified":"1f44a","native":"👊"},{"unified":"1f44a-1f3fb","native":"👊🏻"},{"unified":"1f44a-1f3fc","native":"👊🏼"},{"unified":"1f44a-1f3fd","native":"👊🏽"},{"unified":"1f44a-1f3fe","native":"👊🏾"},{"unified":"1f44a-1f3ff","native":"👊🏿"}],"version":1},"left-facing_fist":{"id":"left-facing_fist","name":"Left-Facing Fist","keywords":["left","facing","hand","fistbump"],"skins":[{"unified":"1f91b","native":"🤛"},{"unified":"1f91b-1f3fb","native":"🤛🏻"},{"unified":"1f91b-1f3fc","native":"🤛🏼"},{"unified":"1f91b-1f3fd","native":"🤛🏽"},{"unified":"1f91b-1f3fe","native":"🤛🏾"},{"unified":"1f91b-1f3ff","native":"🤛🏿"}],"version":3},"right-facing_fist":{"id":"right-facing_fist","name":"Right-Facing Fist","keywords":["right","facing","hand","fistbump"],"skins":[{"unified":"1f91c","native":"🤜"},{"unified":"1f91c-1f3fb","native":"🤜🏻"},{"unified":"1f91c-1f3fc","native":"🤜🏼"},{"unified":"1f91c-1f3fd","native":"🤜🏽"},{"unified":"1f91c-1f3fe","native":"🤜🏾"},{"unified":"1f91c-1f3ff","native":"🤜🏿"}],"version":3},"clap":{"id":"clap","name":"Clapping Hands","keywords":["clap","praise","applause","congrats","yay"],"skins":[{"unified":"1f44f","native":"👏"},{"unified":"1f44f-1f3fb","native":"👏🏻"},{"unified":"1f44f-1f3fc","native":"👏🏼"},{"unified":"1f44f-1f3fd","native":"👏🏽"},{"unified":"1f44f-1f3fe","native":"👏🏾"},{"unified":"1f44f-1f3ff","native":"👏🏿"}],"version":1},"raised_hands":{"id":"raised_hands","name":"Raising Hands","keywords":["raised","gesture","hooray","yea","celebration"],"skins":[{"unified":"1f64c","native":"🙌"},{"unified":"1f64c-1f3fb","native":"🙌🏻"},{"unified":"1f64c-1f3fc","native":"🙌🏼"},{"unified":"1f64c-1f3fd","native":"🙌🏽"},{"unified":"1f64c-1f3fe","native":"🙌🏾"},{"unified":"1f64c-1f3ff","native":"🙌🏿"}],"version":1},"heart_hands":{"id":"heart_hands","name":"Heart Hands","keywords":["love","appreciation","support"],"skins":[{"unified":"1faf6","native":"🫶"},{"unified":"1faf6-1f3fb","native":"🫶🏻"},{"unified":"1faf6-1f3fc","native":"🫶🏼"},{"unified":"1faf6-1f3fd","native":"🫶🏽"},{"unified":"1faf6-1f3fe","native":"🫶🏾"},{"unified":"1faf6-1f3ff","native":"🫶🏿"}],"version":14},"open_hands":{"id":"open_hands","name":"Open Hands","keywords":["fingers","butterfly"],"skins":[{"unified":"1f450","native":"👐"},{"unified":"1f450-1f3fb","native":"👐🏻"},{"unified":"1f450-1f3fc","native":"👐🏼"},{"unified":"1f450-1f3fd","native":"👐🏽"},{"unified":"1f450-1f3fe","native":"👐🏾"},{"unified":"1f450-1f3ff","native":"👐🏿"}],"version":1},"palms_up_together":{"id":"palms_up_together","name":"Palms Up Together","keywords":["hands","gesture","cupped","prayer"],"skins":[{"unified":"1f932","native":"🤲"},{"unified":"1f932-1f3fb","native":"🤲🏻"},{"unified":"1f932-1f3fc","native":"🤲🏼"},{"unified":"1f932-1f3fd","native":"🤲🏽"},{"unified":"1f932-1f3fe","native":"🤲🏾"},{"unified":"1f932-1f3ff","native":"🤲🏿"}],"version":5},"handshake":{"id":"handshake","name":"Handshake","keywords":["agreement","shake"],"skins":[{"unified":"1f91d","native":"🤝"},{"unified":"1f91d-1f3fb","native":"🤝🏻"},{"unified":"1f91d-1f3fc","native":"🤝🏼"},{"unified":"1f91d-1f3fd","native":"🤝🏽"},{"unified":"1f91d-1f3fe","native":"🤝🏾"},{"unified":"1f91d-1f3ff","native":"🤝🏿"}],"version":3},"pray":{"id":"pray","name":"Folded Hands","keywords":["pray","please","hope","wish","namaste","highfive","high","five","thank","you","thanks","appreciate"],"skins":[{"unified":"1f64f","native":"🙏"},{"unified":"1f64f-1f3fb","native":"🙏🏻"},{"unified":"1f64f-1f3fc","native":"🙏🏼"},{"unified":"1f64f-1f3fd","native":"🙏🏽"},{"unified":"1f64f-1f3fe","native":"🙏🏾"},{"unified":"1f64f-1f3ff","native":"🙏🏿"}],"version":1},"writing_hand":{"id":"writing_hand","name":"Writing Hand","keywords":["lower","left","ballpoint","pen","stationery","write","compose"],"skins":[{"unified":"270d-fe0f","native":"✍️"},{"unified":"270d-1f3fb","native":"✍🏻"},{"unified":"270d-1f3fc","native":"✍🏼"},{"unified":"270d-1f3fd","native":"✍🏽"},{"unified":"270d-1f3fe","native":"✍🏾"},{"unified":"270d-1f3ff","native":"✍🏿"}],"version":1},"nail_care":{"id":"nail_care","name":"Nail Polish","keywords":["care","beauty","manicure","finger","fashion"],"skins":[{"unified":"1f485","native":"💅"},{"unified":"1f485-1f3fb","native":"💅🏻"},{"unified":"1f485-1f3fc","native":"💅🏼"},{"unified":"1f485-1f3fd","native":"💅🏽"},{"unified":"1f485-1f3fe","native":"💅🏾"},{"unified":"1f485-1f3ff","native":"💅🏿"}],"version":1},"selfie":{"id":"selfie","name":"Selfie","keywords":["camera","phone"],"skins":[{"unified":"1f933","native":"🤳"},{"unified":"1f933-1f3fb","native":"🤳🏻"},{"unified":"1f933-1f3fc","native":"🤳🏼"},{"unified":"1f933-1f3fd","native":"🤳🏽"},{"unified":"1f933-1f3fe","native":"🤳🏾"},{"unified":"1f933-1f3ff","native":"🤳🏿"}],"version":3},"muscle":{"id":"muscle","name":"Flexed Biceps","keywords":["muscle","arm","flex","hand","summer","strong"],"skins":[{"unified":"1f4aa","native":"💪"},{"unified":"1f4aa-1f3fb","native":"💪🏻"},{"unified":"1f4aa-1f3fc","native":"💪🏼"},{"unified":"1f4aa-1f3fd","native":"💪🏽"},{"unified":"1f4aa-1f3fe","native":"💪🏾"},{"unified":"1f4aa-1f3ff","native":"💪🏿"}],"version":1},"mechanical_arm":{"id":"mechanical_arm","name":"Mechanical Arm","keywords":["accessibility"],"skins":[{"unified":"1f9be","native":"🦾"}],"version":12},"mechanical_leg":{"id":"mechanical_leg","name":"Mechanical Leg","keywords":["accessibility"],"skins":[{"unified":"1f9bf","native":"🦿"}],"version":12},"leg":{"id":"leg","name":"Leg","keywords":["kick","limb"],"skins":[{"unified":"1f9b5","native":"🦵"},{"unified":"1f9b5-1f3fb","native":"🦵🏻"},{"unified":"1f9b5-1f3fc","native":"🦵🏼"},{"unified":"1f9b5-1f3fd","native":"🦵🏽"},{"unified":"1f9b5-1f3fe","native":"🦵🏾"},{"unified":"1f9b5-1f3ff","native":"🦵🏿"}],"version":11},"foot":{"id":"foot","name":"Foot","keywords":["kick","stomp"],"skins":[{"unified":"1f9b6","native":"🦶"},{"unified":"1f9b6-1f3fb","native":"🦶🏻"},{"unified":"1f9b6-1f3fc","native":"🦶🏼"},{"unified":"1f9b6-1f3fd","native":"🦶🏽"},{"unified":"1f9b6-1f3fe","native":"🦶🏾"},{"unified":"1f9b6-1f3ff","native":"🦶🏿"}],"version":11},"ear":{"id":"ear","name":"Ear","keywords":["face","hear","sound","listen"],"skins":[{"unified":"1f442","native":"👂"},{"unified":"1f442-1f3fb","native":"👂🏻"},{"unified":"1f442-1f3fc","native":"👂🏼"},{"unified":"1f442-1f3fd","native":"👂🏽"},{"unified":"1f442-1f3fe","native":"👂🏾"},{"unified":"1f442-1f3ff","native":"👂🏿"}],"version":1},"ear_with_hearing_aid":{"id":"ear_with_hearing_aid","name":"Ear with Hearing Aid","keywords":["accessibility"],"skins":[{"unified":"1f9bb","native":"🦻"},{"unified":"1f9bb-1f3fb","native":"🦻🏻"},{"unified":"1f9bb-1f3fc","native":"🦻🏼"},{"unified":"1f9bb-1f3fd","native":"🦻🏽"},{"unified":"1f9bb-1f3fe","native":"🦻🏾"},{"unified":"1f9bb-1f3ff","native":"🦻🏿"}],"version":12},"nose":{"id":"nose","name":"Nose","keywords":["smell","sniff"],"skins":[{"unified":"1f443","native":"👃"},{"unified":"1f443-1f3fb","native":"👃🏻"},{"unified":"1f443-1f3fc","native":"👃🏼"},{"unified":"1f443-1f3fd","native":"👃🏽"},{"unified":"1f443-1f3fe","native":"👃🏾"},{"unified":"1f443-1f3ff","native":"👃🏿"}],"version":1},"brain":{"id":"brain","name":"Brain","keywords":["smart","intelligent"],"skins":[{"unified":"1f9e0","native":"🧠"}],"version":5},"anatomical_heart":{"id":"anatomical_heart","name":"Anatomical Heart","keywords":["health","heartbeat"],"skins":[{"unified":"1fac0","native":"🫀"}],"version":13},"lungs":{"id":"lungs","name":"Lungs","keywords":["breathe"],"skins":[{"unified":"1fac1","native":"🫁"}],"version":13},"tooth":{"id":"tooth","name":"Tooth","keywords":["teeth","dentist"],"skins":[{"unified":"1f9b7","native":"🦷"}],"version":11},"bone":{"id":"bone","name":"Bone","keywords":["skeleton"],"skins":[{"unified":"1f9b4","native":"🦴"}],"version":11},"eyes":{"id":"eyes","name":"Eyes","keywords":["look","watch","stalk","peek","see"],"skins":[{"unified":"1f440","native":"👀"}],"version":1},"eye":{"id":"eye","name":"Eye","keywords":["face","look","see","watch","stare"],"skins":[{"unified":"1f441-fe0f","native":"👁️"}],"version":1},"tongue":{"id":"tongue","name":"Tongue","keywords":["mouth","playful"],"skins":[{"unified":"1f445","native":"👅"}],"version":1},"lips":{"id":"lips","name":"Mouth","keywords":["lips","kiss"],"skins":[{"unified":"1f444","native":"👄"}],"version":1},"biting_lip":{"id":"biting_lip","name":"Biting Lip","keywords":["flirt","sexy","pain","worry"],"skins":[{"unified":"1fae6","native":"🫦"}],"version":14},"baby":{"id":"baby","name":"Baby","keywords":["child","boy","girl","toddler"],"skins":[{"unified":"1f476","native":"👶"},{"unified":"1f476-1f3fb","native":"👶🏻"},{"unified":"1f476-1f3fc","native":"👶🏼"},{"unified":"1f476-1f3fd","native":"👶🏽"},{"unified":"1f476-1f3fe","native":"👶🏾"},{"unified":"1f476-1f3ff","native":"👶🏿"}],"version":1},"child":{"id":"child","name":"Child","keywords":["gender","neutral","young"],"skins":[{"unified":"1f9d2","native":"🧒"},{"unified":"1f9d2-1f3fb","native":"🧒🏻"},{"unified":"1f9d2-1f3fc","native":"🧒🏼"},{"unified":"1f9d2-1f3fd","native":"🧒🏽"},{"unified":"1f9d2-1f3fe","native":"🧒🏾"},{"unified":"1f9d2-1f3ff","native":"🧒🏿"}],"version":5},"boy":{"id":"boy","name":"Boy","keywords":["man","male","guy","teenager"],"skins":[{"unified":"1f466","native":"👦"},{"unified":"1f466-1f3fb","native":"👦🏻"},{"unified":"1f466-1f3fc","native":"👦🏼"},{"unified":"1f466-1f3fd","native":"👦🏽"},{"unified":"1f466-1f3fe","native":"👦🏾"},{"unified":"1f466-1f3ff","native":"👦🏿"}],"version":1},"girl":{"id":"girl","name":"Girl","keywords":["female","woman","teenager"],"skins":[{"unified":"1f467","native":"👧"},{"unified":"1f467-1f3fb","native":"👧🏻"},{"unified":"1f467-1f3fc","native":"👧🏼"},{"unified":"1f467-1f3fd","native":"👧🏽"},{"unified":"1f467-1f3fe","native":"👧🏾"},{"unified":"1f467-1f3ff","native":"👧🏿"}],"version":1},"adult":{"id":"adult","name":"Adult","keywords":["person","gender","neutral"],"skins":[{"unified":"1f9d1","native":"🧑"},{"unified":"1f9d1-1f3fb","native":"🧑🏻"},{"unified":"1f9d1-1f3fc","native":"🧑🏼"},{"unified":"1f9d1-1f3fd","native":"🧑🏽"},{"unified":"1f9d1-1f3fe","native":"🧑🏾"},{"unified":"1f9d1-1f3ff","native":"🧑🏿"}],"version":5},"person_with_blond_hair":{"id":"person_with_blond_hair","name":"Person Blond Hair","keywords":["with","hairstyle"],"skins":[{"unified":"1f471","native":"👱"},{"unified":"1f471-1f3fb","native":"👱🏻"},{"unified":"1f471-1f3fc","native":"👱🏼"},{"unified":"1f471-1f3fd","native":"👱🏽"},{"unified":"1f471-1f3fe","native":"👱🏾"},{"unified":"1f471-1f3ff","native":"👱🏿"}],"version":1},"man":{"id":"man","name":"Man","keywords":["mustache","father","dad","guy","classy","sir","moustache"],"skins":[{"unified":"1f468","native":"👨"},{"unified":"1f468-1f3fb","native":"👨🏻"},{"unified":"1f468-1f3fc","native":"👨🏼"},{"unified":"1f468-1f3fd","native":"👨🏽"},{"unified":"1f468-1f3fe","native":"👨🏾"},{"unified":"1f468-1f3ff","native":"👨🏿"}],"version":1},"bearded_person":{"id":"bearded_person","name":"Person Beard","keywords":["bearded","man","bewhiskered"],"skins":[{"unified":"1f9d4","native":"🧔"},{"unified":"1f9d4-1f3fb","native":"🧔🏻"},{"unified":"1f9d4-1f3fc","native":"🧔🏼"},{"unified":"1f9d4-1f3fd","native":"🧔🏽"},{"unified":"1f9d4-1f3fe","native":"🧔🏾"},{"unified":"1f9d4-1f3ff","native":"🧔🏿"}],"version":5},"man_with_beard":{"id":"man_with_beard","name":"Man: Beard","keywords":["man","with","facial","hair"],"skins":[{"unified":"1f9d4-200d-2642-fe0f","native":"🧔♂️"},{"unified":"1f9d4-1f3fb-200d-2642-fe0f","native":"🧔🏻♂️"},{"unified":"1f9d4-1f3fc-200d-2642-fe0f","native":"🧔🏼♂️"},{"unified":"1f9d4-1f3fd-200d-2642-fe0f","native":"🧔🏽♂️"},{"unified":"1f9d4-1f3fe-200d-2642-fe0f","native":"🧔🏾♂️"},{"unified":"1f9d4-1f3ff-200d-2642-fe0f","native":"🧔🏿♂️"}],"version":13.1},"woman_with_beard":{"id":"woman_with_beard","name":"Woman: Beard","keywords":["woman","with","facial","hair"],"skins":[{"unified":"1f9d4-200d-2640-fe0f","native":"🧔♀️"},{"unified":"1f9d4-1f3fb-200d-2640-fe0f","native":"🧔🏻♀️"},{"unified":"1f9d4-1f3fc-200d-2640-fe0f","native":"🧔🏼♀️"},{"unified":"1f9d4-1f3fd-200d-2640-fe0f","native":"🧔🏽♀️"},{"unified":"1f9d4-1f3fe-200d-2640-fe0f","native":"🧔🏾♀️"},{"unified":"1f9d4-1f3ff-200d-2640-fe0f","native":"🧔🏿♀️"}],"version":13.1},"red_haired_man":{"id":"red_haired_man","name":"Man: Red Hair","keywords":["haired","man","hairstyle"],"skins":[{"unified":"1f468-200d-1f9b0","native":"👨🦰"},{"unified":"1f468-1f3fb-200d-1f9b0","native":"👨🏻🦰"},{"unified":"1f468-1f3fc-200d-1f9b0","native":"👨🏼🦰"},{"unified":"1f468-1f3fd-200d-1f9b0","native":"👨🏽🦰"},{"unified":"1f468-1f3fe-200d-1f9b0","native":"👨🏾🦰"},{"unified":"1f468-1f3ff-200d-1f9b0","native":"👨🏿🦰"}],"version":11},"curly_haired_man":{"id":"curly_haired_man","name":"Man: Curly Hair","keywords":["haired","man","hairstyle"],"skins":[{"unified":"1f468-200d-1f9b1","native":"👨🦱"},{"unified":"1f468-1f3fb-200d-1f9b1","native":"👨🏻🦱"},{"unified":"1f468-1f3fc-200d-1f9b1","native":"👨🏼🦱"},{"unified":"1f468-1f3fd-200d-1f9b1","native":"👨🏽🦱"},{"unified":"1f468-1f3fe-200d-1f9b1","native":"👨🏾🦱"},{"unified":"1f468-1f3ff-200d-1f9b1","native":"👨🏿🦱"}],"version":11},"white_haired_man":{"id":"white_haired_man","name":"Man: White Hair","keywords":["haired","man","old","elder"],"skins":[{"unified":"1f468-200d-1f9b3","native":"👨🦳"},{"unified":"1f468-1f3fb-200d-1f9b3","native":"👨🏻🦳"},{"unified":"1f468-1f3fc-200d-1f9b3","native":"👨🏼🦳"},{"unified":"1f468-1f3fd-200d-1f9b3","native":"👨🏽🦳"},{"unified":"1f468-1f3fe-200d-1f9b3","native":"👨🏾🦳"},{"unified":"1f468-1f3ff-200d-1f9b3","native":"👨🏿🦳"}],"version":11},"bald_man":{"id":"bald_man","name":"Man: Bald","keywords":["man","hairless"],"skins":[{"unified":"1f468-200d-1f9b2","native":"👨🦲"},{"unified":"1f468-1f3fb-200d-1f9b2","native":"👨🏻🦲"},{"unified":"1f468-1f3fc-200d-1f9b2","native":"👨🏼🦲"},{"unified":"1f468-1f3fd-200d-1f9b2","native":"👨🏽🦲"},{"unified":"1f468-1f3fe-200d-1f9b2","native":"👨🏾🦲"},{"unified":"1f468-1f3ff-200d-1f9b2","native":"👨🏿🦲"}],"version":11},"woman":{"id":"woman","name":"Woman","keywords":["female","girls","lady"],"skins":[{"unified":"1f469","native":"👩"},{"unified":"1f469-1f3fb","native":"👩🏻"},{"unified":"1f469-1f3fc","native":"👩🏼"},{"unified":"1f469-1f3fd","native":"👩🏽"},{"unified":"1f469-1f3fe","native":"👩🏾"},{"unified":"1f469-1f3ff","native":"👩🏿"}],"version":1},"red_haired_woman":{"id":"red_haired_woman","name":"Woman: Red Hair","keywords":["haired","woman","hairstyle"],"skins":[{"unified":"1f469-200d-1f9b0","native":"👩🦰"},{"unified":"1f469-1f3fb-200d-1f9b0","native":"👩🏻🦰"},{"unified":"1f469-1f3fc-200d-1f9b0","native":"👩🏼🦰"},{"unified":"1f469-1f3fd-200d-1f9b0","native":"👩🏽🦰"},{"unified":"1f469-1f3fe-200d-1f9b0","native":"👩🏾🦰"},{"unified":"1f469-1f3ff-200d-1f9b0","native":"👩🏿🦰"}],"version":11},"red_haired_person":{"id":"red_haired_person","name":"Person: Red Hair","keywords":["haired","person","hairstyle"],"skins":[{"unified":"1f9d1-200d-1f9b0","native":"🧑🦰"},{"unified":"1f9d1-1f3fb-200d-1f9b0","native":"🧑🏻🦰"},{"unified":"1f9d1-1f3fc-200d-1f9b0","native":"🧑🏼🦰"},{"unified":"1f9d1-1f3fd-200d-1f9b0","native":"🧑🏽🦰"},{"unified":"1f9d1-1f3fe-200d-1f9b0","native":"🧑🏾🦰"},{"unified":"1f9d1-1f3ff-200d-1f9b0","native":"🧑🏿🦰"}],"version":12.1},"curly_haired_woman":{"id":"curly_haired_woman","name":"Woman: Curly Hair","keywords":["haired","woman","hairstyle"],"skins":[{"unified":"1f469-200d-1f9b1","native":"👩🦱"},{"unified":"1f469-1f3fb-200d-1f9b1","native":"👩🏻🦱"},{"unified":"1f469-1f3fc-200d-1f9b1","native":"👩🏼🦱"},{"unified":"1f469-1f3fd-200d-1f9b1","native":"👩🏽🦱"},{"unified":"1f469-1f3fe-200d-1f9b1","native":"👩🏾🦱"},{"unified":"1f469-1f3ff-200d-1f9b1","native":"👩🏿🦱"}],"version":11},"curly_haired_person":{"id":"curly_haired_person","name":"Person: Curly Hair","keywords":["haired","person","hairstyle"],"skins":[{"unified":"1f9d1-200d-1f9b1","native":"🧑🦱"},{"unified":"1f9d1-1f3fb-200d-1f9b1","native":"🧑🏻🦱"},{"unified":"1f9d1-1f3fc-200d-1f9b1","native":"🧑🏼🦱"},{"unified":"1f9d1-1f3fd-200d-1f9b1","native":"🧑🏽🦱"},{"unified":"1f9d1-1f3fe-200d-1f9b1","native":"🧑🏾🦱"},{"unified":"1f9d1-1f3ff-200d-1f9b1","native":"🧑🏿🦱"}],"version":12.1},"white_haired_woman":{"id":"white_haired_woman","name":"Woman: White Hair","keywords":["haired","woman","old","elder"],"skins":[{"unified":"1f469-200d-1f9b3","native":"👩🦳"},{"unified":"1f469-1f3fb-200d-1f9b3","native":"👩🏻🦳"},{"unified":"1f469-1f3fc-200d-1f9b3","native":"👩🏼🦳"},{"unified":"1f469-1f3fd-200d-1f9b3","native":"👩🏽🦳"},{"unified":"1f469-1f3fe-200d-1f9b3","native":"👩🏾🦳"},{"unified":"1f469-1f3ff-200d-1f9b3","native":"👩🏿🦳"}],"version":11},"white_haired_person":{"id":"white_haired_person","name":"Person: White Hair","keywords":["haired","person","elder","old"],"skins":[{"unified":"1f9d1-200d-1f9b3","native":"🧑🦳"},{"unified":"1f9d1-1f3fb-200d-1f9b3","native":"🧑🏻🦳"},{"unified":"1f9d1-1f3fc-200d-1f9b3","native":"🧑🏼🦳"},{"unified":"1f9d1-1f3fd-200d-1f9b3","native":"🧑🏽🦳"},{"unified":"1f9d1-1f3fe-200d-1f9b3","native":"🧑🏾🦳"},{"unified":"1f9d1-1f3ff-200d-1f9b3","native":"🧑🏿🦳"}],"version":12.1},"bald_woman":{"id":"bald_woman","name":"Woman: Bald","keywords":["woman","hairless"],"skins":[{"unified":"1f469-200d-1f9b2","native":"👩🦲"},{"unified":"1f469-1f3fb-200d-1f9b2","native":"👩🏻🦲"},{"unified":"1f469-1f3fc-200d-1f9b2","native":"👩🏼🦲"},{"unified":"1f469-1f3fd-200d-1f9b2","native":"👩🏽🦲"},{"unified":"1f469-1f3fe-200d-1f9b2","native":"👩🏾🦲"},{"unified":"1f469-1f3ff-200d-1f9b2","native":"👩🏿🦲"}],"version":11},"bald_person":{"id":"bald_person","name":"Person: Bald","keywords":["person","hairless"],"skins":[{"unified":"1f9d1-200d-1f9b2","native":"🧑🦲"},{"unified":"1f9d1-1f3fb-200d-1f9b2","native":"🧑🏻🦲"},{"unified":"1f9d1-1f3fc-200d-1f9b2","native":"🧑🏼🦲"},{"unified":"1f9d1-1f3fd-200d-1f9b2","native":"🧑🏽🦲"},{"unified":"1f9d1-1f3fe-200d-1f9b2","native":"🧑🏾🦲"},{"unified":"1f9d1-1f3ff-200d-1f9b2","native":"🧑🏿🦲"}],"version":12.1},"blond-haired-woman":{"id":"blond-haired-woman","name":"Woman: Blond Hair","keywords":["haired-woman","woman","female","girl","blonde","person"],"skins":[{"unified":"1f471-200d-2640-fe0f","native":"👱♀️"},{"unified":"1f471-1f3fb-200d-2640-fe0f","native":"👱🏻♀️"},{"unified":"1f471-1f3fc-200d-2640-fe0f","native":"👱🏼♀️"},{"unified":"1f471-1f3fd-200d-2640-fe0f","native":"👱🏽♀️"},{"unified":"1f471-1f3fe-200d-2640-fe0f","native":"👱🏾♀️"},{"unified":"1f471-1f3ff-200d-2640-fe0f","native":"👱🏿♀️"}],"version":4},"blond-haired-man":{"id":"blond-haired-man","name":"Man: Blond Hair","keywords":["haired-man","man","male","boy","blonde","guy","person"],"skins":[{"unified":"1f471-200d-2642-fe0f","native":"👱♂️"},{"unified":"1f471-1f3fb-200d-2642-fe0f","native":"👱🏻♂️"},{"unified":"1f471-1f3fc-200d-2642-fe0f","native":"👱🏼♂️"},{"unified":"1f471-1f3fd-200d-2642-fe0f","native":"👱🏽♂️"},{"unified":"1f471-1f3fe-200d-2642-fe0f","native":"👱🏾♂️"},{"unified":"1f471-1f3ff-200d-2642-fe0f","native":"👱🏿♂️"}],"version":4},"older_adult":{"id":"older_adult","name":"Older Adult","keywords":["person","human","elder","senior","gender","neutral"],"skins":[{"unified":"1f9d3","native":"🧓"},{"unified":"1f9d3-1f3fb","native":"🧓🏻"},{"unified":"1f9d3-1f3fc","native":"🧓🏼"},{"unified":"1f9d3-1f3fd","native":"🧓🏽"},{"unified":"1f9d3-1f3fe","native":"🧓🏾"},{"unified":"1f9d3-1f3ff","native":"🧓🏿"}],"version":5},"older_man":{"id":"older_man","name":"Old Man","keywords":["older","human","male","men","elder","senior"],"skins":[{"unified":"1f474","native":"👴"},{"unified":"1f474-1f3fb","native":"👴🏻"},{"unified":"1f474-1f3fc","native":"👴🏼"},{"unified":"1f474-1f3fd","native":"👴🏽"},{"unified":"1f474-1f3fe","native":"👴🏾"},{"unified":"1f474-1f3ff","native":"👴🏿"}],"version":1},"older_woman":{"id":"older_woman","name":"Old Woman","keywords":["older","human","female","women","lady","elder","senior"],"skins":[{"unified":"1f475","native":"👵"},{"unified":"1f475-1f3fb","native":"👵🏻"},{"unified":"1f475-1f3fc","native":"👵🏼"},{"unified":"1f475-1f3fd","native":"👵🏽"},{"unified":"1f475-1f3fe","native":"👵🏾"},{"unified":"1f475-1f3ff","native":"👵🏿"}],"version":1},"person_frowning":{"id":"person_frowning","name":"Person Frowning","keywords":["worried"],"skins":[{"unified":"1f64d","native":"🙍"},{"unified":"1f64d-1f3fb","native":"🙍🏻"},{"unified":"1f64d-1f3fc","native":"🙍🏼"},{"unified":"1f64d-1f3fd","native":"🙍🏽"},{"unified":"1f64d-1f3fe","native":"🙍🏾"},{"unified":"1f64d-1f3ff","native":"🙍🏿"}],"version":1},"man-frowning":{"id":"man-frowning","name":"Man Frowning","keywords":["male","boy","sad","depressed","discouraged","unhappy"],"skins":[{"unified":"1f64d-200d-2642-fe0f","native":"🙍♂️"},{"unified":"1f64d-1f3fb-200d-2642-fe0f","native":"🙍🏻♂️"},{"unified":"1f64d-1f3fc-200d-2642-fe0f","native":"🙍🏼♂️"},{"unified":"1f64d-1f3fd-200d-2642-fe0f","native":"🙍🏽♂️"},{"unified":"1f64d-1f3fe-200d-2642-fe0f","native":"🙍🏾♂️"},{"unified":"1f64d-1f3ff-200d-2642-fe0f","native":"🙍🏿♂️"}],"version":4},"woman-frowning":{"id":"woman-frowning","name":"Woman Frowning","keywords":["female","girl","sad","depressed","discouraged","unhappy"],"skins":[{"unified":"1f64d-200d-2640-fe0f","native":"🙍♀️"},{"unified":"1f64d-1f3fb-200d-2640-fe0f","native":"🙍🏻♀️"},{"unified":"1f64d-1f3fc-200d-2640-fe0f","native":"🙍🏼♀️"},{"unified":"1f64d-1f3fd-200d-2640-fe0f","native":"🙍🏽♀️"},{"unified":"1f64d-1f3fe-200d-2640-fe0f","native":"🙍🏾♀️"},{"unified":"1f64d-1f3ff-200d-2640-fe0f","native":"🙍🏿♀️"}],"version":4},"person_with_pouting_face":{"id":"person_with_pouting_face","name":"Person Pouting","keywords":["with","face","upset"],"skins":[{"unified":"1f64e","native":"🙎"},{"unified":"1f64e-1f3fb","native":"🙎🏻"},{"unified":"1f64e-1f3fc","native":"🙎🏼"},{"unified":"1f64e-1f3fd","native":"🙎🏽"},{"unified":"1f64e-1f3fe","native":"🙎🏾"},{"unified":"1f64e-1f3ff","native":"🙎🏿"}],"version":1},"man-pouting":{"id":"man-pouting","name":"Man Pouting","keywords":["male","boy"],"skins":[{"unified":"1f64e-200d-2642-fe0f","native":"🙎♂️"},{"unified":"1f64e-1f3fb-200d-2642-fe0f","native":"🙎🏻♂️"},{"unified":"1f64e-1f3fc-200d-2642-fe0f","native":"🙎🏼♂️"},{"unified":"1f64e-1f3fd-200d-2642-fe0f","native":"🙎🏽♂️"},{"unified":"1f64e-1f3fe-200d-2642-fe0f","native":"🙎🏾♂️"},{"unified":"1f64e-1f3ff-200d-2642-fe0f","native":"🙎🏿♂️"}],"version":4},"woman-pouting":{"id":"woman-pouting","name":"Woman Pouting","keywords":["female","girl"],"skins":[{"unified":"1f64e-200d-2640-fe0f","native":"🙎♀️"},{"unified":"1f64e-1f3fb-200d-2640-fe0f","native":"🙎🏻♀️"},{"unified":"1f64e-1f3fc-200d-2640-fe0f","native":"🙎🏼♀️"},{"unified":"1f64e-1f3fd-200d-2640-fe0f","native":"🙎🏽♀️"},{"unified":"1f64e-1f3fe-200d-2640-fe0f","native":"🙎🏾♀️"},{"unified":"1f64e-1f3ff-200d-2640-fe0f","native":"🙎🏿♀️"}],"version":4},"no_good":{"id":"no_good","name":"Person Gesturing No","keywords":["good","decline"],"skins":[{"unified":"1f645","native":"🙅"},{"unified":"1f645-1f3fb","native":"🙅🏻"},{"unified":"1f645-1f3fc","native":"🙅🏼"},{"unified":"1f645-1f3fd","native":"🙅🏽"},{"unified":"1f645-1f3fe","native":"🙅🏾"},{"unified":"1f645-1f3ff","native":"🙅🏿"}],"version":1},"man-gesturing-no":{"id":"man-gesturing-no","name":"Man Gesturing No","keywords":["gesturing-no","male","boy","nope"],"skins":[{"unified":"1f645-200d-2642-fe0f","native":"🙅♂️"},{"unified":"1f645-1f3fb-200d-2642-fe0f","native":"🙅🏻♂️"},{"unified":"1f645-1f3fc-200d-2642-fe0f","native":"🙅🏼♂️"},{"unified":"1f645-1f3fd-200d-2642-fe0f","native":"🙅🏽♂️"},{"unified":"1f645-1f3fe-200d-2642-fe0f","native":"🙅🏾♂️"},{"unified":"1f645-1f3ff-200d-2642-fe0f","native":"🙅🏿♂️"}],"version":4},"woman-gesturing-no":{"id":"woman-gesturing-no","name":"Woman Gesturing No","keywords":["gesturing-no","female","girl","nope"],"skins":[{"unified":"1f645-200d-2640-fe0f","native":"🙅♀️"},{"unified":"1f645-1f3fb-200d-2640-fe0f","native":"🙅🏻♀️"},{"unified":"1f645-1f3fc-200d-2640-fe0f","native":"🙅🏼♀️"},{"unified":"1f645-1f3fd-200d-2640-fe0f","native":"🙅🏽♀️"},{"unified":"1f645-1f3fe-200d-2640-fe0f","native":"🙅🏾♀️"},{"unified":"1f645-1f3ff-200d-2640-fe0f","native":"🙅🏿♀️"}],"version":4},"ok_woman":{"id":"ok_woman","name":"Person Gesturing Ok","keywords":["woman","agree"],"skins":[{"unified":"1f646","native":"🙆"},{"unified":"1f646-1f3fb","native":"🙆🏻"},{"unified":"1f646-1f3fc","native":"🙆🏼"},{"unified":"1f646-1f3fd","native":"🙆🏽"},{"unified":"1f646-1f3fe","native":"🙆🏾"},{"unified":"1f646-1f3ff","native":"🙆🏿"}],"version":1},"man-gesturing-ok":{"id":"man-gesturing-ok","name":"Man Gesturing Ok","keywords":["gesturing-ok","men","boy","male","blue","human"],"skins":[{"unified":"1f646-200d-2642-fe0f","native":"🙆♂️"},{"unified":"1f646-1f3fb-200d-2642-fe0f","native":"🙆🏻♂️"},{"unified":"1f646-1f3fc-200d-2642-fe0f","native":"🙆🏼♂️"},{"unified":"1f646-1f3fd-200d-2642-fe0f","native":"🙆🏽♂️"},{"unified":"1f646-1f3fe-200d-2642-fe0f","native":"🙆🏾♂️"},{"unified":"1f646-1f3ff-200d-2642-fe0f","native":"🙆🏿♂️"}],"version":4},"woman-gesturing-ok":{"id":"woman-gesturing-ok","name":"Woman Gesturing Ok","keywords":["gesturing-ok","women","girl","female","pink","human"],"skins":[{"unified":"1f646-200d-2640-fe0f","native":"🙆♀️"},{"unified":"1f646-1f3fb-200d-2640-fe0f","native":"🙆🏻♀️"},{"unified":"1f646-1f3fc-200d-2640-fe0f","native":"🙆🏼♀️"},{"unified":"1f646-1f3fd-200d-2640-fe0f","native":"🙆🏽♀️"},{"unified":"1f646-1f3fe-200d-2640-fe0f","native":"🙆🏾♀️"},{"unified":"1f646-1f3ff-200d-2640-fe0f","native":"🙆🏿♀️"}],"version":4},"information_desk_person":{"id":"information_desk_person","name":"Person Tipping Hand","keywords":["information","desk"],"skins":[{"unified":"1f481","native":"💁"},{"unified":"1f481-1f3fb","native":"💁🏻"},{"unified":"1f481-1f3fc","native":"💁🏼"},{"unified":"1f481-1f3fd","native":"💁🏽"},{"unified":"1f481-1f3fe","native":"💁🏾"},{"unified":"1f481-1f3ff","native":"💁🏿"}],"version":1},"man-tipping-hand":{"id":"man-tipping-hand","name":"Man Tipping Hand","keywords":["tipping-hand","male","boy","human","information"],"skins":[{"unified":"1f481-200d-2642-fe0f","native":"💁♂️"},{"unified":"1f481-1f3fb-200d-2642-fe0f","native":"💁🏻♂️"},{"unified":"1f481-1f3fc-200d-2642-fe0f","native":"💁🏼♂️"},{"unified":"1f481-1f3fd-200d-2642-fe0f","native":"💁🏽♂️"},{"unified":"1f481-1f3fe-200d-2642-fe0f","native":"💁🏾♂️"},{"unified":"1f481-1f3ff-200d-2642-fe0f","native":"💁🏿♂️"}],"version":4},"woman-tipping-hand":{"id":"woman-tipping-hand","name":"Woman Tipping Hand","keywords":["tipping-hand","female","girl","human","information"],"skins":[{"unified":"1f481-200d-2640-fe0f","native":"💁♀️"},{"unified":"1f481-1f3fb-200d-2640-fe0f","native":"💁🏻♀️"},{"unified":"1f481-1f3fc-200d-2640-fe0f","native":"💁🏼♀️"},{"unified":"1f481-1f3fd-200d-2640-fe0f","native":"💁🏽♀️"},{"unified":"1f481-1f3fe-200d-2640-fe0f","native":"💁🏾♀️"},{"unified":"1f481-1f3ff-200d-2640-fe0f","native":"💁🏿♀️"}],"version":4},"raising_hand":{"id":"raising_hand","name":"Person Raising Hand","keywords":["question"],"skins":[{"unified":"1f64b","native":"🙋"},{"unified":"1f64b-1f3fb","native":"🙋🏻"},{"unified":"1f64b-1f3fc","native":"🙋🏼"},{"unified":"1f64b-1f3fd","native":"🙋🏽"},{"unified":"1f64b-1f3fe","native":"🙋🏾"},{"unified":"1f64b-1f3ff","native":"🙋🏿"}],"version":1},"man-raising-hand":{"id":"man-raising-hand","name":"Man Raising Hand","keywords":["raising-hand","male","boy"],"skins":[{"unified":"1f64b-200d-2642-fe0f","native":"🙋♂️"},{"unified":"1f64b-1f3fb-200d-2642-fe0f","native":"🙋🏻♂️"},{"unified":"1f64b-1f3fc-200d-2642-fe0f","native":"🙋🏼♂️"},{"unified":"1f64b-1f3fd-200d-2642-fe0f","native":"🙋🏽♂️"},{"unified":"1f64b-1f3fe-200d-2642-fe0f","native":"🙋🏾♂️"},{"unified":"1f64b-1f3ff-200d-2642-fe0f","native":"🙋🏿♂️"}],"version":4},"woman-raising-hand":{"id":"woman-raising-hand","name":"Woman Raising Hand","keywords":["raising-hand","female","girl"],"skins":[{"unified":"1f64b-200d-2640-fe0f","native":"🙋♀️"},{"unified":"1f64b-1f3fb-200d-2640-fe0f","native":"🙋🏻♀️"},{"unified":"1f64b-1f3fc-200d-2640-fe0f","native":"🙋🏼♀️"},{"unified":"1f64b-1f3fd-200d-2640-fe0f","native":"🙋🏽♀️"},{"unified":"1f64b-1f3fe-200d-2640-fe0f","native":"🙋🏾♀️"},{"unified":"1f64b-1f3ff-200d-2640-fe0f","native":"🙋🏿♀️"}],"version":4},"deaf_person":{"id":"deaf_person","name":"Deaf Person","keywords":["accessibility"],"skins":[{"unified":"1f9cf","native":"🧏"},{"unified":"1f9cf-1f3fb","native":"🧏🏻"},{"unified":"1f9cf-1f3fc","native":"🧏🏼"},{"unified":"1f9cf-1f3fd","native":"🧏🏽"},{"unified":"1f9cf-1f3fe","native":"🧏🏾"},{"unified":"1f9cf-1f3ff","native":"🧏🏿"}],"version":12},"deaf_man":{"id":"deaf_man","name":"Deaf Man","keywords":["accessibility"],"skins":[{"unified":"1f9cf-200d-2642-fe0f","native":"🧏♂️"},{"unified":"1f9cf-1f3fb-200d-2642-fe0f","native":"🧏🏻♂️"},{"unified":"1f9cf-1f3fc-200d-2642-fe0f","native":"🧏🏼♂️"},{"unified":"1f9cf-1f3fd-200d-2642-fe0f","native":"🧏🏽♂️"},{"unified":"1f9cf-1f3fe-200d-2642-fe0f","native":"🧏🏾♂️"},{"unified":"1f9cf-1f3ff-200d-2642-fe0f","native":"🧏🏿♂️"}],"version":12},"deaf_woman":{"id":"deaf_woman","name":"Deaf Woman","keywords":["accessibility"],"skins":[{"unified":"1f9cf-200d-2640-fe0f","native":"🧏♀️"},{"unified":"1f9cf-1f3fb-200d-2640-fe0f","native":"🧏🏻♀️"},{"unified":"1f9cf-1f3fc-200d-2640-fe0f","native":"🧏🏼♀️"},{"unified":"1f9cf-1f3fd-200d-2640-fe0f","native":"🧏🏽♀️"},{"unified":"1f9cf-1f3fe-200d-2640-fe0f","native":"🧏🏾♀️"},{"unified":"1f9cf-1f3ff-200d-2640-fe0f","native":"🧏🏿♀️"}],"version":12},"bow":{"id":"bow","name":"Person Bowing","keywords":["bow","respectiful"],"skins":[{"unified":"1f647","native":"🙇"},{"unified":"1f647-1f3fb","native":"🙇🏻"},{"unified":"1f647-1f3fc","native":"🙇🏼"},{"unified":"1f647-1f3fd","native":"🙇🏽"},{"unified":"1f647-1f3fe","native":"🙇🏾"},{"unified":"1f647-1f3ff","native":"🙇🏿"}],"version":1},"man-bowing":{"id":"man-bowing","name":"Man Bowing","keywords":["male","boy"],"skins":[{"unified":"1f647-200d-2642-fe0f","native":"🙇♂️"},{"unified":"1f647-1f3fb-200d-2642-fe0f","native":"🙇🏻♂️"},{"unified":"1f647-1f3fc-200d-2642-fe0f","native":"🙇🏼♂️"},{"unified":"1f647-1f3fd-200d-2642-fe0f","native":"🙇🏽♂️"},{"unified":"1f647-1f3fe-200d-2642-fe0f","native":"🙇🏾♂️"},{"unified":"1f647-1f3ff-200d-2642-fe0f","native":"🙇🏿♂️"}],"version":4},"woman-bowing":{"id":"woman-bowing","name":"Woman Bowing","keywords":["female","girl"],"skins":[{"unified":"1f647-200d-2640-fe0f","native":"🙇♀️"},{"unified":"1f647-1f3fb-200d-2640-fe0f","native":"🙇🏻♀️"},{"unified":"1f647-1f3fc-200d-2640-fe0f","native":"🙇🏼♀️"},{"unified":"1f647-1f3fd-200d-2640-fe0f","native":"🙇🏽♀️"},{"unified":"1f647-1f3fe-200d-2640-fe0f","native":"🙇🏾♀️"},{"unified":"1f647-1f3ff-200d-2640-fe0f","native":"🙇🏿♀️"}],"version":4},"face_palm":{"id":"face_palm","name":"Face Palm","keywords":["person","facepalming","disappointed"],"skins":[{"unified":"1f926","native":"🤦"},{"unified":"1f926-1f3fb","native":"🤦🏻"},{"unified":"1f926-1f3fc","native":"🤦🏼"},{"unified":"1f926-1f3fd","native":"🤦🏽"},{"unified":"1f926-1f3fe","native":"🤦🏾"},{"unified":"1f926-1f3ff","native":"🤦🏿"}],"version":3},"man-facepalming":{"id":"man-facepalming","name":"Man Facepalming","keywords":["male","boy","disbelief"],"skins":[{"unified":"1f926-200d-2642-fe0f","native":"🤦♂️"},{"unified":"1f926-1f3fb-200d-2642-fe0f","native":"🤦🏻♂️"},{"unified":"1f926-1f3fc-200d-2642-fe0f","native":"🤦🏼♂️"},{"unified":"1f926-1f3fd-200d-2642-fe0f","native":"🤦🏽♂️"},{"unified":"1f926-1f3fe-200d-2642-fe0f","native":"🤦🏾♂️"},{"unified":"1f926-1f3ff-200d-2642-fe0f","native":"🤦🏿♂️"}],"version":4},"woman-facepalming":{"id":"woman-facepalming","name":"Woman Facepalming","keywords":["female","girl","disbelief"],"skins":[{"unified":"1f926-200d-2640-fe0f","native":"🤦♀️"},{"unified":"1f926-1f3fb-200d-2640-fe0f","native":"🤦🏻♀️"},{"unified":"1f926-1f3fc-200d-2640-fe0f","native":"🤦🏼♀️"},{"unified":"1f926-1f3fd-200d-2640-fe0f","native":"🤦🏽♀️"},{"unified":"1f926-1f3fe-200d-2640-fe0f","native":"🤦🏾♀️"},{"unified":"1f926-1f3ff-200d-2640-fe0f","native":"🤦🏿♀️"}],"version":4},"shrug":{"id":"shrug","name":"Shrug","keywords":["person","shrugging","regardless"],"skins":[{"unified":"1f937","native":"🤷"},{"unified":"1f937-1f3fb","native":"🤷🏻"},{"unified":"1f937-1f3fc","native":"🤷🏼"},{"unified":"1f937-1f3fd","native":"🤷🏽"},{"unified":"1f937-1f3fe","native":"🤷🏾"},{"unified":"1f937-1f3ff","native":"🤷🏿"}],"version":3},"man-shrugging":{"id":"man-shrugging","name":"Man Shrugging","keywords":["male","boy","confused","indifferent","doubt"],"skins":[{"unified":"1f937-200d-2642-fe0f","native":"🤷♂️"},{"unified":"1f937-1f3fb-200d-2642-fe0f","native":"🤷🏻♂️"},{"unified":"1f937-1f3fc-200d-2642-fe0f","native":"🤷🏼♂️"},{"unified":"1f937-1f3fd-200d-2642-fe0f","native":"🤷🏽♂️"},{"unified":"1f937-1f3fe-200d-2642-fe0f","native":"🤷🏾♂️"},{"unified":"1f937-1f3ff-200d-2642-fe0f","native":"🤷🏿♂️"}],"version":4},"woman-shrugging":{"id":"woman-shrugging","name":"Woman Shrugging","keywords":["female","girl","confused","indifferent","doubt"],"skins":[{"unified":"1f937-200d-2640-fe0f","native":"🤷♀️"},{"unified":"1f937-1f3fb-200d-2640-fe0f","native":"🤷🏻♀️"},{"unified":"1f937-1f3fc-200d-2640-fe0f","native":"🤷🏼♀️"},{"unified":"1f937-1f3fd-200d-2640-fe0f","native":"🤷🏽♀️"},{"unified":"1f937-1f3fe-200d-2640-fe0f","native":"🤷🏾♀️"},{"unified":"1f937-1f3ff-200d-2640-fe0f","native":"🤷🏿♀️"}],"version":4},"health_worker":{"id":"health_worker","name":"Health Worker","keywords":["hospital"],"skins":[{"unified":"1f9d1-200d-2695-fe0f","native":"🧑⚕️"},{"unified":"1f9d1-1f3fb-200d-2695-fe0f","native":"🧑🏻⚕️"},{"unified":"1f9d1-1f3fc-200d-2695-fe0f","native":"🧑🏼⚕️"},{"unified":"1f9d1-1f3fd-200d-2695-fe0f","native":"🧑🏽⚕️"},{"unified":"1f9d1-1f3fe-200d-2695-fe0f","native":"🧑🏾⚕️"},{"unified":"1f9d1-1f3ff-200d-2695-fe0f","native":"🧑🏿⚕️"}],"version":12.1},"male-doctor":{"id":"male-doctor","name":"Man Health Worker","keywords":["male","doctor","nurse","therapist","healthcare","human"],"skins":[{"unified":"1f468-200d-2695-fe0f","native":"👨⚕️"},{"unified":"1f468-1f3fb-200d-2695-fe0f","native":"👨🏻⚕️"},{"unified":"1f468-1f3fc-200d-2695-fe0f","native":"👨🏼⚕️"},{"unified":"1f468-1f3fd-200d-2695-fe0f","native":"👨🏽⚕️"},{"unified":"1f468-1f3fe-200d-2695-fe0f","native":"👨🏾⚕️"},{"unified":"1f468-1f3ff-200d-2695-fe0f","native":"👨🏿⚕️"}],"version":4},"female-doctor":{"id":"female-doctor","name":"Woman Health Worker","keywords":["female","doctor","nurse","therapist","healthcare","human"],"skins":[{"unified":"1f469-200d-2695-fe0f","native":"👩⚕️"},{"unified":"1f469-1f3fb-200d-2695-fe0f","native":"👩🏻⚕️"},{"unified":"1f469-1f3fc-200d-2695-fe0f","native":"👩🏼⚕️"},{"unified":"1f469-1f3fd-200d-2695-fe0f","native":"👩🏽⚕️"},{"unified":"1f469-1f3fe-200d-2695-fe0f","native":"👩🏾⚕️"},{"unified":"1f469-1f3ff-200d-2695-fe0f","native":"👩🏿⚕️"}],"version":4},"student":{"id":"student","name":"Student","keywords":["learn"],"skins":[{"unified":"1f9d1-200d-1f393","native":"🧑🎓"},{"unified":"1f9d1-1f3fb-200d-1f393","native":"🧑🏻🎓"},{"unified":"1f9d1-1f3fc-200d-1f393","native":"🧑🏼🎓"},{"unified":"1f9d1-1f3fd-200d-1f393","native":"🧑🏽🎓"},{"unified":"1f9d1-1f3fe-200d-1f393","native":"🧑🏾🎓"},{"unified":"1f9d1-1f3ff-200d-1f393","native":"🧑🏿🎓"}],"version":12.1},"male-student":{"id":"male-student","name":"Man Student","keywords":["male","graduate","human"],"skins":[{"unified":"1f468-200d-1f393","native":"👨🎓"},{"unified":"1f468-1f3fb-200d-1f393","native":"👨🏻🎓"},{"unified":"1f468-1f3fc-200d-1f393","native":"👨🏼🎓"},{"unified":"1f468-1f3fd-200d-1f393","native":"👨🏽🎓"},{"unified":"1f468-1f3fe-200d-1f393","native":"👨🏾🎓"},{"unified":"1f468-1f3ff-200d-1f393","native":"👨🏿🎓"}],"version":4},"female-student":{"id":"female-student","name":"Woman Student","keywords":["female","graduate","human"],"skins":[{"unified":"1f469-200d-1f393","native":"👩🎓"},{"unified":"1f469-1f3fb-200d-1f393","native":"👩🏻🎓"},{"unified":"1f469-1f3fc-200d-1f393","native":"👩🏼🎓"},{"unified":"1f469-1f3fd-200d-1f393","native":"👩🏽🎓"},{"unified":"1f469-1f3fe-200d-1f393","native":"👩🏾🎓"},{"unified":"1f469-1f3ff-200d-1f393","native":"👩🏿🎓"}],"version":4},"teacher":{"id":"teacher","name":"Teacher","keywords":["professor"],"skins":[{"unified":"1f9d1-200d-1f3eb","native":"🧑🏫"},{"unified":"1f9d1-1f3fb-200d-1f3eb","native":"🧑🏻🏫"},{"unified":"1f9d1-1f3fc-200d-1f3eb","native":"🧑🏼🏫"},{"unified":"1f9d1-1f3fd-200d-1f3eb","native":"🧑🏽🏫"},{"unified":"1f9d1-1f3fe-200d-1f3eb","native":"🧑🏾🏫"},{"unified":"1f9d1-1f3ff-200d-1f3eb","native":"🧑🏿🏫"}],"version":12.1},"male-teacher":{"id":"male-teacher","name":"Man Teacher","keywords":["male","instructor","professor","human"],"skins":[{"unified":"1f468-200d-1f3eb","native":"👨🏫"},{"unified":"1f468-1f3fb-200d-1f3eb","native":"👨🏻🏫"},{"unified":"1f468-1f3fc-200d-1f3eb","native":"👨🏼🏫"},{"unified":"1f468-1f3fd-200d-1f3eb","native":"👨🏽🏫"},{"unified":"1f468-1f3fe-200d-1f3eb","native":"👨🏾🏫"},{"unified":"1f468-1f3ff-200d-1f3eb","native":"👨🏿🏫"}],"version":4},"female-teacher":{"id":"female-teacher","name":"Woman Teacher","keywords":["female","instructor","professor","human"],"skins":[{"unified":"1f469-200d-1f3eb","native":"👩🏫"},{"unified":"1f469-1f3fb-200d-1f3eb","native":"👩🏻🏫"},{"unified":"1f469-1f3fc-200d-1f3eb","native":"👩🏼🏫"},{"unified":"1f469-1f3fd-200d-1f3eb","native":"👩🏽🏫"},{"unified":"1f469-1f3fe-200d-1f3eb","native":"👩🏾🏫"},{"unified":"1f469-1f3ff-200d-1f3eb","native":"👩🏿🏫"}],"version":4},"judge":{"id":"judge","name":"Judge","keywords":["law"],"skins":[{"unified":"1f9d1-200d-2696-fe0f","native":"🧑⚖️"},{"unified":"1f9d1-1f3fb-200d-2696-fe0f","native":"🧑🏻⚖️"},{"unified":"1f9d1-1f3fc-200d-2696-fe0f","native":"🧑🏼⚖️"},{"unified":"1f9d1-1f3fd-200d-2696-fe0f","native":"🧑🏽⚖️"},{"unified":"1f9d1-1f3fe-200d-2696-fe0f","native":"🧑🏾⚖️"},{"unified":"1f9d1-1f3ff-200d-2696-fe0f","native":"🧑🏿⚖️"}],"version":12.1},"male-judge":{"id":"male-judge","name":"Man Judge","keywords":["male","justice","court","human"],"skins":[{"unified":"1f468-200d-2696-fe0f","native":"👨⚖️"},{"unified":"1f468-1f3fb-200d-2696-fe0f","native":"👨🏻⚖️"},{"unified":"1f468-1f3fc-200d-2696-fe0f","native":"👨🏼⚖️"},{"unified":"1f468-1f3fd-200d-2696-fe0f","native":"👨🏽⚖️"},{"unified":"1f468-1f3fe-200d-2696-fe0f","native":"👨🏾⚖️"},{"unified":"1f468-1f3ff-200d-2696-fe0f","native":"👨🏿⚖️"}],"version":4},"female-judge":{"id":"female-judge","name":"Woman Judge","keywords":["female","justice","court","human"],"skins":[{"unified":"1f469-200d-2696-fe0f","native":"👩⚖️"},{"unified":"1f469-1f3fb-200d-2696-fe0f","native":"👩🏻⚖️"},{"unified":"1f469-1f3fc-200d-2696-fe0f","native":"👩🏼⚖️"},{"unified":"1f469-1f3fd-200d-2696-fe0f","native":"👩🏽⚖️"},{"unified":"1f469-1f3fe-200d-2696-fe0f","native":"👩🏾⚖️"},{"unified":"1f469-1f3ff-200d-2696-fe0f","native":"👩🏿⚖️"}],"version":4},"farmer":{"id":"farmer","name":"Farmer","keywords":["crops"],"skins":[{"unified":"1f9d1-200d-1f33e","native":"🧑🌾"},{"unified":"1f9d1-1f3fb-200d-1f33e","native":"🧑🏻🌾"},{"unified":"1f9d1-1f3fc-200d-1f33e","native":"🧑🏼🌾"},{"unified":"1f9d1-1f3fd-200d-1f33e","native":"🧑🏽🌾"},{"unified":"1f9d1-1f3fe-200d-1f33e","native":"🧑🏾🌾"},{"unified":"1f9d1-1f3ff-200d-1f33e","native":"🧑🏿🌾"}],"version":12.1},"male-farmer":{"id":"male-farmer","name":"Man Farmer","keywords":["male","rancher","gardener","human"],"skins":[{"unified":"1f468-200d-1f33e","native":"👨🌾"},{"unified":"1f468-1f3fb-200d-1f33e","native":"👨🏻🌾"},{"unified":"1f468-1f3fc-200d-1f33e","native":"👨🏼🌾"},{"unified":"1f468-1f3fd-200d-1f33e","native":"👨🏽🌾"},{"unified":"1f468-1f3fe-200d-1f33e","native":"👨🏾🌾"},{"unified":"1f468-1f3ff-200d-1f33e","native":"👨🏿🌾"}],"version":4},"female-farmer":{"id":"female-farmer","name":"Woman Farmer","keywords":["female","rancher","gardener","human"],"skins":[{"unified":"1f469-200d-1f33e","native":"👩🌾"},{"unified":"1f469-1f3fb-200d-1f33e","native":"👩🏻🌾"},{"unified":"1f469-1f3fc-200d-1f33e","native":"👩🏼🌾"},{"unified":"1f469-1f3fd-200d-1f33e","native":"👩🏽🌾"},{"unified":"1f469-1f3fe-200d-1f33e","native":"👩🏾🌾"},{"unified":"1f469-1f3ff-200d-1f33e","native":"👩🏿🌾"}],"version":4},"cook":{"id":"cook","name":"Cook","keywords":["food","kitchen","culinary"],"skins":[{"unified":"1f9d1-200d-1f373","native":"🧑🍳"},{"unified":"1f9d1-1f3fb-200d-1f373","native":"🧑🏻🍳"},{"unified":"1f9d1-1f3fc-200d-1f373","native":"🧑🏼🍳"},{"unified":"1f9d1-1f3fd-200d-1f373","native":"🧑🏽🍳"},{"unified":"1f9d1-1f3fe-200d-1f373","native":"🧑🏾🍳"},{"unified":"1f9d1-1f3ff-200d-1f373","native":"🧑🏿🍳"}],"version":12.1},"male-cook":{"id":"male-cook","name":"Man Cook","keywords":["male","chef","human"],"skins":[{"unified":"1f468-200d-1f373","native":"👨🍳"},{"unified":"1f468-1f3fb-200d-1f373","native":"👨🏻🍳"},{"unified":"1f468-1f3fc-200d-1f373","native":"👨🏼🍳"},{"unified":"1f468-1f3fd-200d-1f373","native":"👨🏽🍳"},{"unified":"1f468-1f3fe-200d-1f373","native":"👨🏾🍳"},{"unified":"1f468-1f3ff-200d-1f373","native":"👨🏿🍳"}],"version":4},"female-cook":{"id":"female-cook","name":"Woman Cook","keywords":["female","chef","human"],"skins":[{"unified":"1f469-200d-1f373","native":"👩🍳"},{"unified":"1f469-1f3fb-200d-1f373","native":"👩🏻🍳"},{"unified":"1f469-1f3fc-200d-1f373","native":"👩🏼🍳"},{"unified":"1f469-1f3fd-200d-1f373","native":"👩🏽🍳"},{"unified":"1f469-1f3fe-200d-1f373","native":"👩🏾🍳"},{"unified":"1f469-1f3ff-200d-1f373","native":"👩🏿🍳"}],"version":4},"mechanic":{"id":"mechanic","name":"Mechanic","keywords":["worker","technician"],"skins":[{"unified":"1f9d1-200d-1f527","native":"🧑🔧"},{"unified":"1f9d1-1f3fb-200d-1f527","native":"🧑🏻🔧"},{"unified":"1f9d1-1f3fc-200d-1f527","native":"🧑🏼🔧"},{"unified":"1f9d1-1f3fd-200d-1f527","native":"🧑🏽🔧"},{"unified":"1f9d1-1f3fe-200d-1f527","native":"🧑🏾🔧"},{"unified":"1f9d1-1f3ff-200d-1f527","native":"🧑🏿🔧"}],"version":12.1},"male-mechanic":{"id":"male-mechanic","name":"Man Mechanic","keywords":["male","plumber","human","wrench"],"skins":[{"unified":"1f468-200d-1f527","native":"👨🔧"},{"unified":"1f468-1f3fb-200d-1f527","native":"👨🏻🔧"},{"unified":"1f468-1f3fc-200d-1f527","native":"👨🏼🔧"},{"unified":"1f468-1f3fd-200d-1f527","native":"👨🏽🔧"},{"unified":"1f468-1f3fe-200d-1f527","native":"👨🏾🔧"},{"unified":"1f468-1f3ff-200d-1f527","native":"👨🏿🔧"}],"version":4},"female-mechanic":{"id":"female-mechanic","name":"Woman Mechanic","keywords":["female","plumber","human","wrench"],"skins":[{"unified":"1f469-200d-1f527","native":"👩🔧"},{"unified":"1f469-1f3fb-200d-1f527","native":"👩🏻🔧"},{"unified":"1f469-1f3fc-200d-1f527","native":"👩🏼🔧"},{"unified":"1f469-1f3fd-200d-1f527","native":"👩🏽🔧"},{"unified":"1f469-1f3fe-200d-1f527","native":"👩🏾🔧"},{"unified":"1f469-1f3ff-200d-1f527","native":"👩🏿🔧"}],"version":4},"factory_worker":{"id":"factory_worker","name":"Factory Worker","keywords":["labor"],"skins":[{"unified":"1f9d1-200d-1f3ed","native":"🧑🏭"},{"unified":"1f9d1-1f3fb-200d-1f3ed","native":"🧑🏻🏭"},{"unified":"1f9d1-1f3fc-200d-1f3ed","native":"🧑🏼🏭"},{"unified":"1f9d1-1f3fd-200d-1f3ed","native":"🧑🏽🏭"},{"unified":"1f9d1-1f3fe-200d-1f3ed","native":"🧑🏾🏭"},{"unified":"1f9d1-1f3ff-200d-1f3ed","native":"🧑🏿🏭"}],"version":12.1},"male-factory-worker":{"id":"male-factory-worker","name":"Man Factory Worker","keywords":["male","factory-worker","assembly","industrial","human"],"skins":[{"unified":"1f468-200d-1f3ed","native":"👨🏭"},{"unified":"1f468-1f3fb-200d-1f3ed","native":"👨🏻🏭"},{"unified":"1f468-1f3fc-200d-1f3ed","native":"👨🏼🏭"},{"unified":"1f468-1f3fd-200d-1f3ed","native":"👨🏽🏭"},{"unified":"1f468-1f3fe-200d-1f3ed","native":"👨🏾🏭"},{"unified":"1f468-1f3ff-200d-1f3ed","native":"👨🏿🏭"}],"version":4},"female-factory-worker":{"id":"female-factory-worker","name":"Woman Factory Worker","keywords":["female","factory-worker","assembly","industrial","human"],"skins":[{"unified":"1f469-200d-1f3ed","native":"👩🏭"},{"unified":"1f469-1f3fb-200d-1f3ed","native":"👩🏻🏭"},{"unified":"1f469-1f3fc-200d-1f3ed","native":"👩🏼🏭"},{"unified":"1f469-1f3fd-200d-1f3ed","native":"👩🏽🏭"},{"unified":"1f469-1f3fe-200d-1f3ed","native":"👩🏾🏭"},{"unified":"1f469-1f3ff-200d-1f3ed","native":"👩🏿🏭"}],"version":4},"office_worker":{"id":"office_worker","name":"Office Worker","keywords":["business"],"skins":[{"unified":"1f9d1-200d-1f4bc","native":"🧑💼"},{"unified":"1f9d1-1f3fb-200d-1f4bc","native":"🧑🏻💼"},{"unified":"1f9d1-1f3fc-200d-1f4bc","native":"🧑🏼💼"},{"unified":"1f9d1-1f3fd-200d-1f4bc","native":"🧑🏽💼"},{"unified":"1f9d1-1f3fe-200d-1f4bc","native":"🧑🏾💼"},{"unified":"1f9d1-1f3ff-200d-1f4bc","native":"🧑🏿💼"}],"version":12.1},"male-office-worker":{"id":"male-office-worker","name":"Man Office Worker","keywords":["male","office-worker","business","manager","human"],"skins":[{"unified":"1f468-200d-1f4bc","native":"👨💼"},{"unified":"1f468-1f3fb-200d-1f4bc","native":"👨🏻💼"},{"unified":"1f468-1f3fc-200d-1f4bc","native":"👨🏼💼"},{"unified":"1f468-1f3fd-200d-1f4bc","native":"👨🏽💼"},{"unified":"1f468-1f3fe-200d-1f4bc","native":"👨🏾💼"},{"unified":"1f468-1f3ff-200d-1f4bc","native":"👨🏿💼"}],"version":4},"female-office-worker":{"id":"female-office-worker","name":"Woman Office Worker","keywords":["female","office-worker","business","manager","human"],"skins":[{"unified":"1f469-200d-1f4bc","native":"👩💼"},{"unified":"1f469-1f3fb-200d-1f4bc","native":"👩🏻💼"},{"unified":"1f469-1f3fc-200d-1f4bc","native":"👩🏼💼"},{"unified":"1f469-1f3fd-200d-1f4bc","native":"👩🏽💼"},{"unified":"1f469-1f3fe-200d-1f4bc","native":"👩🏾💼"},{"unified":"1f469-1f3ff-200d-1f4bc","native":"👩🏿💼"}],"version":4},"scientist":{"id":"scientist","name":"Scientist","keywords":["chemistry"],"skins":[{"unified":"1f9d1-200d-1f52c","native":"🧑🔬"},{"unified":"1f9d1-1f3fb-200d-1f52c","native":"🧑🏻🔬"},{"unified":"1f9d1-1f3fc-200d-1f52c","native":"🧑🏼🔬"},{"unified":"1f9d1-1f3fd-200d-1f52c","native":"🧑🏽🔬"},{"unified":"1f9d1-1f3fe-200d-1f52c","native":"🧑🏾🔬"},{"unified":"1f9d1-1f3ff-200d-1f52c","native":"🧑🏿🔬"}],"version":12.1},"male-scientist":{"id":"male-scientist","name":"Man Scientist","keywords":["male","biologist","chemist","engineer","physicist","human"],"skins":[{"unified":"1f468-200d-1f52c","native":"👨🔬"},{"unified":"1f468-1f3fb-200d-1f52c","native":"👨🏻🔬"},{"unified":"1f468-1f3fc-200d-1f52c","native":"👨🏼🔬"},{"unified":"1f468-1f3fd-200d-1f52c","native":"👨🏽🔬"},{"unified":"1f468-1f3fe-200d-1f52c","native":"👨🏾🔬"},{"unified":"1f468-1f3ff-200d-1f52c","native":"👨🏿🔬"}],"version":4},"female-scientist":{"id":"female-scientist","name":"Woman Scientist","keywords":["female","biologist","chemist","engineer","physicist","human"],"skins":[{"unified":"1f469-200d-1f52c","native":"👩🔬"},{"unified":"1f469-1f3fb-200d-1f52c","native":"👩🏻🔬"},{"unified":"1f469-1f3fc-200d-1f52c","native":"👩🏼🔬"},{"unified":"1f469-1f3fd-200d-1f52c","native":"👩🏽🔬"},{"unified":"1f469-1f3fe-200d-1f52c","native":"👩🏾🔬"},{"unified":"1f469-1f3ff-200d-1f52c","native":"👩🏿🔬"}],"version":4},"technologist":{"id":"technologist","name":"Technologist","keywords":["computer"],"skins":[{"unified":"1f9d1-200d-1f4bb","native":"🧑💻"},{"unified":"1f9d1-1f3fb-200d-1f4bb","native":"🧑🏻💻"},{"unified":"1f9d1-1f3fc-200d-1f4bb","native":"🧑🏼💻"},{"unified":"1f9d1-1f3fd-200d-1f4bb","native":"🧑🏽💻"},{"unified":"1f9d1-1f3fe-200d-1f4bb","native":"🧑🏾💻"},{"unified":"1f9d1-1f3ff-200d-1f4bb","native":"🧑🏿💻"}],"version":12.1},"male-technologist":{"id":"male-technologist","name":"Man Technologist","keywords":["male","coder","developer","engineer","programmer","software","human","laptop","computer"],"skins":[{"unified":"1f468-200d-1f4bb","native":"👨💻"},{"unified":"1f468-1f3fb-200d-1f4bb","native":"👨🏻💻"},{"unified":"1f468-1f3fc-200d-1f4bb","native":"👨🏼💻"},{"unified":"1f468-1f3fd-200d-1f4bb","native":"👨🏽💻"},{"unified":"1f468-1f3fe-200d-1f4bb","native":"👨🏾💻"},{"unified":"1f468-1f3ff-200d-1f4bb","native":"👨🏿💻"}],"version":4},"female-technologist":{"id":"female-technologist","name":"Woman Technologist","keywords":["female","coder","developer","engineer","programmer","software","human","laptop","computer"],"skins":[{"unified":"1f469-200d-1f4bb","native":"👩💻"},{"unified":"1f469-1f3fb-200d-1f4bb","native":"👩🏻💻"},{"unified":"1f469-1f3fc-200d-1f4bb","native":"👩🏼💻"},{"unified":"1f469-1f3fd-200d-1f4bb","native":"👩🏽💻"},{"unified":"1f469-1f3fe-200d-1f4bb","native":"👩🏾💻"},{"unified":"1f469-1f3ff-200d-1f4bb","native":"👩🏿💻"}],"version":4},"singer":{"id":"singer","name":"Singer","keywords":["song","artist","performer"],"skins":[{"unified":"1f9d1-200d-1f3a4","native":"🧑🎤"},{"unified":"1f9d1-1f3fb-200d-1f3a4","native":"🧑🏻🎤"},{"unified":"1f9d1-1f3fc-200d-1f3a4","native":"🧑🏼🎤"},{"unified":"1f9d1-1f3fd-200d-1f3a4","native":"🧑🏽🎤"},{"unified":"1f9d1-1f3fe-200d-1f3a4","native":"🧑🏾🎤"},{"unified":"1f9d1-1f3ff-200d-1f3a4","native":"🧑🏿🎤"}],"version":12.1},"male-singer":{"id":"male-singer","name":"Man Singer","keywords":["male","rockstar","entertainer","human"],"skins":[{"unified":"1f468-200d-1f3a4","native":"👨🎤"},{"unified":"1f468-1f3fb-200d-1f3a4","native":"👨🏻🎤"},{"unified":"1f468-1f3fc-200d-1f3a4","native":"👨🏼🎤"},{"unified":"1f468-1f3fd-200d-1f3a4","native":"👨🏽🎤"},{"unified":"1f468-1f3fe-200d-1f3a4","native":"👨🏾🎤"},{"unified":"1f468-1f3ff-200d-1f3a4","native":"👨🏿🎤"}],"version":4},"female-singer":{"id":"female-singer","name":"Woman Singer","keywords":["female","rockstar","entertainer","human"],"skins":[{"unified":"1f469-200d-1f3a4","native":"👩🎤"},{"unified":"1f469-1f3fb-200d-1f3a4","native":"👩🏻🎤"},{"unified":"1f469-1f3fc-200d-1f3a4","native":"👩🏼🎤"},{"unified":"1f469-1f3fd-200d-1f3a4","native":"👩🏽🎤"},{"unified":"1f469-1f3fe-200d-1f3a4","native":"👩🏾🎤"},{"unified":"1f469-1f3ff-200d-1f3a4","native":"👩🏿🎤"}],"version":4},"artist":{"id":"artist","name":"Artist","keywords":["painting","draw","creativity"],"skins":[{"unified":"1f9d1-200d-1f3a8","native":"🧑🎨"},{"unified":"1f9d1-1f3fb-200d-1f3a8","native":"🧑🏻🎨"},{"unified":"1f9d1-1f3fc-200d-1f3a8","native":"🧑🏼🎨"},{"unified":"1f9d1-1f3fd-200d-1f3a8","native":"🧑🏽🎨"},{"unified":"1f9d1-1f3fe-200d-1f3a8","native":"🧑🏾🎨"},{"unified":"1f9d1-1f3ff-200d-1f3a8","native":"🧑🏿🎨"}],"version":12.1},"male-artist":{"id":"male-artist","name":"Man Artist","keywords":["male","painter","human"],"skins":[{"unified":"1f468-200d-1f3a8","native":"👨🎨"},{"unified":"1f468-1f3fb-200d-1f3a8","native":"👨🏻🎨"},{"unified":"1f468-1f3fc-200d-1f3a8","native":"👨🏼🎨"},{"unified":"1f468-1f3fd-200d-1f3a8","native":"👨🏽🎨"},{"unified":"1f468-1f3fe-200d-1f3a8","native":"👨🏾🎨"},{"unified":"1f468-1f3ff-200d-1f3a8","native":"👨🏿🎨"}],"version":4},"female-artist":{"id":"female-artist","name":"Woman Artist","keywords":["female","painter","human"],"skins":[{"unified":"1f469-200d-1f3a8","native":"👩🎨"},{"unified":"1f469-1f3fb-200d-1f3a8","native":"👩🏻🎨"},{"unified":"1f469-1f3fc-200d-1f3a8","native":"👩🏼🎨"},{"unified":"1f469-1f3fd-200d-1f3a8","native":"👩🏽🎨"},{"unified":"1f469-1f3fe-200d-1f3a8","native":"👩🏾🎨"},{"unified":"1f469-1f3ff-200d-1f3a8","native":"👩🏿🎨"}],"version":4},"pilot":{"id":"pilot","name":"Pilot","keywords":["fly","plane","airplane"],"skins":[{"unified":"1f9d1-200d-2708-fe0f","native":"🧑✈️"},{"unified":"1f9d1-1f3fb-200d-2708-fe0f","native":"🧑🏻✈️"},{"unified":"1f9d1-1f3fc-200d-2708-fe0f","native":"🧑🏼✈️"},{"unified":"1f9d1-1f3fd-200d-2708-fe0f","native":"🧑🏽✈️"},{"unified":"1f9d1-1f3fe-200d-2708-fe0f","native":"🧑🏾✈️"},{"unified":"1f9d1-1f3ff-200d-2708-fe0f","native":"🧑🏿✈️"}],"version":12.1},"male-pilot":{"id":"male-pilot","name":"Man Pilot","keywords":["male","aviator","plane","human"],"skins":[{"unified":"1f468-200d-2708-fe0f","native":"👨✈️"},{"unified":"1f468-1f3fb-200d-2708-fe0f","native":"👨🏻✈️"},{"unified":"1f468-1f3fc-200d-2708-fe0f","native":"👨🏼✈️"},{"unified":"1f468-1f3fd-200d-2708-fe0f","native":"👨🏽✈️"},{"unified":"1f468-1f3fe-200d-2708-fe0f","native":"👨🏾✈️"},{"unified":"1f468-1f3ff-200d-2708-fe0f","native":"👨🏿✈️"}],"version":4},"female-pilot":{"id":"female-pilot","name":"Woman Pilot","keywords":["female","aviator","plane","human"],"skins":[{"unified":"1f469-200d-2708-fe0f","native":"👩✈️"},{"unified":"1f469-1f3fb-200d-2708-fe0f","native":"👩🏻✈️"},{"unified":"1f469-1f3fc-200d-2708-fe0f","native":"👩🏼✈️"},{"unified":"1f469-1f3fd-200d-2708-fe0f","native":"👩🏽✈️"},{"unified":"1f469-1f3fe-200d-2708-fe0f","native":"👩🏾✈️"},{"unified":"1f469-1f3ff-200d-2708-fe0f","native":"👩🏿✈️"}],"version":4},"astronaut":{"id":"astronaut","name":"Astronaut","keywords":["outerspace"],"skins":[{"unified":"1f9d1-200d-1f680","native":"🧑🚀"},{"unified":"1f9d1-1f3fb-200d-1f680","native":"🧑🏻🚀"},{"unified":"1f9d1-1f3fc-200d-1f680","native":"🧑🏼🚀"},{"unified":"1f9d1-1f3fd-200d-1f680","native":"🧑🏽🚀"},{"unified":"1f9d1-1f3fe-200d-1f680","native":"🧑🏾🚀"},{"unified":"1f9d1-1f3ff-200d-1f680","native":"🧑🏿🚀"}],"version":12.1},"male-astronaut":{"id":"male-astronaut","name":"Man Astronaut","keywords":["male","space","rocket","human"],"skins":[{"unified":"1f468-200d-1f680","native":"👨🚀"},{"unified":"1f468-1f3fb-200d-1f680","native":"👨🏻🚀"},{"unified":"1f468-1f3fc-200d-1f680","native":"👨🏼🚀"},{"unified":"1f468-1f3fd-200d-1f680","native":"👨🏽🚀"},{"unified":"1f468-1f3fe-200d-1f680","native":"👨🏾🚀"},{"unified":"1f468-1f3ff-200d-1f680","native":"👨🏿🚀"}],"version":4},"female-astronaut":{"id":"female-astronaut","name":"Woman Astronaut","keywords":["female","space","rocket","human"],"skins":[{"unified":"1f469-200d-1f680","native":"👩🚀"},{"unified":"1f469-1f3fb-200d-1f680","native":"👩🏻🚀"},{"unified":"1f469-1f3fc-200d-1f680","native":"👩🏼🚀"},{"unified":"1f469-1f3fd-200d-1f680","native":"👩🏽🚀"},{"unified":"1f469-1f3fe-200d-1f680","native":"👩🏾🚀"},{"unified":"1f469-1f3ff-200d-1f680","native":"👩🏿🚀"}],"version":4},"firefighter":{"id":"firefighter","name":"Firefighter","keywords":["fire"],"skins":[{"unified":"1f9d1-200d-1f692","native":"🧑🚒"},{"unified":"1f9d1-1f3fb-200d-1f692","native":"🧑🏻🚒"},{"unified":"1f9d1-1f3fc-200d-1f692","native":"🧑🏼🚒"},{"unified":"1f9d1-1f3fd-200d-1f692","native":"🧑🏽🚒"},{"unified":"1f9d1-1f3fe-200d-1f692","native":"🧑🏾🚒"},{"unified":"1f9d1-1f3ff-200d-1f692","native":"🧑🏿🚒"}],"version":12.1},"male-firefighter":{"id":"male-firefighter","name":"Man Firefighter","keywords":["male","fireman","human"],"skins":[{"unified":"1f468-200d-1f692","native":"👨🚒"},{"unified":"1f468-1f3fb-200d-1f692","native":"👨🏻🚒"},{"unified":"1f468-1f3fc-200d-1f692","native":"👨🏼🚒"},{"unified":"1f468-1f3fd-200d-1f692","native":"👨🏽🚒"},{"unified":"1f468-1f3fe-200d-1f692","native":"👨🏾🚒"},{"unified":"1f468-1f3ff-200d-1f692","native":"👨🏿🚒"}],"version":4},"female-firefighter":{"id":"female-firefighter","name":"Woman Firefighter","keywords":["female","fireman","human"],"skins":[{"unified":"1f469-200d-1f692","native":"👩🚒"},{"unified":"1f469-1f3fb-200d-1f692","native":"👩🏻🚒"},{"unified":"1f469-1f3fc-200d-1f692","native":"👩🏼🚒"},{"unified":"1f469-1f3fd-200d-1f692","native":"👩🏽🚒"},{"unified":"1f469-1f3fe-200d-1f692","native":"👩🏾🚒"},{"unified":"1f469-1f3ff-200d-1f692","native":"👩🏿🚒"}],"version":4},"cop":{"id":"cop","name":"Police Officer","keywords":["cop"],"skins":[{"unified":"1f46e","native":"👮"},{"unified":"1f46e-1f3fb","native":"👮🏻"},{"unified":"1f46e-1f3fc","native":"👮🏼"},{"unified":"1f46e-1f3fd","native":"👮🏽"},{"unified":"1f46e-1f3fe","native":"👮🏾"},{"unified":"1f46e-1f3ff","native":"👮🏿"}],"version":1},"male-police-officer":{"id":"male-police-officer","name":"Man Police Officer","keywords":["male","police-officer","law","legal","enforcement","arrest","911"],"skins":[{"unified":"1f46e-200d-2642-fe0f","native":"👮♂️"},{"unified":"1f46e-1f3fb-200d-2642-fe0f","native":"👮🏻♂️"},{"unified":"1f46e-1f3fc-200d-2642-fe0f","native":"👮🏼♂️"},{"unified":"1f46e-1f3fd-200d-2642-fe0f","native":"👮🏽♂️"},{"unified":"1f46e-1f3fe-200d-2642-fe0f","native":"👮🏾♂️"},{"unified":"1f46e-1f3ff-200d-2642-fe0f","native":"👮🏿♂️"}],"version":4},"female-police-officer":{"id":"female-police-officer","name":"Woman Police Officer","keywords":["female","police-officer","law","legal","enforcement","arrest","911"],"skins":[{"unified":"1f46e-200d-2640-fe0f","native":"👮♀️"},{"unified":"1f46e-1f3fb-200d-2640-fe0f","native":"👮🏻♀️"},{"unified":"1f46e-1f3fc-200d-2640-fe0f","native":"👮🏼♀️"},{"unified":"1f46e-1f3fd-200d-2640-fe0f","native":"👮🏽♀️"},{"unified":"1f46e-1f3fe-200d-2640-fe0f","native":"👮🏾♀️"},{"unified":"1f46e-1f3ff-200d-2640-fe0f","native":"👮🏿♀️"}],"version":4},"sleuth_or_spy":{"id":"sleuth_or_spy","name":"Detective","keywords":["sleuth","or","spy","human"],"skins":[{"unified":"1f575-fe0f","native":"🕵️"},{"unified":"1f575-1f3fb","native":"🕵🏻"},{"unified":"1f575-1f3fc","native":"🕵🏼"},{"unified":"1f575-1f3fd","native":"🕵🏽"},{"unified":"1f575-1f3fe","native":"🕵🏾"},{"unified":"1f575-1f3ff","native":"🕵🏿"}],"version":1},"male-detective":{"id":"male-detective","name":"Man Detective","keywords":["male","crime"],"skins":[{"unified":"1f575-fe0f-200d-2642-fe0f","native":"🕵️♂️"},{"unified":"1f575-1f3fb-200d-2642-fe0f","native":"🕵🏻♂️"},{"unified":"1f575-1f3fc-200d-2642-fe0f","native":"🕵🏼♂️"},{"unified":"1f575-1f3fd-200d-2642-fe0f","native":"🕵🏽♂️"},{"unified":"1f575-1f3fe-200d-2642-fe0f","native":"🕵🏾♂️"},{"unified":"1f575-1f3ff-200d-2642-fe0f","native":"🕵🏿♂️"}],"version":4},"female-detective":{"id":"female-detective","name":"Woman Detective","keywords":["female","human","spy"],"skins":[{"unified":"1f575-fe0f-200d-2640-fe0f","native":"🕵️♀️"},{"unified":"1f575-1f3fb-200d-2640-fe0f","native":"🕵🏻♀️"},{"unified":"1f575-1f3fc-200d-2640-fe0f","native":"🕵🏼♀️"},{"unified":"1f575-1f3fd-200d-2640-fe0f","native":"🕵🏽♀️"},{"unified":"1f575-1f3fe-200d-2640-fe0f","native":"🕵🏾♀️"},{"unified":"1f575-1f3ff-200d-2640-fe0f","native":"🕵🏿♀️"}],"version":4},"guardsman":{"id":"guardsman","name":"Guard","keywords":["guardsman","protect"],"skins":[{"unified":"1f482","native":"💂"},{"unified":"1f482-1f3fb","native":"💂🏻"},{"unified":"1f482-1f3fc","native":"💂🏼"},{"unified":"1f482-1f3fd","native":"💂🏽"},{"unified":"1f482-1f3fe","native":"💂🏾"},{"unified":"1f482-1f3ff","native":"💂🏿"}],"version":1},"male-guard":{"id":"male-guard","name":"Man Guard","keywords":["male","uk","gb","british","guy","royal"],"skins":[{"unified":"1f482-200d-2642-fe0f","native":"💂♂️"},{"unified":"1f482-1f3fb-200d-2642-fe0f","native":"💂🏻♂️"},{"unified":"1f482-1f3fc-200d-2642-fe0f","native":"💂🏼♂️"},{"unified":"1f482-1f3fd-200d-2642-fe0f","native":"💂🏽♂️"},{"unified":"1f482-1f3fe-200d-2642-fe0f","native":"💂🏾♂️"},{"unified":"1f482-1f3ff-200d-2642-fe0f","native":"💂🏿♂️"}],"version":4},"female-guard":{"id":"female-guard","name":"Woman Guard","keywords":["female","uk","gb","british","royal"],"skins":[{"unified":"1f482-200d-2640-fe0f","native":"💂♀️"},{"unified":"1f482-1f3fb-200d-2640-fe0f","native":"💂🏻♀️"},{"unified":"1f482-1f3fc-200d-2640-fe0f","native":"💂🏼♀️"},{"unified":"1f482-1f3fd-200d-2640-fe0f","native":"💂🏽♀️"},{"unified":"1f482-1f3fe-200d-2640-fe0f","native":"💂🏾♀️"},{"unified":"1f482-1f3ff-200d-2640-fe0f","native":"💂🏿♀️"}],"version":4},"ninja":{"id":"ninja","name":"Ninja","keywords":["ninjutsu","skills","japanese"],"skins":[{"unified":"1f977","native":"🥷"},{"unified":"1f977-1f3fb","native":"🥷🏻"},{"unified":"1f977-1f3fc","native":"🥷🏼"},{"unified":"1f977-1f3fd","native":"🥷🏽"},{"unified":"1f977-1f3fe","native":"🥷🏾"},{"unified":"1f977-1f3ff","native":"🥷🏿"}],"version":13},"construction_worker":{"id":"construction_worker","name":"Construction Worker","keywords":["labor","build"],"skins":[{"unified":"1f477","native":"👷"},{"unified":"1f477-1f3fb","native":"👷🏻"},{"unified":"1f477-1f3fc","native":"👷🏼"},{"unified":"1f477-1f3fd","native":"👷🏽"},{"unified":"1f477-1f3fe","native":"👷🏾"},{"unified":"1f477-1f3ff","native":"👷🏿"}],"version":1},"male-construction-worker":{"id":"male-construction-worker","name":"Man Construction Worker","keywords":["male","construction-worker","human","wip","guy","build","labor"],"skins":[{"unified":"1f477-200d-2642-fe0f","native":"👷♂️"},{"unified":"1f477-1f3fb-200d-2642-fe0f","native":"👷🏻♂️"},{"unified":"1f477-1f3fc-200d-2642-fe0f","native":"👷🏼♂️"},{"unified":"1f477-1f3fd-200d-2642-fe0f","native":"👷🏽♂️"},{"unified":"1f477-1f3fe-200d-2642-fe0f","native":"👷🏾♂️"},{"unified":"1f477-1f3ff-200d-2642-fe0f","native":"👷🏿♂️"}],"version":4},"female-construction-worker":{"id":"female-construction-worker","name":"Woman Construction Worker","keywords":["female","construction-worker","human","wip","build","labor"],"skins":[{"unified":"1f477-200d-2640-fe0f","native":"👷♀️"},{"unified":"1f477-1f3fb-200d-2640-fe0f","native":"👷🏻♀️"},{"unified":"1f477-1f3fc-200d-2640-fe0f","native":"👷🏼♀️"},{"unified":"1f477-1f3fd-200d-2640-fe0f","native":"👷🏽♀️"},{"unified":"1f477-1f3fe-200d-2640-fe0f","native":"👷🏾♀️"},{"unified":"1f477-1f3ff-200d-2640-fe0f","native":"👷🏿♀️"}],"version":4},"person_with_crown":{"id":"person_with_crown","name":"Person with Crown","keywords":["royalty","power"],"skins":[{"unified":"1fac5","native":"🫅"},{"unified":"1fac5-1f3fb","native":"🫅🏻"},{"unified":"1fac5-1f3fc","native":"🫅🏼"},{"unified":"1fac5-1f3fd","native":"🫅🏽"},{"unified":"1fac5-1f3fe","native":"🫅🏾"},{"unified":"1fac5-1f3ff","native":"🫅🏿"}],"version":14},"prince":{"id":"prince","name":"Prince","keywords":["boy","man","male","crown","royal","king"],"skins":[{"unified":"1f934","native":"🤴"},{"unified":"1f934-1f3fb","native":"🤴🏻"},{"unified":"1f934-1f3fc","native":"🤴🏼"},{"unified":"1f934-1f3fd","native":"🤴🏽"},{"unified":"1f934-1f3fe","native":"🤴🏾"},{"unified":"1f934-1f3ff","native":"🤴🏿"}],"version":3},"princess":{"id":"princess","name":"Princess","keywords":["girl","woman","female","blond","crown","royal","queen"],"skins":[{"unified":"1f478","native":"👸"},{"unified":"1f478-1f3fb","native":"👸🏻"},{"unified":"1f478-1f3fc","native":"👸🏼"},{"unified":"1f478-1f3fd","native":"👸🏽"},{"unified":"1f478-1f3fe","native":"👸🏾"},{"unified":"1f478-1f3ff","native":"👸🏿"}],"version":1},"man_with_turban":{"id":"man_with_turban","name":"Man with Turban","keywords":["person","wearing","headdress"],"skins":[{"unified":"1f473","native":"👳"},{"unified":"1f473-1f3fb","native":"👳🏻"},{"unified":"1f473-1f3fc","native":"👳🏼"},{"unified":"1f473-1f3fd","native":"👳🏽"},{"unified":"1f473-1f3fe","native":"👳🏾"},{"unified":"1f473-1f3ff","native":"👳🏿"}],"version":1},"man-wearing-turban":{"id":"man-wearing-turban","name":"Man Wearing Turban","keywords":["wearing-turban","male","indian","hinduism","arabs"],"skins":[{"unified":"1f473-200d-2642-fe0f","native":"👳♂️"},{"unified":"1f473-1f3fb-200d-2642-fe0f","native":"👳🏻♂️"},{"unified":"1f473-1f3fc-200d-2642-fe0f","native":"👳🏼♂️"},{"unified":"1f473-1f3fd-200d-2642-fe0f","native":"👳🏽♂️"},{"unified":"1f473-1f3fe-200d-2642-fe0f","native":"👳🏾♂️"},{"unified":"1f473-1f3ff-200d-2642-fe0f","native":"👳🏿♂️"}],"version":4},"woman-wearing-turban":{"id":"woman-wearing-turban","name":"Woman Wearing Turban","keywords":["wearing-turban","female","indian","hinduism","arabs"],"skins":[{"unified":"1f473-200d-2640-fe0f","native":"👳♀️"},{"unified":"1f473-1f3fb-200d-2640-fe0f","native":"👳🏻♀️"},{"unified":"1f473-1f3fc-200d-2640-fe0f","native":"👳🏼♀️"},{"unified":"1f473-1f3fd-200d-2640-fe0f","native":"👳🏽♀️"},{"unified":"1f473-1f3fe-200d-2640-fe0f","native":"👳🏾♀️"},{"unified":"1f473-1f3ff-200d-2640-fe0f","native":"👳🏿♀️"}],"version":4},"man_with_gua_pi_mao":{"id":"man_with_gua_pi_mao","name":"Man with Gua Pi Mao","keywords":["skullcap","male","boy","chinese"],"skins":[{"unified":"1f472","native":"👲"},{"unified":"1f472-1f3fb","native":"👲🏻"},{"unified":"1f472-1f3fc","native":"👲🏼"},{"unified":"1f472-1f3fd","native":"👲🏽"},{"unified":"1f472-1f3fe","native":"👲🏾"},{"unified":"1f472-1f3ff","native":"👲🏿"}],"version":1},"person_with_headscarf":{"id":"person_with_headscarf","name":"Woman with Headscarf","keywords":["person","female","hijab","mantilla","tichel"],"skins":[{"unified":"1f9d5","native":"🧕"},{"unified":"1f9d5-1f3fb","native":"🧕🏻"},{"unified":"1f9d5-1f3fc","native":"🧕🏼"},{"unified":"1f9d5-1f3fd","native":"🧕🏽"},{"unified":"1f9d5-1f3fe","native":"🧕🏾"},{"unified":"1f9d5-1f3ff","native":"🧕🏿"}],"version":5},"person_in_tuxedo":{"id":"person_in_tuxedo","name":"Man in Tuxedo","keywords":["person","couple","marriage","wedding","groom"],"skins":[{"unified":"1f935","native":"🤵"},{"unified":"1f935-1f3fb","native":"🤵🏻"},{"unified":"1f935-1f3fc","native":"🤵🏼"},{"unified":"1f935-1f3fd","native":"🤵🏽"},{"unified":"1f935-1f3fe","native":"🤵🏾"},{"unified":"1f935-1f3ff","native":"🤵🏿"}],"version":3},"man_in_tuxedo":{"id":"man_in_tuxedo","name":"Man in Tuxedo","keywords":["formal","fashion"],"skins":[{"unified":"1f935-200d-2642-fe0f","native":"🤵♂️"},{"unified":"1f935-1f3fb-200d-2642-fe0f","native":"🤵🏻♂️"},{"unified":"1f935-1f3fc-200d-2642-fe0f","native":"🤵🏼♂️"},{"unified":"1f935-1f3fd-200d-2642-fe0f","native":"🤵🏽♂️"},{"unified":"1f935-1f3fe-200d-2642-fe0f","native":"🤵🏾♂️"},{"unified":"1f935-1f3ff-200d-2642-fe0f","native":"🤵🏿♂️"}],"version":13},"woman_in_tuxedo":{"id":"woman_in_tuxedo","name":"Woman in Tuxedo","keywords":["formal","fashion"],"skins":[{"unified":"1f935-200d-2640-fe0f","native":"🤵♀️"},{"unified":"1f935-1f3fb-200d-2640-fe0f","native":"🤵🏻♀️"},{"unified":"1f935-1f3fc-200d-2640-fe0f","native":"🤵🏼♀️"},{"unified":"1f935-1f3fd-200d-2640-fe0f","native":"🤵🏽♀️"},{"unified":"1f935-1f3fe-200d-2640-fe0f","native":"🤵🏾♀️"},{"unified":"1f935-1f3ff-200d-2640-fe0f","native":"🤵🏿♀️"}],"version":13},"bride_with_veil":{"id":"bride_with_veil","name":"Bride with Veil","keywords":["couple","marriage","wedding","woman"],"skins":[{"unified":"1f470","native":"👰"},{"unified":"1f470-1f3fb","native":"👰🏻"},{"unified":"1f470-1f3fc","native":"👰🏼"},{"unified":"1f470-1f3fd","native":"👰🏽"},{"unified":"1f470-1f3fe","native":"👰🏾"},{"unified":"1f470-1f3ff","native":"👰🏿"}],"version":1},"man_with_veil":{"id":"man_with_veil","name":"Man with Veil","keywords":["wedding","marriage"],"skins":[{"unified":"1f470-200d-2642-fe0f","native":"👰♂️"},{"unified":"1f470-1f3fb-200d-2642-fe0f","native":"👰🏻♂️"},{"unified":"1f470-1f3fc-200d-2642-fe0f","native":"👰🏼♂️"},{"unified":"1f470-1f3fd-200d-2642-fe0f","native":"👰🏽♂️"},{"unified":"1f470-1f3fe-200d-2642-fe0f","native":"👰🏾♂️"},{"unified":"1f470-1f3ff-200d-2642-fe0f","native":"👰🏿♂️"}],"version":13},"woman_with_veil":{"id":"woman_with_veil","name":"Woman with Veil","keywords":["wedding","marriage"],"skins":[{"unified":"1f470-200d-2640-fe0f","native":"👰♀️"},{"unified":"1f470-1f3fb-200d-2640-fe0f","native":"👰🏻♀️"},{"unified":"1f470-1f3fc-200d-2640-fe0f","native":"👰🏼♀️"},{"unified":"1f470-1f3fd-200d-2640-fe0f","native":"👰🏽♀️"},{"unified":"1f470-1f3fe-200d-2640-fe0f","native":"👰🏾♀️"},{"unified":"1f470-1f3ff-200d-2640-fe0f","native":"👰🏿♀️"}],"version":13},"pregnant_woman":{"id":"pregnant_woman","name":"Pregnant Woman","keywords":["baby"],"skins":[{"unified":"1f930","native":"🤰"},{"unified":"1f930-1f3fb","native":"🤰🏻"},{"unified":"1f930-1f3fc","native":"🤰🏼"},{"unified":"1f930-1f3fd","native":"🤰🏽"},{"unified":"1f930-1f3fe","native":"🤰🏾"},{"unified":"1f930-1f3ff","native":"🤰🏿"}],"version":3},"pregnant_man":{"id":"pregnant_man","name":"Pregnant Man","keywords":["baby","belly"],"skins":[{"unified":"1fac3","native":"🫃"},{"unified":"1fac3-1f3fb","native":"🫃🏻"},{"unified":"1fac3-1f3fc","native":"🫃🏼"},{"unified":"1fac3-1f3fd","native":"🫃🏽"},{"unified":"1fac3-1f3fe","native":"🫃🏾"},{"unified":"1fac3-1f3ff","native":"🫃🏿"}],"version":14},"pregnant_person":{"id":"pregnant_person","name":"Pregnant Person","keywords":["baby","belly"],"skins":[{"unified":"1fac4","native":"🫄"},{"unified":"1fac4-1f3fb","native":"🫄🏻"},{"unified":"1fac4-1f3fc","native":"🫄🏼"},{"unified":"1fac4-1f3fd","native":"🫄🏽"},{"unified":"1fac4-1f3fe","native":"🫄🏾"},{"unified":"1fac4-1f3ff","native":"🫄🏿"}],"version":14},"breast-feeding":{"id":"breast-feeding","name":"Breast-Feeding","keywords":["breast","feeding","nursing","baby"],"skins":[{"unified":"1f931","native":"🤱"},{"unified":"1f931-1f3fb","native":"🤱🏻"},{"unified":"1f931-1f3fc","native":"🤱🏼"},{"unified":"1f931-1f3fd","native":"🤱🏽"},{"unified":"1f931-1f3fe","native":"🤱🏾"},{"unified":"1f931-1f3ff","native":"🤱🏿"}],"version":5},"woman_feeding_baby":{"id":"woman_feeding_baby","name":"Woman Feeding Baby","keywords":["birth","food"],"skins":[{"unified":"1f469-200d-1f37c","native":"👩🍼"},{"unified":"1f469-1f3fb-200d-1f37c","native":"👩🏻🍼"},{"unified":"1f469-1f3fc-200d-1f37c","native":"👩🏼🍼"},{"unified":"1f469-1f3fd-200d-1f37c","native":"👩🏽🍼"},{"unified":"1f469-1f3fe-200d-1f37c","native":"👩🏾🍼"},{"unified":"1f469-1f3ff-200d-1f37c","native":"👩🏿🍼"}],"version":13},"man_feeding_baby":{"id":"man_feeding_baby","name":"Man Feeding Baby","keywords":["birth","food"],"skins":[{"unified":"1f468-200d-1f37c","native":"👨🍼"},{"unified":"1f468-1f3fb-200d-1f37c","native":"👨🏻🍼"},{"unified":"1f468-1f3fc-200d-1f37c","native":"👨🏼🍼"},{"unified":"1f468-1f3fd-200d-1f37c","native":"👨🏽🍼"},{"unified":"1f468-1f3fe-200d-1f37c","native":"👨🏾🍼"},{"unified":"1f468-1f3ff-200d-1f37c","native":"👨🏿🍼"}],"version":13},"person_feeding_baby":{"id":"person_feeding_baby","name":"Person Feeding Baby","keywords":["birth","food"],"skins":[{"unified":"1f9d1-200d-1f37c","native":"🧑🍼"},{"unified":"1f9d1-1f3fb-200d-1f37c","native":"🧑🏻🍼"},{"unified":"1f9d1-1f3fc-200d-1f37c","native":"🧑🏼🍼"},{"unified":"1f9d1-1f3fd-200d-1f37c","native":"🧑🏽🍼"},{"unified":"1f9d1-1f3fe-200d-1f37c","native":"🧑🏾🍼"},{"unified":"1f9d1-1f3ff-200d-1f37c","native":"🧑🏿🍼"}],"version":13},"angel":{"id":"angel","name":"Baby Angel","keywords":["heaven","wings","halo"],"skins":[{"unified":"1f47c","native":"👼"},{"unified":"1f47c-1f3fb","native":"👼🏻"},{"unified":"1f47c-1f3fc","native":"👼🏼"},{"unified":"1f47c-1f3fd","native":"👼🏽"},{"unified":"1f47c-1f3fe","native":"👼🏾"},{"unified":"1f47c-1f3ff","native":"👼🏿"}],"version":1},"santa":{"id":"santa","name":"Santa Claus","keywords":["festival","man","male","xmas","father","christmas"],"skins":[{"unified":"1f385","native":"🎅"},{"unified":"1f385-1f3fb","native":"🎅🏻"},{"unified":"1f385-1f3fc","native":"🎅🏼"},{"unified":"1f385-1f3fd","native":"🎅🏽"},{"unified":"1f385-1f3fe","native":"🎅🏾"},{"unified":"1f385-1f3ff","native":"🎅🏿"}],"version":1},"mrs_claus":{"id":"mrs_claus","name":"Mrs. Claus","keywords":["mrs","mother","christmas","woman","female","xmas"],"skins":[{"unified":"1f936","native":"🤶"},{"unified":"1f936-1f3fb","native":"🤶🏻"},{"unified":"1f936-1f3fc","native":"🤶🏼"},{"unified":"1f936-1f3fd","native":"🤶🏽"},{"unified":"1f936-1f3fe","native":"🤶🏾"},{"unified":"1f936-1f3ff","native":"🤶🏿"}],"version":3},"mx_claus":{"id":"mx_claus","name":"Mx Claus","keywords":["christmas"],"skins":[{"unified":"1f9d1-200d-1f384","native":"🧑🎄"},{"unified":"1f9d1-1f3fb-200d-1f384","native":"🧑🏻🎄"},{"unified":"1f9d1-1f3fc-200d-1f384","native":"🧑🏼🎄"},{"unified":"1f9d1-1f3fd-200d-1f384","native":"🧑🏽🎄"},{"unified":"1f9d1-1f3fe-200d-1f384","native":"🧑🏾🎄"},{"unified":"1f9d1-1f3ff-200d-1f384","native":"🧑🏿🎄"}],"version":13},"superhero":{"id":"superhero","name":"Superhero","keywords":["marvel"],"skins":[{"unified":"1f9b8","native":"🦸"},{"unified":"1f9b8-1f3fb","native":"🦸🏻"},{"unified":"1f9b8-1f3fc","native":"🦸🏼"},{"unified":"1f9b8-1f3fd","native":"🦸🏽"},{"unified":"1f9b8-1f3fe","native":"🦸🏾"},{"unified":"1f9b8-1f3ff","native":"🦸🏿"}],"version":11},"male_superhero":{"id":"male_superhero","name":"Man Superhero","keywords":["male","good","hero","superpowers"],"skins":[{"unified":"1f9b8-200d-2642-fe0f","native":"🦸♂️"},{"unified":"1f9b8-1f3fb-200d-2642-fe0f","native":"🦸🏻♂️"},{"unified":"1f9b8-1f3fc-200d-2642-fe0f","native":"🦸🏼♂️"},{"unified":"1f9b8-1f3fd-200d-2642-fe0f","native":"🦸🏽♂️"},{"unified":"1f9b8-1f3fe-200d-2642-fe0f","native":"🦸🏾♂️"},{"unified":"1f9b8-1f3ff-200d-2642-fe0f","native":"🦸🏿♂️"}],"version":11},"female_superhero":{"id":"female_superhero","name":"Woman Superhero","keywords":["female","good","heroine","superpowers"],"skins":[{"unified":"1f9b8-200d-2640-fe0f","native":"🦸♀️"},{"unified":"1f9b8-1f3fb-200d-2640-fe0f","native":"🦸🏻♀️"},{"unified":"1f9b8-1f3fc-200d-2640-fe0f","native":"🦸🏼♀️"},{"unified":"1f9b8-1f3fd-200d-2640-fe0f","native":"🦸🏽♀️"},{"unified":"1f9b8-1f3fe-200d-2640-fe0f","native":"🦸🏾♀️"},{"unified":"1f9b8-1f3ff-200d-2640-fe0f","native":"🦸🏿♀️"}],"version":11},"supervillain":{"id":"supervillain","name":"Supervillain","keywords":["marvel"],"skins":[{"unified":"1f9b9","native":"🦹"},{"unified":"1f9b9-1f3fb","native":"🦹🏻"},{"unified":"1f9b9-1f3fc","native":"🦹🏼"},{"unified":"1f9b9-1f3fd","native":"🦹🏽"},{"unified":"1f9b9-1f3fe","native":"🦹🏾"},{"unified":"1f9b9-1f3ff","native":"🦹🏿"}],"version":11},"male_supervillain":{"id":"male_supervillain","name":"Man Supervillain","keywords":["male","evil","bad","criminal","hero","superpowers"],"skins":[{"unified":"1f9b9-200d-2642-fe0f","native":"🦹♂️"},{"unified":"1f9b9-1f3fb-200d-2642-fe0f","native":"🦹🏻♂️"},{"unified":"1f9b9-1f3fc-200d-2642-fe0f","native":"🦹🏼♂️"},{"unified":"1f9b9-1f3fd-200d-2642-fe0f","native":"🦹🏽♂️"},{"unified":"1f9b9-1f3fe-200d-2642-fe0f","native":"🦹🏾♂️"},{"unified":"1f9b9-1f3ff-200d-2642-fe0f","native":"🦹🏿♂️"}],"version":11},"female_supervillain":{"id":"female_supervillain","name":"Woman Supervillain","keywords":["female","evil","bad","criminal","heroine","superpowers"],"skins":[{"unified":"1f9b9-200d-2640-fe0f","native":"🦹♀️"},{"unified":"1f9b9-1f3fb-200d-2640-fe0f","native":"🦹🏻♀️"},{"unified":"1f9b9-1f3fc-200d-2640-fe0f","native":"🦹🏼♀️"},{"unified":"1f9b9-1f3fd-200d-2640-fe0f","native":"🦹🏽♀️"},{"unified":"1f9b9-1f3fe-200d-2640-fe0f","native":"🦹🏾♀️"},{"unified":"1f9b9-1f3ff-200d-2640-fe0f","native":"🦹🏿♀️"}],"version":11},"mage":{"id":"mage","name":"Mage","keywords":["magic"],"skins":[{"unified":"1f9d9","native":"🧙"},{"unified":"1f9d9-1f3fb","native":"🧙🏻"},{"unified":"1f9d9-1f3fc","native":"🧙🏼"},{"unified":"1f9d9-1f3fd","native":"🧙🏽"},{"unified":"1f9d9-1f3fe","native":"🧙🏾"},{"unified":"1f9d9-1f3ff","native":"🧙🏿"}],"version":5},"male_mage":{"id":"male_mage","name":"Man Mage","keywords":["male","sorcerer"],"skins":[{"unified":"1f9d9-200d-2642-fe0f","native":"🧙♂️"},{"unified":"1f9d9-1f3fb-200d-2642-fe0f","native":"🧙🏻♂️"},{"unified":"1f9d9-1f3fc-200d-2642-fe0f","native":"🧙🏼♂️"},{"unified":"1f9d9-1f3fd-200d-2642-fe0f","native":"🧙🏽♂️"},{"unified":"1f9d9-1f3fe-200d-2642-fe0f","native":"🧙🏾♂️"},{"unified":"1f9d9-1f3ff-200d-2642-fe0f","native":"🧙🏿♂️"}],"version":5},"female_mage":{"id":"female_mage","name":"Woman Mage","keywords":["female","witch"],"skins":[{"unified":"1f9d9-200d-2640-fe0f","native":"🧙♀️"},{"unified":"1f9d9-1f3fb-200d-2640-fe0f","native":"🧙🏻♀️"},{"unified":"1f9d9-1f3fc-200d-2640-fe0f","native":"🧙🏼♀️"},{"unified":"1f9d9-1f3fd-200d-2640-fe0f","native":"🧙🏽♀️"},{"unified":"1f9d9-1f3fe-200d-2640-fe0f","native":"🧙🏾♀️"},{"unified":"1f9d9-1f3ff-200d-2640-fe0f","native":"🧙🏿♀️"}],"version":5},"fairy":{"id":"fairy","name":"Fairy","keywords":["wings","magical"],"skins":[{"unified":"1f9da","native":"🧚"},{"unified":"1f9da-1f3fb","native":"🧚🏻"},{"unified":"1f9da-1f3fc","native":"🧚🏼"},{"unified":"1f9da-1f3fd","native":"🧚🏽"},{"unified":"1f9da-1f3fe","native":"🧚🏾"},{"unified":"1f9da-1f3ff","native":"🧚🏿"}],"version":5},"male_fairy":{"id":"male_fairy","name":"Man Fairy","keywords":["male"],"skins":[{"unified":"1f9da-200d-2642-fe0f","native":"🧚♂️"},{"unified":"1f9da-1f3fb-200d-2642-fe0f","native":"🧚🏻♂️"},{"unified":"1f9da-1f3fc-200d-2642-fe0f","native":"🧚🏼♂️"},{"unified":"1f9da-1f3fd-200d-2642-fe0f","native":"🧚🏽♂️"},{"unified":"1f9da-1f3fe-200d-2642-fe0f","native":"🧚🏾♂️"},{"unified":"1f9da-1f3ff-200d-2642-fe0f","native":"🧚🏿♂️"}],"version":5},"female_fairy":{"id":"female_fairy","name":"Woman Fairy","keywords":["female"],"skins":[{"unified":"1f9da-200d-2640-fe0f","native":"🧚♀️"},{"unified":"1f9da-1f3fb-200d-2640-fe0f","native":"🧚🏻♀️"},{"unified":"1f9da-1f3fc-200d-2640-fe0f","native":"🧚🏼♀️"},{"unified":"1f9da-1f3fd-200d-2640-fe0f","native":"🧚🏽♀️"},{"unified":"1f9da-1f3fe-200d-2640-fe0f","native":"🧚🏾♀️"},{"unified":"1f9da-1f3ff-200d-2640-fe0f","native":"🧚🏿♀️"}],"version":5},"vampire":{"id":"vampire","name":"Vampire","keywords":["blood","twilight"],"skins":[{"unified":"1f9db","native":"🧛"},{"unified":"1f9db-1f3fb","native":"🧛🏻"},{"unified":"1f9db-1f3fc","native":"🧛🏼"},{"unified":"1f9db-1f3fd","native":"🧛🏽"},{"unified":"1f9db-1f3fe","native":"🧛🏾"},{"unified":"1f9db-1f3ff","native":"🧛🏿"}],"version":5},"male_vampire":{"id":"male_vampire","name":"Man Vampire","keywords":["male","dracula"],"skins":[{"unified":"1f9db-200d-2642-fe0f","native":"🧛♂️"},{"unified":"1f9db-1f3fb-200d-2642-fe0f","native":"🧛🏻♂️"},{"unified":"1f9db-1f3fc-200d-2642-fe0f","native":"🧛🏼♂️"},{"unified":"1f9db-1f3fd-200d-2642-fe0f","native":"🧛🏽♂️"},{"unified":"1f9db-1f3fe-200d-2642-fe0f","native":"🧛🏾♂️"},{"unified":"1f9db-1f3ff-200d-2642-fe0f","native":"🧛🏿♂️"}],"version":5},"female_vampire":{"id":"female_vampire","name":"Woman Vampire","keywords":["female"],"skins":[{"unified":"1f9db-200d-2640-fe0f","native":"🧛♀️"},{"unified":"1f9db-1f3fb-200d-2640-fe0f","native":"🧛🏻♀️"},{"unified":"1f9db-1f3fc-200d-2640-fe0f","native":"🧛🏼♀️"},{"unified":"1f9db-1f3fd-200d-2640-fe0f","native":"🧛🏽♀️"},{"unified":"1f9db-1f3fe-200d-2640-fe0f","native":"🧛🏾♀️"},{"unified":"1f9db-1f3ff-200d-2640-fe0f","native":"🧛🏿♀️"}],"version":5},"merperson":{"id":"merperson","name":"Merperson","keywords":["sea"],"skins":[{"unified":"1f9dc","native":"🧜"},{"unified":"1f9dc-1f3fb","native":"🧜🏻"},{"unified":"1f9dc-1f3fc","native":"🧜🏼"},{"unified":"1f9dc-1f3fd","native":"🧜🏽"},{"unified":"1f9dc-1f3fe","native":"🧜🏾"},{"unified":"1f9dc-1f3ff","native":"🧜🏿"}],"version":5},"merman":{"id":"merman","name":"Merman","keywords":["man","male","triton"],"skins":[{"unified":"1f9dc-200d-2642-fe0f","native":"🧜♂️"},{"unified":"1f9dc-1f3fb-200d-2642-fe0f","native":"🧜🏻♂️"},{"unified":"1f9dc-1f3fc-200d-2642-fe0f","native":"🧜🏼♂️"},{"unified":"1f9dc-1f3fd-200d-2642-fe0f","native":"🧜🏽♂️"},{"unified":"1f9dc-1f3fe-200d-2642-fe0f","native":"🧜🏾♂️"},{"unified":"1f9dc-1f3ff-200d-2642-fe0f","native":"🧜🏿♂️"}],"version":5},"mermaid":{"id":"mermaid","name":"Mermaid","keywords":["woman","female","merwoman","ariel"],"skins":[{"unified":"1f9dc-200d-2640-fe0f","native":"🧜♀️"},{"unified":"1f9dc-1f3fb-200d-2640-fe0f","native":"🧜🏻♀️"},{"unified":"1f9dc-1f3fc-200d-2640-fe0f","native":"🧜🏼♀️"},{"unified":"1f9dc-1f3fd-200d-2640-fe0f","native":"🧜🏽♀️"},{"unified":"1f9dc-1f3fe-200d-2640-fe0f","native":"🧜🏾♀️"},{"unified":"1f9dc-1f3ff-200d-2640-fe0f","native":"🧜🏿♀️"}],"version":5},"elf":{"id":"elf","name":"Elf","keywords":["magical"],"skins":[{"unified":"1f9dd","native":"🧝"},{"unified":"1f9dd-1f3fb","native":"🧝🏻"},{"unified":"1f9dd-1f3fc","native":"🧝🏼"},{"unified":"1f9dd-1f3fd","native":"🧝🏽"},{"unified":"1f9dd-1f3fe","native":"🧝🏾"},{"unified":"1f9dd-1f3ff","native":"🧝🏿"}],"version":5},"male_elf":{"id":"male_elf","name":"Man Elf","keywords":["male"],"skins":[{"unified":"1f9dd-200d-2642-fe0f","native":"🧝♂️"},{"unified":"1f9dd-1f3fb-200d-2642-fe0f","native":"🧝🏻♂️"},{"unified":"1f9dd-1f3fc-200d-2642-fe0f","native":"🧝🏼♂️"},{"unified":"1f9dd-1f3fd-200d-2642-fe0f","native":"🧝🏽♂️"},{"unified":"1f9dd-1f3fe-200d-2642-fe0f","native":"🧝🏾♂️"},{"unified":"1f9dd-1f3ff-200d-2642-fe0f","native":"🧝🏿♂️"}],"version":5},"female_elf":{"id":"female_elf","name":"Woman Elf","keywords":["female"],"skins":[{"unified":"1f9dd-200d-2640-fe0f","native":"🧝♀️"},{"unified":"1f9dd-1f3fb-200d-2640-fe0f","native":"🧝🏻♀️"},{"unified":"1f9dd-1f3fc-200d-2640-fe0f","native":"🧝🏼♀️"},{"unified":"1f9dd-1f3fd-200d-2640-fe0f","native":"🧝🏽♀️"},{"unified":"1f9dd-1f3fe-200d-2640-fe0f","native":"🧝🏾♀️"},{"unified":"1f9dd-1f3ff-200d-2640-fe0f","native":"🧝🏿♀️"}],"version":5},"genie":{"id":"genie","name":"Genie","keywords":["magical","wishes"],"skins":[{"unified":"1f9de","native":"🧞"}],"version":5},"male_genie":{"id":"male_genie","name":"Man Genie","keywords":["male"],"skins":[{"unified":"1f9de-200d-2642-fe0f","native":"🧞♂️"}],"version":5},"female_genie":{"id":"female_genie","name":"Woman Genie","keywords":["female"],"skins":[{"unified":"1f9de-200d-2640-fe0f","native":"🧞♀️"}],"version":5},"zombie":{"id":"zombie","name":"Zombie","keywords":["dead"],"skins":[{"unified":"1f9df","native":"🧟"}],"version":5},"male_zombie":{"id":"male_zombie","name":"Man Zombie","keywords":["male","dracula","undead","walking","dead"],"skins":[{"unified":"1f9df-200d-2642-fe0f","native":"🧟♂️"}],"version":5},"female_zombie":{"id":"female_zombie","name":"Woman Zombie","keywords":["female","undead","walking","dead"],"skins":[{"unified":"1f9df-200d-2640-fe0f","native":"🧟♀️"}],"version":5},"troll":{"id":"troll","name":"Troll","keywords":["mystical","monster"],"skins":[{"unified":"1f9cc","native":"🧌"}],"version":14},"massage":{"id":"massage","name":"Face Massage","keywords":["person","getting","relax"],"skins":[{"unified":"1f486","native":"💆"},{"unified":"1f486-1f3fb","native":"💆🏻"},{"unified":"1f486-1f3fc","native":"💆🏼"},{"unified":"1f486-1f3fd","native":"💆🏽"},{"unified":"1f486-1f3fe","native":"💆🏾"},{"unified":"1f486-1f3ff","native":"💆🏿"}],"version":1},"man-getting-massage":{"id":"man-getting-massage","name":"Man Getting Massage","keywords":["getting-massage","male","boy","head"],"skins":[{"unified":"1f486-200d-2642-fe0f","native":"💆♂️"},{"unified":"1f486-1f3fb-200d-2642-fe0f","native":"💆🏻♂️"},{"unified":"1f486-1f3fc-200d-2642-fe0f","native":"💆🏼♂️"},{"unified":"1f486-1f3fd-200d-2642-fe0f","native":"💆🏽♂️"},{"unified":"1f486-1f3fe-200d-2642-fe0f","native":"💆🏾♂️"},{"unified":"1f486-1f3ff-200d-2642-fe0f","native":"💆🏿♂️"}],"version":4},"woman-getting-massage":{"id":"woman-getting-massage","name":"Woman Getting Massage","keywords":["getting-massage","female","girl","head"],"skins":[{"unified":"1f486-200d-2640-fe0f","native":"💆♀️"},{"unified":"1f486-1f3fb-200d-2640-fe0f","native":"💆🏻♀️"},{"unified":"1f486-1f3fc-200d-2640-fe0f","native":"💆🏼♀️"},{"unified":"1f486-1f3fd-200d-2640-fe0f","native":"💆🏽♀️"},{"unified":"1f486-1f3fe-200d-2640-fe0f","native":"💆🏾♀️"},{"unified":"1f486-1f3ff-200d-2640-fe0f","native":"💆🏿♀️"}],"version":4},"haircut":{"id":"haircut","name":"Haircut","keywords":["person","getting","hairstyle"],"skins":[{"unified":"1f487","native":"💇"},{"unified":"1f487-1f3fb","native":"💇🏻"},{"unified":"1f487-1f3fc","native":"💇🏼"},{"unified":"1f487-1f3fd","native":"💇🏽"},{"unified":"1f487-1f3fe","native":"💇🏾"},{"unified":"1f487-1f3ff","native":"💇🏿"}],"version":1},"man-getting-haircut":{"id":"man-getting-haircut","name":"Man Getting Haircut","keywords":["getting-haircut","male","boy"],"skins":[{"unified":"1f487-200d-2642-fe0f","native":"💇♂️"},{"unified":"1f487-1f3fb-200d-2642-fe0f","native":"💇🏻♂️"},{"unified":"1f487-1f3fc-200d-2642-fe0f","native":"💇🏼♂️"},{"unified":"1f487-1f3fd-200d-2642-fe0f","native":"💇🏽♂️"},{"unified":"1f487-1f3fe-200d-2642-fe0f","native":"💇🏾♂️"},{"unified":"1f487-1f3ff-200d-2642-fe0f","native":"💇🏿♂️"}],"version":4},"woman-getting-haircut":{"id":"woman-getting-haircut","name":"Woman Getting Haircut","keywords":["getting-haircut","female","girl"],"skins":[{"unified":"1f487-200d-2640-fe0f","native":"💇♀️"},{"unified":"1f487-1f3fb-200d-2640-fe0f","native":"💇🏻♀️"},{"unified":"1f487-1f3fc-200d-2640-fe0f","native":"💇🏼♀️"},{"unified":"1f487-1f3fd-200d-2640-fe0f","native":"💇🏽♀️"},{"unified":"1f487-1f3fe-200d-2640-fe0f","native":"💇🏾♀️"},{"unified":"1f487-1f3ff-200d-2640-fe0f","native":"💇🏿♀️"}],"version":4},"walking":{"id":"walking","name":"Pedestrian","keywords":["walking","person","move"],"skins":[{"unified":"1f6b6","native":"🚶"},{"unified":"1f6b6-1f3fb","native":"🚶🏻"},{"unified":"1f6b6-1f3fc","native":"🚶🏼"},{"unified":"1f6b6-1f3fd","native":"🚶🏽"},{"unified":"1f6b6-1f3fe","native":"🚶🏾"},{"unified":"1f6b6-1f3ff","native":"🚶🏿"}],"version":1},"man-walking":{"id":"man-walking","name":"Man Walking","keywords":["human","feet","steps"],"skins":[{"unified":"1f6b6-200d-2642-fe0f","native":"🚶♂️"},{"unified":"1f6b6-1f3fb-200d-2642-fe0f","native":"🚶🏻♂️"},{"unified":"1f6b6-1f3fc-200d-2642-fe0f","native":"🚶🏼♂️"},{"unified":"1f6b6-1f3fd-200d-2642-fe0f","native":"🚶🏽♂️"},{"unified":"1f6b6-1f3fe-200d-2642-fe0f","native":"🚶🏾♂️"},{"unified":"1f6b6-1f3ff-200d-2642-fe0f","native":"🚶🏿♂️"}],"version":4},"woman-walking":{"id":"woman-walking","name":"Woman Walking","keywords":["human","feet","steps","female"],"skins":[{"unified":"1f6b6-200d-2640-fe0f","native":"🚶♀️"},{"unified":"1f6b6-1f3fb-200d-2640-fe0f","native":"🚶🏻♀️"},{"unified":"1f6b6-1f3fc-200d-2640-fe0f","native":"🚶🏼♀️"},{"unified":"1f6b6-1f3fd-200d-2640-fe0f","native":"🚶🏽♀️"},{"unified":"1f6b6-1f3fe-200d-2640-fe0f","native":"🚶🏾♀️"},{"unified":"1f6b6-1f3ff-200d-2640-fe0f","native":"🚶🏿♀️"}],"version":4},"standing_person":{"id":"standing_person","name":"Standing Person","keywords":["still"],"skins":[{"unified":"1f9cd","native":"🧍"},{"unified":"1f9cd-1f3fb","native":"🧍🏻"},{"unified":"1f9cd-1f3fc","native":"🧍🏼"},{"unified":"1f9cd-1f3fd","native":"🧍🏽"},{"unified":"1f9cd-1f3fe","native":"🧍🏾"},{"unified":"1f9cd-1f3ff","native":"🧍🏿"}],"version":12},"man_standing":{"id":"man_standing","name":"Man Standing","keywords":["still"],"skins":[{"unified":"1f9cd-200d-2642-fe0f","native":"🧍♂️"},{"unified":"1f9cd-1f3fb-200d-2642-fe0f","native":"🧍🏻♂️"},{"unified":"1f9cd-1f3fc-200d-2642-fe0f","native":"🧍🏼♂️"},{"unified":"1f9cd-1f3fd-200d-2642-fe0f","native":"🧍🏽♂️"},{"unified":"1f9cd-1f3fe-200d-2642-fe0f","native":"🧍🏾♂️"},{"unified":"1f9cd-1f3ff-200d-2642-fe0f","native":"🧍🏿♂️"}],"version":12},"woman_standing":{"id":"woman_standing","name":"Woman Standing","keywords":["still"],"skins":[{"unified":"1f9cd-200d-2640-fe0f","native":"🧍♀️"},{"unified":"1f9cd-1f3fb-200d-2640-fe0f","native":"🧍🏻♀️"},{"unified":"1f9cd-1f3fc-200d-2640-fe0f","native":"🧍🏼♀️"},{"unified":"1f9cd-1f3fd-200d-2640-fe0f","native":"🧍🏽♀️"},{"unified":"1f9cd-1f3fe-200d-2640-fe0f","native":"🧍🏾♀️"},{"unified":"1f9cd-1f3ff-200d-2640-fe0f","native":"🧍🏿♀️"}],"version":12},"kneeling_person":{"id":"kneeling_person","name":"Kneeling Person","keywords":["pray","respectful"],"skins":[{"unified":"1f9ce","native":"🧎"},{"unified":"1f9ce-1f3fb","native":"🧎🏻"},{"unified":"1f9ce-1f3fc","native":"🧎🏼"},{"unified":"1f9ce-1f3fd","native":"🧎🏽"},{"unified":"1f9ce-1f3fe","native":"🧎🏾"},{"unified":"1f9ce-1f3ff","native":"🧎🏿"}],"version":12},"man_kneeling":{"id":"man_kneeling","name":"Man Kneeling","keywords":["pray","respectful"],"skins":[{"unified":"1f9ce-200d-2642-fe0f","native":"🧎♂️"},{"unified":"1f9ce-1f3fb-200d-2642-fe0f","native":"🧎🏻♂️"},{"unified":"1f9ce-1f3fc-200d-2642-fe0f","native":"🧎🏼♂️"},{"unified":"1f9ce-1f3fd-200d-2642-fe0f","native":"🧎🏽♂️"},{"unified":"1f9ce-1f3fe-200d-2642-fe0f","native":"🧎🏾♂️"},{"unified":"1f9ce-1f3ff-200d-2642-fe0f","native":"🧎🏿♂️"}],"version":12},"woman_kneeling":{"id":"woman_kneeling","name":"Woman Kneeling","keywords":["respectful","pray"],"skins":[{"unified":"1f9ce-200d-2640-fe0f","native":"🧎♀️"},{"unified":"1f9ce-1f3fb-200d-2640-fe0f","native":"🧎🏻♀️"},{"unified":"1f9ce-1f3fc-200d-2640-fe0f","native":"🧎🏼♀️"},{"unified":"1f9ce-1f3fd-200d-2640-fe0f","native":"🧎🏽♀️"},{"unified":"1f9ce-1f3fe-200d-2640-fe0f","native":"🧎🏾♀️"},{"unified":"1f9ce-1f3ff-200d-2640-fe0f","native":"🧎🏿♀️"}],"version":12},"person_with_probing_cane":{"id":"person_with_probing_cane","name":"Person with White Cane","keywords":["probing","blind"],"skins":[{"unified":"1f9d1-200d-1f9af","native":"🧑🦯"},{"unified":"1f9d1-1f3fb-200d-1f9af","native":"🧑🏻🦯"},{"unified":"1f9d1-1f3fc-200d-1f9af","native":"🧑🏼🦯"},{"unified":"1f9d1-1f3fd-200d-1f9af","native":"🧑🏽🦯"},{"unified":"1f9d1-1f3fe-200d-1f9af","native":"🧑🏾🦯"},{"unified":"1f9d1-1f3ff-200d-1f9af","native":"🧑🏿🦯"}],"version":12.1},"man_with_probing_cane":{"id":"man_with_probing_cane","name":"Man with White Cane","keywords":["probing","blind"],"skins":[{"unified":"1f468-200d-1f9af","native":"👨🦯"},{"unified":"1f468-1f3fb-200d-1f9af","native":"👨🏻🦯"},{"unified":"1f468-1f3fc-200d-1f9af","native":"👨🏼🦯"},{"unified":"1f468-1f3fd-200d-1f9af","native":"👨🏽🦯"},{"unified":"1f468-1f3fe-200d-1f9af","native":"👨🏾🦯"},{"unified":"1f468-1f3ff-200d-1f9af","native":"👨🏿🦯"}],"version":12},"woman_with_probing_cane":{"id":"woman_with_probing_cane","name":"Woman with White Cane","keywords":["probing","blind"],"skins":[{"unified":"1f469-200d-1f9af","native":"👩🦯"},{"unified":"1f469-1f3fb-200d-1f9af","native":"👩🏻🦯"},{"unified":"1f469-1f3fc-200d-1f9af","native":"👩🏼🦯"},{"unified":"1f469-1f3fd-200d-1f9af","native":"👩🏽🦯"},{"unified":"1f469-1f3fe-200d-1f9af","native":"👩🏾🦯"},{"unified":"1f469-1f3ff-200d-1f9af","native":"👩🏿🦯"}],"version":12},"person_in_motorized_wheelchair":{"id":"person_in_motorized_wheelchair","name":"Person in Motorized Wheelchair","keywords":["disability","accessibility"],"skins":[{"unified":"1f9d1-200d-1f9bc","native":"🧑🦼"},{"unified":"1f9d1-1f3fb-200d-1f9bc","native":"🧑🏻🦼"},{"unified":"1f9d1-1f3fc-200d-1f9bc","native":"🧑🏼🦼"},{"unified":"1f9d1-1f3fd-200d-1f9bc","native":"🧑🏽🦼"},{"unified":"1f9d1-1f3fe-200d-1f9bc","native":"🧑🏾🦼"},{"unified":"1f9d1-1f3ff-200d-1f9bc","native":"🧑🏿🦼"}],"version":12.1},"man_in_motorized_wheelchair":{"id":"man_in_motorized_wheelchair","name":"Man in Motorized Wheelchair","keywords":["disability","accessibility"],"skins":[{"unified":"1f468-200d-1f9bc","native":"👨🦼"},{"unified":"1f468-1f3fb-200d-1f9bc","native":"👨🏻🦼"},{"unified":"1f468-1f3fc-200d-1f9bc","native":"👨🏼🦼"},{"unified":"1f468-1f3fd-200d-1f9bc","native":"👨🏽🦼"},{"unified":"1f468-1f3fe-200d-1f9bc","native":"👨🏾🦼"},{"unified":"1f468-1f3ff-200d-1f9bc","native":"👨🏿🦼"}],"version":12},"woman_in_motorized_wheelchair":{"id":"woman_in_motorized_wheelchair","name":"Woman in Motorized Wheelchair","keywords":["disability","accessibility"],"skins":[{"unified":"1f469-200d-1f9bc","native":"👩🦼"},{"unified":"1f469-1f3fb-200d-1f9bc","native":"👩🏻🦼"},{"unified":"1f469-1f3fc-200d-1f9bc","native":"👩🏼🦼"},{"unified":"1f469-1f3fd-200d-1f9bc","native":"👩🏽🦼"},{"unified":"1f469-1f3fe-200d-1f9bc","native":"👩🏾🦼"},{"unified":"1f469-1f3ff-200d-1f9bc","native":"👩🏿🦼"}],"version":12},"person_in_manual_wheelchair":{"id":"person_in_manual_wheelchair","name":"Person in Manual Wheelchair","keywords":["disability","accessibility"],"skins":[{"unified":"1f9d1-200d-1f9bd","native":"🧑🦽"},{"unified":"1f9d1-1f3fb-200d-1f9bd","native":"🧑🏻🦽"},{"unified":"1f9d1-1f3fc-200d-1f9bd","native":"🧑🏼🦽"},{"unified":"1f9d1-1f3fd-200d-1f9bd","native":"🧑🏽🦽"},{"unified":"1f9d1-1f3fe-200d-1f9bd","native":"🧑🏾🦽"},{"unified":"1f9d1-1f3ff-200d-1f9bd","native":"🧑🏿🦽"}],"version":12.1},"man_in_manual_wheelchair":{"id":"man_in_manual_wheelchair","name":"Man in Manual Wheelchair","keywords":["disability","accessibility"],"skins":[{"unified":"1f468-200d-1f9bd","native":"👨🦽"},{"unified":"1f468-1f3fb-200d-1f9bd","native":"👨🏻🦽"},{"unified":"1f468-1f3fc-200d-1f9bd","native":"👨🏼🦽"},{"unified":"1f468-1f3fd-200d-1f9bd","native":"👨🏽🦽"},{"unified":"1f468-1f3fe-200d-1f9bd","native":"👨🏾🦽"},{"unified":"1f468-1f3ff-200d-1f9bd","native":"👨🏿🦽"}],"version":12},"woman_in_manual_wheelchair":{"id":"woman_in_manual_wheelchair","name":"Woman in Manual Wheelchair","keywords":["disability","accessibility"],"skins":[{"unified":"1f469-200d-1f9bd","native":"👩🦽"},{"unified":"1f469-1f3fb-200d-1f9bd","native":"👩🏻🦽"},{"unified":"1f469-1f3fc-200d-1f9bd","native":"👩🏼🦽"},{"unified":"1f469-1f3fd-200d-1f9bd","native":"👩🏽🦽"},{"unified":"1f469-1f3fe-200d-1f9bd","native":"👩🏾🦽"},{"unified":"1f469-1f3ff-200d-1f9bd","native":"👩🏿🦽"}],"version":12},"runner":{"id":"runner","name":"Runner","keywords":["running","person","move"],"skins":[{"unified":"1f3c3","native":"🏃"},{"unified":"1f3c3-1f3fb","native":"🏃🏻"},{"unified":"1f3c3-1f3fc","native":"🏃🏼"},{"unified":"1f3c3-1f3fd","native":"🏃🏽"},{"unified":"1f3c3-1f3fe","native":"🏃🏾"},{"unified":"1f3c3-1f3ff","native":"🏃🏿"}],"version":1},"man-running":{"id":"man-running","name":"Man Running","keywords":["walking","exercise","race"],"skins":[{"unified":"1f3c3-200d-2642-fe0f","native":"🏃♂️"},{"unified":"1f3c3-1f3fb-200d-2642-fe0f","native":"🏃🏻♂️"},{"unified":"1f3c3-1f3fc-200d-2642-fe0f","native":"🏃🏼♂️"},{"unified":"1f3c3-1f3fd-200d-2642-fe0f","native":"🏃🏽♂️"},{"unified":"1f3c3-1f3fe-200d-2642-fe0f","native":"🏃🏾♂️"},{"unified":"1f3c3-1f3ff-200d-2642-fe0f","native":"🏃🏿♂️"}],"version":4},"woman-running":{"id":"woman-running","name":"Woman Running","keywords":["walking","exercise","race","female"],"skins":[{"unified":"1f3c3-200d-2640-fe0f","native":"🏃♀️"},{"unified":"1f3c3-1f3fb-200d-2640-fe0f","native":"🏃🏻♀️"},{"unified":"1f3c3-1f3fc-200d-2640-fe0f","native":"🏃🏼♀️"},{"unified":"1f3c3-1f3fd-200d-2640-fe0f","native":"🏃🏽♀️"},{"unified":"1f3c3-1f3fe-200d-2640-fe0f","native":"🏃🏾♀️"},{"unified":"1f3c3-1f3ff-200d-2640-fe0f","native":"🏃🏿♀️"}],"version":4},"dancer":{"id":"dancer","name":"Dancer","keywords":["woman","dancing","female","girl","fun"],"skins":[{"unified":"1f483","native":"💃"},{"unified":"1f483-1f3fb","native":"💃🏻"},{"unified":"1f483-1f3fc","native":"💃🏼"},{"unified":"1f483-1f3fd","native":"💃🏽"},{"unified":"1f483-1f3fe","native":"💃🏾"},{"unified":"1f483-1f3ff","native":"💃🏿"}],"version":1},"man_dancing":{"id":"man_dancing","name":"Man Dancing","keywords":["male","boy","fun","dancer"],"skins":[{"unified":"1f57a","native":"🕺"},{"unified":"1f57a-1f3fb","native":"🕺🏻"},{"unified":"1f57a-1f3fc","native":"🕺🏼"},{"unified":"1f57a-1f3fd","native":"🕺🏽"},{"unified":"1f57a-1f3fe","native":"🕺🏾"},{"unified":"1f57a-1f3ff","native":"🕺🏿"}],"version":3},"man_in_business_suit_levitating":{"id":"man_in_business_suit_levitating","name":"Person in Suit Levitating","keywords":["man","business","levitate","hover","jump"],"skins":[{"unified":"1f574-fe0f","native":"🕴️"},{"unified":"1f574-1f3fb","native":"🕴🏻"},{"unified":"1f574-1f3fc","native":"🕴🏼"},{"unified":"1f574-1f3fd","native":"🕴🏽"},{"unified":"1f574-1f3fe","native":"🕴🏾"},{"unified":"1f574-1f3ff","native":"🕴🏿"}],"version":1},"dancers":{"id":"dancers","name":"Woman with Bunny Ears","keywords":["dancers","people","perform","costume"],"skins":[{"unified":"1f46f","native":"👯"}],"version":1},"men-with-bunny-ears-partying":{"id":"men-with-bunny-ears-partying","name":"Men with Bunny Ears","keywords":["with-bunny-ears-partying","man","male","boys"],"skins":[{"unified":"1f46f-200d-2642-fe0f","native":"👯♂️"}],"version":4},"women-with-bunny-ears-partying":{"id":"women-with-bunny-ears-partying","name":"Women with Bunny Ears","keywords":["with-bunny-ears-partying","woman","female","girls"],"skins":[{"unified":"1f46f-200d-2640-fe0f","native":"👯♀️"}],"version":4},"person_in_steamy_room":{"id":"person_in_steamy_room","name":"Person in Steamy Room","keywords":["relax","spa"],"skins":[{"unified":"1f9d6","native":"🧖"},{"unified":"1f9d6-1f3fb","native":"🧖🏻"},{"unified":"1f9d6-1f3fc","native":"🧖🏼"},{"unified":"1f9d6-1f3fd","native":"🧖🏽"},{"unified":"1f9d6-1f3fe","native":"🧖🏾"},{"unified":"1f9d6-1f3ff","native":"🧖🏿"}],"version":5},"man_in_steamy_room":{"id":"man_in_steamy_room","name":"Man in Steamy Room","keywords":["male","spa","steamroom","sauna"],"skins":[{"unified":"1f9d6-200d-2642-fe0f","native":"🧖♂️"},{"unified":"1f9d6-1f3fb-200d-2642-fe0f","native":"🧖🏻♂️"},{"unified":"1f9d6-1f3fc-200d-2642-fe0f","native":"🧖🏼♂️"},{"unified":"1f9d6-1f3fd-200d-2642-fe0f","native":"🧖🏽♂️"},{"unified":"1f9d6-1f3fe-200d-2642-fe0f","native":"🧖🏾♂️"},{"unified":"1f9d6-1f3ff-200d-2642-fe0f","native":"🧖🏿♂️"}],"version":5},"woman_in_steamy_room":{"id":"woman_in_steamy_room","name":"Woman in Steamy Room","keywords":["female","spa","steamroom","sauna"],"skins":[{"unified":"1f9d6-200d-2640-fe0f","native":"🧖♀️"},{"unified":"1f9d6-1f3fb-200d-2640-fe0f","native":"🧖🏻♀️"},{"unified":"1f9d6-1f3fc-200d-2640-fe0f","native":"🧖🏼♀️"},{"unified":"1f9d6-1f3fd-200d-2640-fe0f","native":"🧖🏽♀️"},{"unified":"1f9d6-1f3fe-200d-2640-fe0f","native":"🧖🏾♀️"},{"unified":"1f9d6-1f3ff-200d-2640-fe0f","native":"🧖🏿♀️"}],"version":5},"person_climbing":{"id":"person_climbing","name":"Person Climbing","keywords":["sport"],"skins":[{"unified":"1f9d7","native":"🧗"},{"unified":"1f9d7-1f3fb","native":"🧗🏻"},{"unified":"1f9d7-1f3fc","native":"🧗🏼"},{"unified":"1f9d7-1f3fd","native":"🧗🏽"},{"unified":"1f9d7-1f3fe","native":"🧗🏾"},{"unified":"1f9d7-1f3ff","native":"🧗🏿"}],"version":5},"man_climbing":{"id":"man_climbing","name":"Man Climbing","keywords":["sports","hobby","male","rock"],"skins":[{"unified":"1f9d7-200d-2642-fe0f","native":"🧗♂️"},{"unified":"1f9d7-1f3fb-200d-2642-fe0f","native":"🧗🏻♂️"},{"unified":"1f9d7-1f3fc-200d-2642-fe0f","native":"🧗🏼♂️"},{"unified":"1f9d7-1f3fd-200d-2642-fe0f","native":"🧗🏽♂️"},{"unified":"1f9d7-1f3fe-200d-2642-fe0f","native":"🧗🏾♂️"},{"unified":"1f9d7-1f3ff-200d-2642-fe0f","native":"🧗🏿♂️"}],"version":5},"woman_climbing":{"id":"woman_climbing","name":"Woman Climbing","keywords":["sports","hobby","female","rock"],"skins":[{"unified":"1f9d7-200d-2640-fe0f","native":"🧗♀️"},{"unified":"1f9d7-1f3fb-200d-2640-fe0f","native":"🧗🏻♀️"},{"unified":"1f9d7-1f3fc-200d-2640-fe0f","native":"🧗🏼♀️"},{"unified":"1f9d7-1f3fd-200d-2640-fe0f","native":"🧗🏽♀️"},{"unified":"1f9d7-1f3fe-200d-2640-fe0f","native":"🧗🏾♀️"},{"unified":"1f9d7-1f3ff-200d-2640-fe0f","native":"🧗🏿♀️"}],"version":5},"fencer":{"id":"fencer","name":"Fencer","keywords":["person","fencing","sports","sword"],"skins":[{"unified":"1f93a","native":"🤺"}],"version":3},"horse_racing":{"id":"horse_racing","name":"Horse Racing","keywords":["animal","betting","competition","gambling","luck"],"skins":[{"unified":"1f3c7","native":"🏇"},{"unified":"1f3c7-1f3fb","native":"🏇🏻"},{"unified":"1f3c7-1f3fc","native":"🏇🏼"},{"unified":"1f3c7-1f3fd","native":"🏇🏽"},{"unified":"1f3c7-1f3fe","native":"🏇🏾"},{"unified":"1f3c7-1f3ff","native":"🏇🏿"}],"version":1},"skier":{"id":"skier","name":"Skier","keywords":["sports","winter","snow"],"skins":[{"unified":"26f7-fe0f","native":"⛷️"}],"version":1},"snowboarder":{"id":"snowboarder","name":"Snowboarder","keywords":["sports","winter"],"skins":[{"unified":"1f3c2","native":"🏂"},{"unified":"1f3c2-1f3fb","native":"🏂🏻"},{"unified":"1f3c2-1f3fc","native":"🏂🏼"},{"unified":"1f3c2-1f3fd","native":"🏂🏽"},{"unified":"1f3c2-1f3fe","native":"🏂🏾"},{"unified":"1f3c2-1f3ff","native":"🏂🏿"}],"version":1},"golfer":{"id":"golfer","name":"Person Golfing","keywords":["golfer","sports","business"],"skins":[{"unified":"1f3cc-fe0f","native":"🏌️"},{"unified":"1f3cc-1f3fb","native":"🏌🏻"},{"unified":"1f3cc-1f3fc","native":"🏌🏼"},{"unified":"1f3cc-1f3fd","native":"🏌🏽"},{"unified":"1f3cc-1f3fe","native":"🏌🏾"},{"unified":"1f3cc-1f3ff","native":"🏌🏿"}],"version":1},"man-golfing":{"id":"man-golfing","name":"Man Golfing","keywords":["sport"],"skins":[{"unified":"1f3cc-fe0f-200d-2642-fe0f","native":"🏌️♂️"},{"unified":"1f3cc-1f3fb-200d-2642-fe0f","native":"🏌🏻♂️"},{"unified":"1f3cc-1f3fc-200d-2642-fe0f","native":"🏌🏼♂️"},{"unified":"1f3cc-1f3fd-200d-2642-fe0f","native":"🏌🏽♂️"},{"unified":"1f3cc-1f3fe-200d-2642-fe0f","native":"🏌🏾♂️"},{"unified":"1f3cc-1f3ff-200d-2642-fe0f","native":"🏌🏿♂️"}],"version":4},"woman-golfing":{"id":"woman-golfing","name":"Woman Golfing","keywords":["sports","business","female"],"skins":[{"unified":"1f3cc-fe0f-200d-2640-fe0f","native":"🏌️♀️"},{"unified":"1f3cc-1f3fb-200d-2640-fe0f","native":"🏌🏻♀️"},{"unified":"1f3cc-1f3fc-200d-2640-fe0f","native":"🏌🏼♀️"},{"unified":"1f3cc-1f3fd-200d-2640-fe0f","native":"🏌🏽♀️"},{"unified":"1f3cc-1f3fe-200d-2640-fe0f","native":"🏌🏾♀️"},{"unified":"1f3cc-1f3ff-200d-2640-fe0f","native":"🏌🏿♀️"}],"version":4},"surfer":{"id":"surfer","name":"Surfer","keywords":["person","surfing","sport","sea"],"skins":[{"unified":"1f3c4","native":"🏄"},{"unified":"1f3c4-1f3fb","native":"🏄🏻"},{"unified":"1f3c4-1f3fc","native":"🏄🏼"},{"unified":"1f3c4-1f3fd","native":"🏄🏽"},{"unified":"1f3c4-1f3fe","native":"🏄🏾"},{"unified":"1f3c4-1f3ff","native":"🏄🏿"}],"version":1},"man-surfing":{"id":"man-surfing","name":"Man Surfing","keywords":["sports","ocean","sea","summer","beach"],"skins":[{"unified":"1f3c4-200d-2642-fe0f","native":"🏄♂️"},{"unified":"1f3c4-1f3fb-200d-2642-fe0f","native":"🏄🏻♂️"},{"unified":"1f3c4-1f3fc-200d-2642-fe0f","native":"🏄🏼♂️"},{"unified":"1f3c4-1f3fd-200d-2642-fe0f","native":"🏄🏽♂️"},{"unified":"1f3c4-1f3fe-200d-2642-fe0f","native":"🏄🏾♂️"},{"unified":"1f3c4-1f3ff-200d-2642-fe0f","native":"🏄🏿♂️"}],"version":4},"woman-surfing":{"id":"woman-surfing","name":"Woman Surfing","keywords":["sports","ocean","sea","summer","beach","female"],"skins":[{"unified":"1f3c4-200d-2640-fe0f","native":"🏄♀️"},{"unified":"1f3c4-1f3fb-200d-2640-fe0f","native":"🏄🏻♀️"},{"unified":"1f3c4-1f3fc-200d-2640-fe0f","native":"🏄🏼♀️"},{"unified":"1f3c4-1f3fd-200d-2640-fe0f","native":"🏄🏽♀️"},{"unified":"1f3c4-1f3fe-200d-2640-fe0f","native":"🏄🏾♀️"},{"unified":"1f3c4-1f3ff-200d-2640-fe0f","native":"🏄🏿♀️"}],"version":4},"rowboat":{"id":"rowboat","name":"Rowboat","keywords":["person","rowing","boat","sport","move"],"skins":[{"unified":"1f6a3","native":"🚣"},{"unified":"1f6a3-1f3fb","native":"🚣🏻"},{"unified":"1f6a3-1f3fc","native":"🚣🏼"},{"unified":"1f6a3-1f3fd","native":"🚣🏽"},{"unified":"1f6a3-1f3fe","native":"🚣🏾"},{"unified":"1f6a3-1f3ff","native":"🚣🏿"}],"version":1},"man-rowing-boat":{"id":"man-rowing-boat","name":"Man Rowing Boat","keywords":["rowing-boat","sports","hobby","water","ship"],"skins":[{"unified":"1f6a3-200d-2642-fe0f","native":"🚣♂️"},{"unified":"1f6a3-1f3fb-200d-2642-fe0f","native":"🚣🏻♂️"},{"unified":"1f6a3-1f3fc-200d-2642-fe0f","native":"🚣🏼♂️"},{"unified":"1f6a3-1f3fd-200d-2642-fe0f","native":"🚣🏽♂️"},{"unified":"1f6a3-1f3fe-200d-2642-fe0f","native":"🚣🏾♂️"},{"unified":"1f6a3-1f3ff-200d-2642-fe0f","native":"🚣🏿♂️"}],"version":4},"woman-rowing-boat":{"id":"woman-rowing-boat","name":"Woman Rowing Boat","keywords":["rowing-boat","sports","hobby","water","ship","female"],"skins":[{"unified":"1f6a3-200d-2640-fe0f","native":"🚣♀️"},{"unified":"1f6a3-1f3fb-200d-2640-fe0f","native":"🚣🏻♀️"},{"unified":"1f6a3-1f3fc-200d-2640-fe0f","native":"🚣🏼♀️"},{"unified":"1f6a3-1f3fd-200d-2640-fe0f","native":"🚣🏽♀️"},{"unified":"1f6a3-1f3fe-200d-2640-fe0f","native":"🚣🏾♀️"},{"unified":"1f6a3-1f3ff-200d-2640-fe0f","native":"🚣🏿♀️"}],"version":4},"swimmer":{"id":"swimmer","name":"Swimmer","keywords":["person","swimming","sport","pool"],"skins":[{"unified":"1f3ca","native":"🏊"},{"unified":"1f3ca-1f3fb","native":"🏊🏻"},{"unified":"1f3ca-1f3fc","native":"🏊🏼"},{"unified":"1f3ca-1f3fd","native":"🏊🏽"},{"unified":"1f3ca-1f3fe","native":"🏊🏾"},{"unified":"1f3ca-1f3ff","native":"🏊🏿"}],"version":1},"man-swimming":{"id":"man-swimming","name":"Man Swimming","keywords":["sports","exercise","human","athlete","water","summer"],"skins":[{"unified":"1f3ca-200d-2642-fe0f","native":"🏊♂️"},{"unified":"1f3ca-1f3fb-200d-2642-fe0f","native":"🏊🏻♂️"},{"unified":"1f3ca-1f3fc-200d-2642-fe0f","native":"🏊🏼♂️"},{"unified":"1f3ca-1f3fd-200d-2642-fe0f","native":"🏊🏽♂️"},{"unified":"1f3ca-1f3fe-200d-2642-fe0f","native":"🏊🏾♂️"},{"unified":"1f3ca-1f3ff-200d-2642-fe0f","native":"🏊🏿♂️"}],"version":4},"woman-swimming":{"id":"woman-swimming","name":"Woman Swimming","keywords":["sports","exercise","human","athlete","water","summer","female"],"skins":[{"unified":"1f3ca-200d-2640-fe0f","native":"🏊♀️"},{"unified":"1f3ca-1f3fb-200d-2640-fe0f","native":"🏊🏻♀️"},{"unified":"1f3ca-1f3fc-200d-2640-fe0f","native":"🏊🏼♀️"},{"unified":"1f3ca-1f3fd-200d-2640-fe0f","native":"🏊🏽♀️"},{"unified":"1f3ca-1f3fe-200d-2640-fe0f","native":"🏊🏾♀️"},{"unified":"1f3ca-1f3ff-200d-2640-fe0f","native":"🏊🏿♀️"}],"version":4},"person_with_ball":{"id":"person_with_ball","name":"Person Bouncing Ball","keywords":["with","sports","human"],"skins":[{"unified":"26f9-fe0f","native":"⛹️"},{"unified":"26f9-1f3fb","native":"⛹🏻"},{"unified":"26f9-1f3fc","native":"⛹🏼"},{"unified":"26f9-1f3fd","native":"⛹🏽"},{"unified":"26f9-1f3fe","native":"⛹🏾"},{"unified":"26f9-1f3ff","native":"⛹🏿"}],"version":1},"man-bouncing-ball":{"id":"man-bouncing-ball","name":"Man Bouncing Ball","keywords":["bouncing-ball","sport"],"skins":[{"unified":"26f9-fe0f-200d-2642-fe0f","native":"⛹️♂️"},{"unified":"26f9-1f3fb-200d-2642-fe0f","native":"⛹🏻♂️"},{"unified":"26f9-1f3fc-200d-2642-fe0f","native":"⛹🏼♂️"},{"unified":"26f9-1f3fd-200d-2642-fe0f","native":"⛹🏽♂️"},{"unified":"26f9-1f3fe-200d-2642-fe0f","native":"⛹🏾♂️"},{"unified":"26f9-1f3ff-200d-2642-fe0f","native":"⛹🏿♂️"}],"version":4},"woman-bouncing-ball":{"id":"woman-bouncing-ball","name":"Woman Bouncing Ball","keywords":["bouncing-ball","sports","human","female"],"skins":[{"unified":"26f9-fe0f-200d-2640-fe0f","native":"⛹️♀️"},{"unified":"26f9-1f3fb-200d-2640-fe0f","native":"⛹🏻♀️"},{"unified":"26f9-1f3fc-200d-2640-fe0f","native":"⛹🏼♀️"},{"unified":"26f9-1f3fd-200d-2640-fe0f","native":"⛹🏽♀️"},{"unified":"26f9-1f3fe-200d-2640-fe0f","native":"⛹🏾♀️"},{"unified":"26f9-1f3ff-200d-2640-fe0f","native":"⛹🏿♀️"}],"version":4},"weight_lifter":{"id":"weight_lifter","name":"Person Lifting Weights","keywords":["weight","lifter","sports","training","exercise"],"skins":[{"unified":"1f3cb-fe0f","native":"🏋️"},{"unified":"1f3cb-1f3fb","native":"🏋🏻"},{"unified":"1f3cb-1f3fc","native":"🏋🏼"},{"unified":"1f3cb-1f3fd","native":"🏋🏽"},{"unified":"1f3cb-1f3fe","native":"🏋🏾"},{"unified":"1f3cb-1f3ff","native":"🏋🏿"}],"version":1},"man-lifting-weights":{"id":"man-lifting-weights","name":"Man Lifting Weights","keywords":["lifting-weights","sport"],"skins":[{"unified":"1f3cb-fe0f-200d-2642-fe0f","native":"🏋️♂️"},{"unified":"1f3cb-1f3fb-200d-2642-fe0f","native":"🏋🏻♂️"},{"unified":"1f3cb-1f3fc-200d-2642-fe0f","native":"🏋🏼♂️"},{"unified":"1f3cb-1f3fd-200d-2642-fe0f","native":"🏋🏽♂️"},{"unified":"1f3cb-1f3fe-200d-2642-fe0f","native":"🏋🏾♂️"},{"unified":"1f3cb-1f3ff-200d-2642-fe0f","native":"🏋🏿♂️"}],"version":4},"woman-lifting-weights":{"id":"woman-lifting-weights","name":"Woman Lifting Weights","keywords":["lifting-weights","sports","training","exercise","female"],"skins":[{"unified":"1f3cb-fe0f-200d-2640-fe0f","native":"🏋️♀️"},{"unified":"1f3cb-1f3fb-200d-2640-fe0f","native":"🏋🏻♀️"},{"unified":"1f3cb-1f3fc-200d-2640-fe0f","native":"🏋🏼♀️"},{"unified":"1f3cb-1f3fd-200d-2640-fe0f","native":"🏋🏽♀️"},{"unified":"1f3cb-1f3fe-200d-2640-fe0f","native":"🏋🏾♀️"},{"unified":"1f3cb-1f3ff-200d-2640-fe0f","native":"🏋🏿♀️"}],"version":4},"bicyclist":{"id":"bicyclist","name":"Bicyclist","keywords":["person","biking","sport","move"],"skins":[{"unified":"1f6b4","native":"🚴"},{"unified":"1f6b4-1f3fb","native":"🚴🏻"},{"unified":"1f6b4-1f3fc","native":"🚴🏼"},{"unified":"1f6b4-1f3fd","native":"🚴🏽"},{"unified":"1f6b4-1f3fe","native":"🚴🏾"},{"unified":"1f6b4-1f3ff","native":"🚴🏿"}],"version":1},"man-biking":{"id":"man-biking","name":"Man Biking","keywords":["sports","bike","exercise","hipster"],"skins":[{"unified":"1f6b4-200d-2642-fe0f","native":"🚴♂️"},{"unified":"1f6b4-1f3fb-200d-2642-fe0f","native":"🚴🏻♂️"},{"unified":"1f6b4-1f3fc-200d-2642-fe0f","native":"🚴🏼♂️"},{"unified":"1f6b4-1f3fd-200d-2642-fe0f","native":"🚴🏽♂️"},{"unified":"1f6b4-1f3fe-200d-2642-fe0f","native":"🚴🏾♂️"},{"unified":"1f6b4-1f3ff-200d-2642-fe0f","native":"🚴🏿♂️"}],"version":4},"woman-biking":{"id":"woman-biking","name":"Woman Biking","keywords":["sports","bike","exercise","hipster","female"],"skins":[{"unified":"1f6b4-200d-2640-fe0f","native":"🚴♀️"},{"unified":"1f6b4-1f3fb-200d-2640-fe0f","native":"🚴🏻♀️"},{"unified":"1f6b4-1f3fc-200d-2640-fe0f","native":"🚴🏼♀️"},{"unified":"1f6b4-1f3fd-200d-2640-fe0f","native":"🚴🏽♀️"},{"unified":"1f6b4-1f3fe-200d-2640-fe0f","native":"🚴🏾♀️"},{"unified":"1f6b4-1f3ff-200d-2640-fe0f","native":"🚴🏿♀️"}],"version":4},"mountain_bicyclist":{"id":"mountain_bicyclist","name":"Mountain Bicyclist","keywords":["person","biking","sport","move"],"skins":[{"unified":"1f6b5","native":"🚵"},{"unified":"1f6b5-1f3fb","native":"🚵🏻"},{"unified":"1f6b5-1f3fc","native":"🚵🏼"},{"unified":"1f6b5-1f3fd","native":"🚵🏽"},{"unified":"1f6b5-1f3fe","native":"🚵🏾"},{"unified":"1f6b5-1f3ff","native":"🚵🏿"}],"version":1},"man-mountain-biking":{"id":"man-mountain-biking","name":"Man Mountain Biking","keywords":["mountain-biking","transportation","sports","human","race","bike"],"skins":[{"unified":"1f6b5-200d-2642-fe0f","native":"🚵♂️"},{"unified":"1f6b5-1f3fb-200d-2642-fe0f","native":"🚵🏻♂️"},{"unified":"1f6b5-1f3fc-200d-2642-fe0f","native":"🚵🏼♂️"},{"unified":"1f6b5-1f3fd-200d-2642-fe0f","native":"🚵🏽♂️"},{"unified":"1f6b5-1f3fe-200d-2642-fe0f","native":"🚵🏾♂️"},{"unified":"1f6b5-1f3ff-200d-2642-fe0f","native":"🚵🏿♂️"}],"version":4},"woman-mountain-biking":{"id":"woman-mountain-biking","name":"Woman Mountain Biking","keywords":["mountain-biking","transportation","sports","human","race","bike","female"],"skins":[{"unified":"1f6b5-200d-2640-fe0f","native":"🚵♀️"},{"unified":"1f6b5-1f3fb-200d-2640-fe0f","native":"🚵🏻♀️"},{"unified":"1f6b5-1f3fc-200d-2640-fe0f","native":"🚵🏼♀️"},{"unified":"1f6b5-1f3fd-200d-2640-fe0f","native":"🚵🏽♀️"},{"unified":"1f6b5-1f3fe-200d-2640-fe0f","native":"🚵🏾♀️"},{"unified":"1f6b5-1f3ff-200d-2640-fe0f","native":"🚵🏿♀️"}],"version":4},"person_doing_cartwheel":{"id":"person_doing_cartwheel","name":"Person Cartwheeling","keywords":["doing","cartwheel","sport","gymnastic"],"skins":[{"unified":"1f938","native":"🤸"},{"unified":"1f938-1f3fb","native":"🤸🏻"},{"unified":"1f938-1f3fc","native":"🤸🏼"},{"unified":"1f938-1f3fd","native":"🤸🏽"},{"unified":"1f938-1f3fe","native":"🤸🏾"},{"unified":"1f938-1f3ff","native":"🤸🏿"}],"version":3},"man-cartwheeling":{"id":"man-cartwheeling","name":"Man Cartwheeling","keywords":["gymnastics"],"skins":[{"unified":"1f938-200d-2642-fe0f","native":"🤸♂️"},{"unified":"1f938-1f3fb-200d-2642-fe0f","native":"🤸🏻♂️"},{"unified":"1f938-1f3fc-200d-2642-fe0f","native":"🤸🏼♂️"},{"unified":"1f938-1f3fd-200d-2642-fe0f","native":"🤸🏽♂️"},{"unified":"1f938-1f3fe-200d-2642-fe0f","native":"🤸🏾♂️"},{"unified":"1f938-1f3ff-200d-2642-fe0f","native":"🤸🏿♂️"}],"version":4},"woman-cartwheeling":{"id":"woman-cartwheeling","name":"Woman Cartwheeling","keywords":["gymnastics"],"skins":[{"unified":"1f938-200d-2640-fe0f","native":"🤸♀️"},{"unified":"1f938-1f3fb-200d-2640-fe0f","native":"🤸🏻♀️"},{"unified":"1f938-1f3fc-200d-2640-fe0f","native":"🤸🏼♀️"},{"unified":"1f938-1f3fd-200d-2640-fe0f","native":"🤸🏽♀️"},{"unified":"1f938-1f3fe-200d-2640-fe0f","native":"🤸🏾♀️"},{"unified":"1f938-1f3ff-200d-2640-fe0f","native":"🤸🏿♀️"}],"version":4},"wrestlers":{"id":"wrestlers","name":"Wrestlers","keywords":["people","wrestling","sport"],"skins":[{"unified":"1f93c","native":"🤼"}],"version":3},"man-wrestling":{"id":"man-wrestling","name":"Men Wrestling","keywords":["man","sports","wrestlers"],"skins":[{"unified":"1f93c-200d-2642-fe0f","native":"🤼♂️"}],"version":4},"woman-wrestling":{"id":"woman-wrestling","name":"Women Wrestling","keywords":["woman","sports","wrestlers"],"skins":[{"unified":"1f93c-200d-2640-fe0f","native":"🤼♀️"}],"version":4},"water_polo":{"id":"water_polo","name":"Water Polo","keywords":["person","playing","sport"],"skins":[{"unified":"1f93d","native":"🤽"},{"unified":"1f93d-1f3fb","native":"🤽🏻"},{"unified":"1f93d-1f3fc","native":"🤽🏼"},{"unified":"1f93d-1f3fd","native":"🤽🏽"},{"unified":"1f93d-1f3fe","native":"🤽🏾"},{"unified":"1f93d-1f3ff","native":"🤽🏿"}],"version":3},"man-playing-water-polo":{"id":"man-playing-water-polo","name":"Man Playing Water Polo","keywords":["playing-water-polo","sports","pool"],"skins":[{"unified":"1f93d-200d-2642-fe0f","native":"🤽♂️"},{"unified":"1f93d-1f3fb-200d-2642-fe0f","native":"🤽🏻♂️"},{"unified":"1f93d-1f3fc-200d-2642-fe0f","native":"🤽🏼♂️"},{"unified":"1f93d-1f3fd-200d-2642-fe0f","native":"🤽🏽♂️"},{"unified":"1f93d-1f3fe-200d-2642-fe0f","native":"🤽🏾♂️"},{"unified":"1f93d-1f3ff-200d-2642-fe0f","native":"🤽🏿♂️"}],"version":4},"woman-playing-water-polo":{"id":"woman-playing-water-polo","name":"Woman Playing Water Polo","keywords":["playing-water-polo","sports","pool"],"skins":[{"unified":"1f93d-200d-2640-fe0f","native":"🤽♀️"},{"unified":"1f93d-1f3fb-200d-2640-fe0f","native":"🤽🏻♀️"},{"unified":"1f93d-1f3fc-200d-2640-fe0f","native":"🤽🏼♀️"},{"unified":"1f93d-1f3fd-200d-2640-fe0f","native":"🤽🏽♀️"},{"unified":"1f93d-1f3fe-200d-2640-fe0f","native":"🤽🏾♀️"},{"unified":"1f93d-1f3ff-200d-2640-fe0f","native":"🤽🏿♀️"}],"version":4},"handball":{"id":"handball","name":"Handball","keywords":["person","playing","sport"],"skins":[{"unified":"1f93e","native":"🤾"},{"unified":"1f93e-1f3fb","native":"🤾🏻"},{"unified":"1f93e-1f3fc","native":"🤾🏼"},{"unified":"1f93e-1f3fd","native":"🤾🏽"},{"unified":"1f93e-1f3fe","native":"🤾🏾"},{"unified":"1f93e-1f3ff","native":"🤾🏿"}],"version":3},"man-playing-handball":{"id":"man-playing-handball","name":"Man Playing Handball","keywords":["playing-handball","sports"],"skins":[{"unified":"1f93e-200d-2642-fe0f","native":"🤾♂️"},{"unified":"1f93e-1f3fb-200d-2642-fe0f","native":"🤾🏻♂️"},{"unified":"1f93e-1f3fc-200d-2642-fe0f","native":"🤾🏼♂️"},{"unified":"1f93e-1f3fd-200d-2642-fe0f","native":"🤾🏽♂️"},{"unified":"1f93e-1f3fe-200d-2642-fe0f","native":"🤾🏾♂️"},{"unified":"1f93e-1f3ff-200d-2642-fe0f","native":"🤾🏿♂️"}],"version":4},"woman-playing-handball":{"id":"woman-playing-handball","name":"Woman Playing Handball","keywords":["playing-handball","sports"],"skins":[{"unified":"1f93e-200d-2640-fe0f","native":"🤾♀️"},{"unified":"1f93e-1f3fb-200d-2640-fe0f","native":"🤾🏻♀️"},{"unified":"1f93e-1f3fc-200d-2640-fe0f","native":"🤾🏼♀️"},{"unified":"1f93e-1f3fd-200d-2640-fe0f","native":"🤾🏽♀️"},{"unified":"1f93e-1f3fe-200d-2640-fe0f","native":"🤾🏾♀️"},{"unified":"1f93e-1f3ff-200d-2640-fe0f","native":"🤾🏿♀️"}],"version":4},"juggling":{"id":"juggling","name":"Juggling","keywords":["person","performance","balance"],"skins":[{"unified":"1f939","native":"🤹"},{"unified":"1f939-1f3fb","native":"🤹🏻"},{"unified":"1f939-1f3fc","native":"🤹🏼"},{"unified":"1f939-1f3fd","native":"🤹🏽"},{"unified":"1f939-1f3fe","native":"🤹🏾"},{"unified":"1f939-1f3ff","native":"🤹🏿"}],"version":3},"man-juggling":{"id":"man-juggling","name":"Man Juggling","keywords":["juggle","balance","skill","multitask"],"skins":[{"unified":"1f939-200d-2642-fe0f","native":"🤹♂️"},{"unified":"1f939-1f3fb-200d-2642-fe0f","native":"🤹🏻♂️"},{"unified":"1f939-1f3fc-200d-2642-fe0f","native":"🤹🏼♂️"},{"unified":"1f939-1f3fd-200d-2642-fe0f","native":"🤹🏽♂️"},{"unified":"1f939-1f3fe-200d-2642-fe0f","native":"🤹🏾♂️"},{"unified":"1f939-1f3ff-200d-2642-fe0f","native":"🤹🏿♂️"}],"version":4},"woman-juggling":{"id":"woman-juggling","name":"Woman Juggling","keywords":["juggle","balance","skill","multitask"],"skins":[{"unified":"1f939-200d-2640-fe0f","native":"🤹♀️"},{"unified":"1f939-1f3fb-200d-2640-fe0f","native":"🤹🏻♀️"},{"unified":"1f939-1f3fc-200d-2640-fe0f","native":"🤹🏼♀️"},{"unified":"1f939-1f3fd-200d-2640-fe0f","native":"🤹🏽♀️"},{"unified":"1f939-1f3fe-200d-2640-fe0f","native":"🤹🏾♀️"},{"unified":"1f939-1f3ff-200d-2640-fe0f","native":"🤹🏿♀️"}],"version":4},"person_in_lotus_position":{"id":"person_in_lotus_position","name":"Person in Lotus Position","keywords":["meditate"],"skins":[{"unified":"1f9d8","native":"🧘"},{"unified":"1f9d8-1f3fb","native":"🧘🏻"},{"unified":"1f9d8-1f3fc","native":"🧘🏼"},{"unified":"1f9d8-1f3fd","native":"🧘🏽"},{"unified":"1f9d8-1f3fe","native":"🧘🏾"},{"unified":"1f9d8-1f3ff","native":"🧘🏿"}],"version":5},"man_in_lotus_position":{"id":"man_in_lotus_position","name":"Man in Lotus Position","keywords":["male","meditation","yoga","serenity","zen","mindfulness"],"skins":[{"unified":"1f9d8-200d-2642-fe0f","native":"🧘♂️"},{"unified":"1f9d8-1f3fb-200d-2642-fe0f","native":"🧘🏻♂️"},{"unified":"1f9d8-1f3fc-200d-2642-fe0f","native":"🧘🏼♂️"},{"unified":"1f9d8-1f3fd-200d-2642-fe0f","native":"🧘🏽♂️"},{"unified":"1f9d8-1f3fe-200d-2642-fe0f","native":"🧘🏾♂️"},{"unified":"1f9d8-1f3ff-200d-2642-fe0f","native":"🧘🏿♂️"}],"version":5},"woman_in_lotus_position":{"id":"woman_in_lotus_position","name":"Woman in Lotus Position","keywords":["female","meditation","yoga","serenity","zen","mindfulness"],"skins":[{"unified":"1f9d8-200d-2640-fe0f","native":"🧘♀️"},{"unified":"1f9d8-1f3fb-200d-2640-fe0f","native":"🧘🏻♀️"},{"unified":"1f9d8-1f3fc-200d-2640-fe0f","native":"🧘🏼♀️"},{"unified":"1f9d8-1f3fd-200d-2640-fe0f","native":"🧘🏽♀️"},{"unified":"1f9d8-1f3fe-200d-2640-fe0f","native":"🧘🏾♀️"},{"unified":"1f9d8-1f3ff-200d-2640-fe0f","native":"🧘🏿♀️"}],"version":5},"bath":{"id":"bath","name":"Bath","keywords":["person","taking","clean","shower","bathroom"],"skins":[{"unified":"1f6c0","native":"🛀"},{"unified":"1f6c0-1f3fb","native":"🛀🏻"},{"unified":"1f6c0-1f3fc","native":"🛀🏼"},{"unified":"1f6c0-1f3fd","native":"🛀🏽"},{"unified":"1f6c0-1f3fe","native":"🛀🏾"},{"unified":"1f6c0-1f3ff","native":"🛀🏿"}],"version":1},"sleeping_accommodation":{"id":"sleeping_accommodation","name":"Person in Bed","keywords":["sleeping","accommodation","rest"],"skins":[{"unified":"1f6cc","native":"🛌"},{"unified":"1f6cc-1f3fb","native":"🛌🏻"},{"unified":"1f6cc-1f3fc","native":"🛌🏼"},{"unified":"1f6cc-1f3fd","native":"🛌🏽"},{"unified":"1f6cc-1f3fe","native":"🛌🏾"},{"unified":"1f6cc-1f3ff","native":"🛌🏿"}],"version":1},"people_holding_hands":{"id":"people_holding_hands","name":"People Holding Hands","keywords":["friendship"],"skins":[{"unified":"1f9d1-200d-1f91d-200d-1f9d1","native":"🧑🤝🧑"},{"unified":"1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fb","native":"🧑🏻🤝🧑🏻"},{"unified":"1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fc","native":"🧑🏼🤝🧑🏼"},{"unified":"1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fd","native":"🧑🏽🤝🧑🏽"},{"unified":"1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fe","native":"🧑🏾🤝🧑🏾"},{"unified":"1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3ff","native":"🧑🏿🤝🧑🏿"}],"version":12},"two_women_holding_hands":{"id":"two_women_holding_hands","name":"Women Holding Hands","keywords":["two","pair","friendship","couple","love","like","female","people","human"],"skins":[{"unified":"1f46d","native":"👭"},{"unified":"1f46d-1f3fb","native":"👭🏻"},{"unified":"1f46d-1f3fc","native":"👭🏼"},{"unified":"1f46d-1f3fd","native":"👭🏽"},{"unified":"1f46d-1f3fe","native":"👭🏾"},{"unified":"1f46d-1f3ff","native":"👭🏿"}],"version":1},"man_and_woman_holding_hands":{"id":"man_and_woman_holding_hands","name":"Man and Woman Holding Hands","keywords":["couple","pair","people","human","love","date","dating","like","affection","valentines","marriage"],"skins":[{"unified":"1f46b","native":"👫"},{"unified":"1f46b-1f3fb","native":"👫🏻"},{"unified":"1f46b-1f3fc","native":"👫🏼"},{"unified":"1f46b-1f3fd","native":"👫🏽"},{"unified":"1f46b-1f3fe","native":"👫🏾"},{"unified":"1f46b-1f3ff","native":"👫🏿"}],"version":1},"two_men_holding_hands":{"id":"two_men_holding_hands","name":"Men Holding Hands","keywords":["two","pair","couple","love","like","bromance","friendship","people","human"],"skins":[{"unified":"1f46c","native":"👬"},{"unified":"1f46c-1f3fb","native":"👬🏻"},{"unified":"1f46c-1f3fc","native":"👬🏼"},{"unified":"1f46c-1f3fd","native":"👬🏽"},{"unified":"1f46c-1f3fe","native":"👬🏾"},{"unified":"1f46c-1f3ff","native":"👬🏿"}],"version":1},"couplekiss":{"id":"couplekiss","name":"Kiss","keywords":["couplekiss","pair","valentines","love","like","dating","marriage"],"skins":[{"unified":"1f48f","native":"💏"},{"unified":"1f48f-1f3fb","native":"💏🏻"},{"unified":"1f48f-1f3fc","native":"💏🏼"},{"unified":"1f48f-1f3fd","native":"💏🏽"},{"unified":"1f48f-1f3fe","native":"💏🏾"},{"unified":"1f48f-1f3ff","native":"💏🏿"}],"version":1},"woman-kiss-man":{"id":"woman-kiss-man","name":"Kiss: Woman, Man","keywords":["woman","kiss-man","kiss","love"],"skins":[{"unified":"1f469-200d-2764-fe0f-200d-1f48b-200d-1f468","native":"👩❤️💋👨"},{"unified":"1f469-1f3fb-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fb","native":"👩🏻❤️💋👨🏻"},{"unified":"1f469-1f3fc-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fc","native":"👩🏼❤️💋👨🏼"},{"unified":"1f469-1f3fd-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fd","native":"👩🏽❤️💋👨🏽"},{"unified":"1f469-1f3fe-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fe","native":"👩🏾❤️💋👨🏾"},{"unified":"1f469-1f3ff-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3ff","native":"👩🏿❤️💋👨🏿"}],"version":2},"man-kiss-man":{"id":"man-kiss-man","name":"Kiss: Man, Man","keywords":["kiss-man","kiss","pair","valentines","love","like","dating","marriage"],"skins":[{"unified":"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468","native":"👨❤️💋👨"},{"unified":"1f468-1f3fb-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fb","native":"👨🏻❤️💋👨🏻"},{"unified":"1f468-1f3fc-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fc","native":"👨🏼❤️💋👨🏼"},{"unified":"1f468-1f3fd-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fd","native":"👨🏽❤️💋👨🏽"},{"unified":"1f468-1f3fe-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fe","native":"👨🏾❤️💋👨🏾"},{"unified":"1f468-1f3ff-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3ff","native":"👨🏿❤️💋👨🏿"}],"version":2},"woman-kiss-woman":{"id":"woman-kiss-woman","name":"Kiss: Woman, Woman","keywords":["kiss-woman","kiss","pair","valentines","love","like","dating","marriage"],"skins":[{"unified":"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469","native":"👩❤️💋👩"},{"unified":"1f469-1f3fb-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3fb","native":"👩🏻❤️💋👩🏻"},{"unified":"1f469-1f3fc-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3fc","native":"👩🏼❤️💋👩🏼"},{"unified":"1f469-1f3fd-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3fd","native":"👩🏽❤️💋👩🏽"},{"unified":"1f469-1f3fe-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3fe","native":"👩🏾❤️💋👩🏾"},{"unified":"1f469-1f3ff-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3ff","native":"👩🏿❤️💋👩🏿"}],"version":2},"couple_with_heart":{"id":"couple_with_heart","name":"Couple with Heart","keywords":["pair","love","like","affection","human","dating","valentines","marriage"],"skins":[{"unified":"1f491","native":"💑"},{"unified":"1f491-1f3fb","native":"💑🏻"},{"unified":"1f491-1f3fc","native":"💑🏼"},{"unified":"1f491-1f3fd","native":"💑🏽"},{"unified":"1f491-1f3fe","native":"💑🏾"},{"unified":"1f491-1f3ff","native":"💑🏿"}],"version":1},"woman-heart-man":{"id":"woman-heart-man","name":"Couple with Heart: Woman, Man","keywords":["woman","heart-man","heart","love"],"skins":[{"unified":"1f469-200d-2764-fe0f-200d-1f468","native":"👩❤️👨"},{"unified":"1f469-1f3fb-200d-2764-fe0f-200d-1f468-1f3fb","native":"👩🏻❤️👨🏻"},{"unified":"1f469-1f3fc-200d-2764-fe0f-200d-1f468-1f3fc","native":"👩🏼❤️👨🏼"},{"unified":"1f469-1f3fd-200d-2764-fe0f-200d-1f468-1f3fd","native":"👩🏽❤️👨🏽"},{"unified":"1f469-1f3fe-200d-2764-fe0f-200d-1f468-1f3fe","native":"👩🏾❤️👨🏾"},{"unified":"1f469-1f3ff-200d-2764-fe0f-200d-1f468-1f3ff","native":"👩🏿❤️👨🏿"}],"version":2},"man-heart-man":{"id":"man-heart-man","name":"Couple with Heart: Man, Man","keywords":["heart-man","heart","pair","love","like","affection","human","dating","valentines","marriage"],"skins":[{"unified":"1f468-200d-2764-fe0f-200d-1f468","native":"👨❤️👨"},{"unified":"1f468-1f3fb-200d-2764-fe0f-200d-1f468-1f3fb","native":"👨🏻❤️👨🏻"},{"unified":"1f468-1f3fc-200d-2764-fe0f-200d-1f468-1f3fc","native":"👨🏼❤️👨🏼"},{"unified":"1f468-1f3fd-200d-2764-fe0f-200d-1f468-1f3fd","native":"👨🏽❤️👨🏽"},{"unified":"1f468-1f3fe-200d-2764-fe0f-200d-1f468-1f3fe","native":"👨🏾❤️👨🏾"},{"unified":"1f468-1f3ff-200d-2764-fe0f-200d-1f468-1f3ff","native":"👨🏿❤️👨🏿"}],"version":2},"woman-heart-woman":{"id":"woman-heart-woman","name":"Couple with Heart: Woman, Woman","keywords":["heart-woman","heart","pair","love","like","affection","human","dating","valentines","marriage"],"skins":[{"unified":"1f469-200d-2764-fe0f-200d-1f469","native":"👩❤️👩"},{"unified":"1f469-1f3fb-200d-2764-fe0f-200d-1f469-1f3fb","native":"👩🏻❤️👩🏻"},{"unified":"1f469-1f3fc-200d-2764-fe0f-200d-1f469-1f3fc","native":"👩🏼❤️👩🏼"},{"unified":"1f469-1f3fd-200d-2764-fe0f-200d-1f469-1f3fd","native":"👩🏽❤️👩🏽"},{"unified":"1f469-1f3fe-200d-2764-fe0f-200d-1f469-1f3fe","native":"👩🏾❤️👩🏾"},{"unified":"1f469-1f3ff-200d-2764-fe0f-200d-1f469-1f3ff","native":"👩🏿❤️👩🏿"}],"version":2},"family":{"id":"family","name":"Family","keywords":["home","parents","child","mom","dad","father","mother","people","human"],"skins":[{"unified":"1f46a","native":"👪"}],"version":1},"man-woman-boy":{"id":"man-woman-boy","name":"Family: Man, Woman, Boy","keywords":["man","woman-boy","family","woman","love"],"skins":[{"unified":"1f468-200d-1f469-200d-1f466","native":"👨👩👦"}],"version":2},"man-woman-girl":{"id":"man-woman-girl","name":"Family: Man, Woman, Girl","keywords":["man","woman-girl","family","woman","home","parents","people","human","child"],"skins":[{"unified":"1f468-200d-1f469-200d-1f467","native":"👨👩👧"}],"version":2},"man-woman-girl-boy":{"id":"man-woman-girl-boy","name":"Family: Man, Woman, Girl, Boy","keywords":["man","woman-girl-boy","family","woman","girl","home","parents","people","human","children"],"skins":[{"unified":"1f468-200d-1f469-200d-1f467-200d-1f466","native":"👨👩👧👦"}],"version":2},"man-woman-boy-boy":{"id":"man-woman-boy-boy","name":"Family: Man, Woman, Boy, Boy","keywords":["man","woman-boy-boy","family","woman","home","parents","people","human","children"],"skins":[{"unified":"1f468-200d-1f469-200d-1f466-200d-1f466","native":"👨👩👦👦"}],"version":2},"man-woman-girl-girl":{"id":"man-woman-girl-girl","name":"Family: Man, Woman, Girl, Girl","keywords":["man","woman-girl-girl","family","woman","home","parents","people","human","children"],"skins":[{"unified":"1f468-200d-1f469-200d-1f467-200d-1f467","native":"👨👩👧👧"}],"version":2},"man-man-boy":{"id":"man-man-boy","name":"Family: Man, Man, Boy","keywords":["man","man-boy","family","home","parents","people","human","children"],"skins":[{"unified":"1f468-200d-1f468-200d-1f466","native":"👨👨👦"}],"version":2},"man-man-girl":{"id":"man-man-girl","name":"Family: Man, Man, Girl","keywords":["man","man-girl","family","home","parents","people","human","children"],"skins":[{"unified":"1f468-200d-1f468-200d-1f467","native":"👨👨👧"}],"version":2},"man-man-girl-boy":{"id":"man-man-girl-boy","name":"Family: Man, Man, Girl, Boy","keywords":["man","man-girl-boy","family","girl","home","parents","people","human","children"],"skins":[{"unified":"1f468-200d-1f468-200d-1f467-200d-1f466","native":"👨👨👧👦"}],"version":2},"man-man-boy-boy":{"id":"man-man-boy-boy","name":"Family: Man, Man, Boy, Boy","keywords":["man","man-boy-boy","family","home","parents","people","human","children"],"skins":[{"unified":"1f468-200d-1f468-200d-1f466-200d-1f466","native":"👨👨👦👦"}],"version":2},"man-man-girl-girl":{"id":"man-man-girl-girl","name":"Family: Man, Man, Girl, Girl","keywords":["man","man-girl-girl","family","home","parents","people","human","children"],"skins":[{"unified":"1f468-200d-1f468-200d-1f467-200d-1f467","native":"👨👨👧👧"}],"version":2},"woman-woman-boy":{"id":"woman-woman-boy","name":"Family: Woman, Woman, Boy","keywords":["woman","woman-boy","family","home","parents","people","human","children"],"skins":[{"unified":"1f469-200d-1f469-200d-1f466","native":"👩👩👦"}],"version":2},"woman-woman-girl":{"id":"woman-woman-girl","name":"Family: Woman, Woman, Girl","keywords":["woman","woman-girl","family","home","parents","people","human","children"],"skins":[{"unified":"1f469-200d-1f469-200d-1f467","native":"👩👩👧"}],"version":2},"woman-woman-girl-boy":{"id":"woman-woman-girl-boy","name":"Family: Woman, Woman, Girl, Boy","keywords":["woman","woman-girl-boy","family","girl","home","parents","people","human","children"],"skins":[{"unified":"1f469-200d-1f469-200d-1f467-200d-1f466","native":"👩👩👧👦"}],"version":2},"woman-woman-boy-boy":{"id":"woman-woman-boy-boy","name":"Family: Woman, Woman, Boy, Boy","keywords":["woman","woman-boy-boy","family","home","parents","people","human","children"],"skins":[{"unified":"1f469-200d-1f469-200d-1f466-200d-1f466","native":"👩👩👦👦"}],"version":2},"woman-woman-girl-girl":{"id":"woman-woman-girl-girl","name":"Family: Woman, Woman, Girl, Girl","keywords":["woman","woman-girl-girl","family","home","parents","people","human","children"],"skins":[{"unified":"1f469-200d-1f469-200d-1f467-200d-1f467","native":"👩👩👧👧"}],"version":2},"man-boy":{"id":"man-boy","name":"Family: Man, Boy","keywords":["man","family","home","parent","people","human","child"],"skins":[{"unified":"1f468-200d-1f466","native":"👨👦"}],"version":4},"man-boy-boy":{"id":"man-boy-boy","name":"Family: Man, Boy, Boy","keywords":["man","boy-boy","family","home","parent","people","human","children"],"skins":[{"unified":"1f468-200d-1f466-200d-1f466","native":"👨👦👦"}],"version":4},"man-girl":{"id":"man-girl","name":"Family: Man, Girl","keywords":["man","family","home","parent","people","human","child"],"skins":[{"unified":"1f468-200d-1f467","native":"👨👧"}],"version":4},"man-girl-boy":{"id":"man-girl-boy","name":"Family: Man, Girl, Boy","keywords":["man","girl-boy","family","girl","home","parent","people","human","children"],"skins":[{"unified":"1f468-200d-1f467-200d-1f466","native":"👨👧👦"}],"version":4},"man-girl-girl":{"id":"man-girl-girl","name":"Family: Man, Girl, Girl","keywords":["man","girl-girl","family","home","parent","people","human","children"],"skins":[{"unified":"1f468-200d-1f467-200d-1f467","native":"👨👧👧"}],"version":4},"woman-boy":{"id":"woman-boy","name":"Family: Woman, Boy","keywords":["woman","family","home","parent","people","human","child"],"skins":[{"unified":"1f469-200d-1f466","native":"👩👦"}],"version":4},"woman-boy-boy":{"id":"woman-boy-boy","name":"Family: Woman, Boy, Boy","keywords":["woman","boy-boy","family","home","parent","people","human","children"],"skins":[{"unified":"1f469-200d-1f466-200d-1f466","native":"👩👦👦"}],"version":4},"woman-girl":{"id":"woman-girl","name":"Family: Woman, Girl","keywords":["woman","family","home","parent","people","human","child"],"skins":[{"unified":"1f469-200d-1f467","native":"👩👧"}],"version":4},"woman-girl-boy":{"id":"woman-girl-boy","name":"Family: Woman, Girl, Boy","keywords":["woman","girl-boy","family","girl","home","parent","people","human","children"],"skins":[{"unified":"1f469-200d-1f467-200d-1f466","native":"👩👧👦"}],"version":4},"woman-girl-girl":{"id":"woman-girl-girl","name":"Family: Woman, Girl, Girl","keywords":["woman","girl-girl","family","home","parent","people","human","children"],"skins":[{"unified":"1f469-200d-1f467-200d-1f467","native":"👩👧👧"}],"version":4},"speaking_head_in_silhouette":{"id":"speaking_head_in_silhouette","name":"Speaking Head","keywords":["in","silhouette","user","person","human","sing","say","talk"],"skins":[{"unified":"1f5e3-fe0f","native":"🗣️"}],"version":1},"bust_in_silhouette":{"id":"bust_in_silhouette","name":"Bust in Silhouette","keywords":["user","person","human"],"skins":[{"unified":"1f464","native":"👤"}],"version":1},"busts_in_silhouette":{"id":"busts_in_silhouette","name":"Busts in Silhouette","keywords":["user","person","human","group","team"],"skins":[{"unified":"1f465","native":"👥"}],"version":1},"people_hugging":{"id":"people_hugging","name":"People Hugging","keywords":["care"],"skins":[{"unified":"1fac2","native":"🫂"}],"version":13},"footprints":{"id":"footprints","name":"Footprints","keywords":["feet","tracking","walking","beach"],"skins":[{"unified":"1f463","native":"👣"}],"version":1},"monkey_face":{"id":"monkey_face","name":"Monkey Face","emoticons":[":o)"],"keywords":["animal","nature","circus"],"skins":[{"unified":"1f435","native":"🐵"}],"version":1},"monkey":{"id":"monkey","name":"Monkey","keywords":["animal","nature","banana","circus"],"skins":[{"unified":"1f412","native":"🐒"}],"version":1},"gorilla":{"id":"gorilla","name":"Gorilla","keywords":["animal","nature","circus"],"skins":[{"unified":"1f98d","native":"🦍"}],"version":3},"orangutan":{"id":"orangutan","name":"Orangutan","keywords":["animal"],"skins":[{"unified":"1f9a7","native":"🦧"}],"version":12},"dog":{"id":"dog","name":"Dog Face","keywords":["animal","friend","nature","woof","puppy","pet","faithful"],"skins":[{"unified":"1f436","native":"🐶"}],"version":1},"dog2":{"id":"dog2","name":"Dog","keywords":["dog2","animal","nature","friend","doge","pet","faithful"],"skins":[{"unified":"1f415","native":"🐕"}],"version":1},"guide_dog":{"id":"guide_dog","name":"Guide Dog","keywords":["animal","blind"],"skins":[{"unified":"1f9ae","native":"🦮"}],"version":12},"service_dog":{"id":"service_dog","name":"Service Dog","keywords":["blind","animal"],"skins":[{"unified":"1f415-200d-1f9ba","native":"🐕🦺"}],"version":12},"poodle":{"id":"poodle","name":"Poodle","keywords":["dog","animal","101","nature","pet"],"skins":[{"unified":"1f429","native":"🐩"}],"version":1},"wolf":{"id":"wolf","name":"Wolf","keywords":["animal","nature","wild"],"skins":[{"unified":"1f43a","native":"🐺"}],"version":1},"fox_face":{"id":"fox_face","name":"Fox","keywords":["face","animal","nature"],"skins":[{"unified":"1f98a","native":"🦊"}],"version":3},"raccoon":{"id":"raccoon","name":"Raccoon","keywords":["animal","nature"],"skins":[{"unified":"1f99d","native":"🦝"}],"version":11},"cat":{"id":"cat","name":"Cat Face","keywords":["animal","meow","nature","pet","kitten"],"skins":[{"unified":"1f431","native":"🐱"}],"version":1},"cat2":{"id":"cat2","name":"Cat","keywords":["cat2","animal","meow","pet","cats"],"skins":[{"unified":"1f408","native":"🐈"}],"version":1},"black_cat":{"id":"black_cat","name":"Black Cat","keywords":["superstition","luck"],"skins":[{"unified":"1f408-200d-2b1b","native":"🐈⬛"}],"version":13},"lion_face":{"id":"lion_face","name":"Lion","keywords":["face","animal","nature"],"skins":[{"unified":"1f981","native":"🦁"}],"version":1},"tiger":{"id":"tiger","name":"Tiger Face","keywords":["animal","cat","danger","wild","nature","roar"],"skins":[{"unified":"1f42f","native":"🐯"}],"version":1},"tiger2":{"id":"tiger2","name":"Tiger","keywords":["tiger2","animal","nature","roar"],"skins":[{"unified":"1f405","native":"🐅"}],"version":1},"leopard":{"id":"leopard","name":"Leopard","keywords":["animal","nature"],"skins":[{"unified":"1f406","native":"🐆"}],"version":1},"horse":{"id":"horse","name":"Horse Face","keywords":["animal","brown","nature"],"skins":[{"unified":"1f434","native":"🐴"}],"version":1},"moose":{"id":"moose","name":"Moose","keywords":["shrek","canada","sweden","sven","cool"],"skins":[{"unified":"1face","native":"🫎"}],"version":15},"donkey":{"id":"donkey","name":"Donkey","keywords":["eeyore","mule"],"skins":[{"unified":"1facf","native":"🫏"}],"version":15},"racehorse":{"id":"racehorse","name":"Horse","keywords":["racehorse","animal","gamble","luck"],"skins":[{"unified":"1f40e","native":"🐎"}],"version":1},"unicorn_face":{"id":"unicorn_face","name":"Unicorn","keywords":["face","animal","nature","mystical"],"skins":[{"unified":"1f984","native":"🦄"}],"version":1},"zebra_face":{"id":"zebra_face","name":"Zebra","keywords":["face","animal","nature","stripes","safari"],"skins":[{"unified":"1f993","native":"🦓"}],"version":5},"deer":{"id":"deer","name":"Deer","keywords":["animal","nature","horns","venison"],"skins":[{"unified":"1f98c","native":"🦌"}],"version":3},"bison":{"id":"bison","name":"Bison","keywords":["ox"],"skins":[{"unified":"1f9ac","native":"🦬"}],"version":13},"cow":{"id":"cow","name":"Cow Face","keywords":["beef","ox","animal","nature","moo","milk"],"skins":[{"unified":"1f42e","native":"🐮"}],"version":1},"ox":{"id":"ox","name":"Ox","keywords":["animal","cow","beef"],"skins":[{"unified":"1f402","native":"🐂"}],"version":1},"water_buffalo":{"id":"water_buffalo","name":"Water Buffalo","keywords":["animal","nature","ox","cow"],"skins":[{"unified":"1f403","native":"🐃"}],"version":1},"cow2":{"id":"cow2","name":"Cow","keywords":["cow2","beef","ox","animal","nature","moo","milk"],"skins":[{"unified":"1f404","native":"🐄"}],"version":1},"pig":{"id":"pig","name":"Pig Face","keywords":["animal","oink","nature"],"skins":[{"unified":"1f437","native":"🐷"}],"version":1},"pig2":{"id":"pig2","name":"Pig","keywords":["pig2","animal","nature"],"skins":[{"unified":"1f416","native":"🐖"}],"version":1},"boar":{"id":"boar","name":"Boar","keywords":["animal","nature"],"skins":[{"unified":"1f417","native":"🐗"}],"version":1},"pig_nose":{"id":"pig_nose","name":"Pig Nose","keywords":["animal","oink"],"skins":[{"unified":"1f43d","native":"🐽"}],"version":1},"ram":{"id":"ram","name":"Ram","keywords":["animal","sheep","nature"],"skins":[{"unified":"1f40f","native":"🐏"}],"version":1},"sheep":{"id":"sheep","name":"Ewe","keywords":["sheep","animal","nature","wool","shipit"],"skins":[{"unified":"1f411","native":"🐑"}],"version":1},"goat":{"id":"goat","name":"Goat","keywords":["animal","nature"],"skins":[{"unified":"1f410","native":"🐐"}],"version":1},"dromedary_camel":{"id":"dromedary_camel","name":"Camel","keywords":["dromedary","animal","hot","desert","hump"],"skins":[{"unified":"1f42a","native":"🐪"}],"version":1},"camel":{"id":"camel","name":"Bactrian Camel","keywords":["two","hump","animal","nature","hot","desert"],"skins":[{"unified":"1f42b","native":"🐫"}],"version":1},"llama":{"id":"llama","name":"Llama","keywords":["animal","nature","alpaca"],"skins":[{"unified":"1f999","native":"🦙"}],"version":11},"giraffe_face":{"id":"giraffe_face","name":"Giraffe","keywords":["face","animal","nature","spots","safari"],"skins":[{"unified":"1f992","native":"🦒"}],"version":5},"elephant":{"id":"elephant","name":"Elephant","keywords":["animal","nature","nose","th","circus"],"skins":[{"unified":"1f418","native":"🐘"}],"version":1},"mammoth":{"id":"mammoth","name":"Mammoth","keywords":["elephant","tusks"],"skins":[{"unified":"1f9a3","native":"🦣"}],"version":13},"rhinoceros":{"id":"rhinoceros","name":"Rhinoceros","keywords":["animal","nature","horn"],"skins":[{"unified":"1f98f","native":"🦏"}],"version":3},"hippopotamus":{"id":"hippopotamus","name":"Hippopotamus","keywords":["animal","nature"],"skins":[{"unified":"1f99b","native":"🦛"}],"version":11},"mouse":{"id":"mouse","name":"Mouse Face","keywords":["animal","nature","cheese","wedge","rodent"],"skins":[{"unified":"1f42d","native":"🐭"}],"version":1},"mouse2":{"id":"mouse2","name":"Mouse","keywords":["mouse2","animal","nature","rodent"],"skins":[{"unified":"1f401","native":"🐁"}],"version":1},"rat":{"id":"rat","name":"Rat","keywords":["animal","mouse","rodent"],"skins":[{"unified":"1f400","native":"🐀"}],"version":1},"hamster":{"id":"hamster","name":"Hamster","keywords":["animal","nature"],"skins":[{"unified":"1f439","native":"🐹"}],"version":1},"rabbit":{"id":"rabbit","name":"Rabbit Face","keywords":["animal","nature","pet","spring","magic","bunny"],"skins":[{"unified":"1f430","native":"🐰"}],"version":1},"rabbit2":{"id":"rabbit2","name":"Rabbit","keywords":["rabbit2","animal","nature","pet","magic","spring"],"skins":[{"unified":"1f407","native":"🐇"}],"version":1},"chipmunk":{"id":"chipmunk","name":"Chipmunk","keywords":["animal","nature","rodent","squirrel"],"skins":[{"unified":"1f43f-fe0f","native":"🐿️"}],"version":1},"beaver":{"id":"beaver","name":"Beaver","keywords":["animal","rodent"],"skins":[{"unified":"1f9ab","native":"🦫"}],"version":13},"hedgehog":{"id":"hedgehog","name":"Hedgehog","keywords":["animal","nature","spiny"],"skins":[{"unified":"1f994","native":"🦔"}],"version":5},"bat":{"id":"bat","name":"Bat","keywords":["animal","nature","blind","vampire"],"skins":[{"unified":"1f987","native":"🦇"}],"version":3},"bear":{"id":"bear","name":"Bear","keywords":["animal","nature","wild"],"skins":[{"unified":"1f43b","native":"🐻"}],"version":1},"polar_bear":{"id":"polar_bear","name":"Polar Bear","keywords":["animal","arctic"],"skins":[{"unified":"1f43b-200d-2744-fe0f","native":"🐻❄️"}],"version":13},"koala":{"id":"koala","name":"Koala","keywords":["animal","nature"],"skins":[{"unified":"1f428","native":"🐨"}],"version":1},"panda_face":{"id":"panda_face","name":"Panda","keywords":["face","animal","nature"],"skins":[{"unified":"1f43c","native":"🐼"}],"version":1},"sloth":{"id":"sloth","name":"Sloth","keywords":["animal"],"skins":[{"unified":"1f9a5","native":"🦥"}],"version":12},"otter":{"id":"otter","name":"Otter","keywords":["animal"],"skins":[{"unified":"1f9a6","native":"🦦"}],"version":12},"skunk":{"id":"skunk","name":"Skunk","keywords":["animal"],"skins":[{"unified":"1f9a8","native":"🦨"}],"version":12},"kangaroo":{"id":"kangaroo","name":"Kangaroo","keywords":["animal","nature","australia","joey","hop","marsupial"],"skins":[{"unified":"1f998","native":"🦘"}],"version":11},"badger":{"id":"badger","name":"Badger","keywords":["animal","nature","honey"],"skins":[{"unified":"1f9a1","native":"🦡"}],"version":11},"feet":{"id":"feet","name":"Paw Prints","keywords":["feet","animal","tracking","footprints","dog","cat","pet"],"skins":[{"unified":"1f43e","native":"🐾"}],"version":1},"turkey":{"id":"turkey","name":"Turkey","keywords":["animal","bird"],"skins":[{"unified":"1f983","native":"🦃"}],"version":1},"chicken":{"id":"chicken","name":"Chicken","keywords":["animal","cluck","nature","bird"],"skins":[{"unified":"1f414","native":"🐔"}],"version":1},"rooster":{"id":"rooster","name":"Rooster","keywords":["animal","nature","chicken"],"skins":[{"unified":"1f413","native":"🐓"}],"version":1},"hatching_chick":{"id":"hatching_chick","name":"Hatching Chick","keywords":["animal","chicken","egg","born","baby","bird"],"skins":[{"unified":"1f423","native":"🐣"}],"version":1},"baby_chick":{"id":"baby_chick","name":"Baby Chick","keywords":["animal","chicken","bird"],"skins":[{"unified":"1f424","native":"🐤"}],"version":1},"hatched_chick":{"id":"hatched_chick","name":"Front-Facing Baby Chick","keywords":["hatched","front","facing","animal","chicken","bird"],"skins":[{"unified":"1f425","native":"🐥"}],"version":1},"bird":{"id":"bird","name":"Bird","keywords":["animal","nature","fly","tweet","spring"],"skins":[{"unified":"1f426","native":"🐦"}],"version":1},"penguin":{"id":"penguin","name":"Penguin","keywords":["animal","nature"],"skins":[{"unified":"1f427","native":"🐧"}],"version":1},"dove_of_peace":{"id":"dove_of_peace","name":"Dove","keywords":["of","peace","animal","bird"],"skins":[{"unified":"1f54a-fe0f","native":"🕊️"}],"version":1},"eagle":{"id":"eagle","name":"Eagle","keywords":["animal","nature","bird"],"skins":[{"unified":"1f985","native":"🦅"}],"version":3},"duck":{"id":"duck","name":"Duck","keywords":["animal","nature","bird","mallard"],"skins":[{"unified":"1f986","native":"🦆"}],"version":3},"swan":{"id":"swan","name":"Swan","keywords":["animal","nature","bird"],"skins":[{"unified":"1f9a2","native":"🦢"}],"version":11},"owl":{"id":"owl","name":"Owl","keywords":["animal","nature","bird","hoot"],"skins":[{"unified":"1f989","native":"🦉"}],"version":3},"dodo":{"id":"dodo","name":"Dodo","keywords":["animal","bird"],"skins":[{"unified":"1f9a4","native":"🦤"}],"version":13},"feather":{"id":"feather","name":"Feather","keywords":["bird","fly"],"skins":[{"unified":"1fab6","native":"🪶"}],"version":13},"flamingo":{"id":"flamingo","name":"Flamingo","keywords":["animal"],"skins":[{"unified":"1f9a9","native":"🦩"}],"version":12},"peacock":{"id":"peacock","name":"Peacock","keywords":["animal","nature","peahen","bird"],"skins":[{"unified":"1f99a","native":"🦚"}],"version":11},"parrot":{"id":"parrot","name":"Parrot","keywords":["animal","nature","bird","pirate","talk"],"skins":[{"unified":"1f99c","native":"🦜"}],"version":11},"wing":{"id":"wing","name":"Wing","keywords":["angel","birds","flying"],"skins":[{"unified":"1fabd","native":"🪽"}],"version":15},"black_bird":{"id":"black_bird","name":"Black Bird","keywords":["crow"],"skins":[{"unified":"1f426-200d-2b1b","native":"🐦⬛"}],"version":15},"goose":{"id":"goose","name":"Goose","keywords":["silly","jemima","goosebumps"],"skins":[{"unified":"1fabf","native":"🪿"}],"version":15},"frog":{"id":"frog","name":"Frog","keywords":["animal","nature","croak","toad"],"skins":[{"unified":"1f438","native":"🐸"}],"version":1},"crocodile":{"id":"crocodile","name":"Crocodile","keywords":["animal","nature","reptile","lizard","alligator"],"skins":[{"unified":"1f40a","native":"🐊"}],"version":1},"turtle":{"id":"turtle","name":"Turtle","keywords":["animal","slow","nature","tortoise"],"skins":[{"unified":"1f422","native":"🐢"}],"version":1},"lizard":{"id":"lizard","name":"Lizard","keywords":["animal","nature","reptile"],"skins":[{"unified":"1f98e","native":"🦎"}],"version":3},"snake":{"id":"snake","name":"Snake","keywords":["animal","evil","nature","hiss","python"],"skins":[{"unified":"1f40d","native":"🐍"}],"version":1},"dragon_face":{"id":"dragon_face","name":"Dragon Face","keywords":["animal","myth","nature","chinese","green"],"skins":[{"unified":"1f432","native":"🐲"}],"version":1},"dragon":{"id":"dragon","name":"Dragon","keywords":["animal","myth","nature","chinese","green"],"skins":[{"unified":"1f409","native":"🐉"}],"version":1},"sauropod":{"id":"sauropod","name":"Sauropod","keywords":["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],"skins":[{"unified":"1f995","native":"🦕"}],"version":5},"t-rex":{"id":"t-rex","name":"T-Rex","keywords":["t","rex","animal","nature","dinosaur","tyrannosaurus","extinct"],"skins":[{"unified":"1f996","native":"🦖"}],"version":5},"whale":{"id":"whale","name":"Spouting Whale","keywords":["animal","nature","sea","ocean"],"skins":[{"unified":"1f433","native":"🐳"}],"version":1},"whale2":{"id":"whale2","name":"Whale","keywords":["whale2","animal","nature","sea","ocean"],"skins":[{"unified":"1f40b","native":"🐋"}],"version":1},"dolphin":{"id":"dolphin","name":"Dolphin","keywords":["flipper","animal","nature","fish","sea","ocean","fins","beach"],"skins":[{"unified":"1f42c","native":"🐬"}],"version":1},"seal":{"id":"seal","name":"Seal","keywords":["animal","creature","sea"],"skins":[{"unified":"1f9ad","native":"🦭"}],"version":13},"fish":{"id":"fish","name":"Fish","keywords":["animal","food","nature"],"skins":[{"unified":"1f41f","native":"🐟"}],"version":1},"tropical_fish":{"id":"tropical_fish","name":"Tropical Fish","keywords":["animal","swim","ocean","beach","nemo"],"skins":[{"unified":"1f420","native":"🐠"}],"version":1},"blowfish":{"id":"blowfish","name":"Blowfish","keywords":["animal","nature","food","sea","ocean"],"skins":[{"unified":"1f421","native":"🐡"}],"version":1},"shark":{"id":"shark","name":"Shark","keywords":["animal","nature","fish","sea","ocean","jaws","fins","beach"],"skins":[{"unified":"1f988","native":"🦈"}],"version":3},"octopus":{"id":"octopus","name":"Octopus","keywords":["animal","creature","ocean","sea","nature","beach"],"skins":[{"unified":"1f419","native":"🐙"}],"version":1},"shell":{"id":"shell","name":"Spiral Shell","keywords":["nature","sea","beach"],"skins":[{"unified":"1f41a","native":"🐚"}],"version":1},"coral":{"id":"coral","name":"Coral","keywords":["ocean","sea","reef"],"skins":[{"unified":"1fab8","native":"🪸"}],"version":14},"jellyfish":{"id":"jellyfish","name":"Jellyfish","keywords":["sting","tentacles"],"skins":[{"unified":"1fabc","native":"🪼"}],"version":15},"snail":{"id":"snail","name":"Snail","keywords":["slow","animal","shell"],"skins":[{"unified":"1f40c","native":"🐌"}],"version":1},"butterfly":{"id":"butterfly","name":"Butterfly","keywords":["animal","insect","nature","caterpillar"],"skins":[{"unified":"1f98b","native":"🦋"}],"version":3},"bug":{"id":"bug","name":"Bug","keywords":["animal","insect","nature","worm"],"skins":[{"unified":"1f41b","native":"🐛"}],"version":1},"ant":{"id":"ant","name":"Ant","keywords":["animal","insect","nature","bug"],"skins":[{"unified":"1f41c","native":"🐜"}],"version":1},"bee":{"id":"bee","name":"Honeybee","keywords":["bee","animal","insect","nature","bug","spring","honey"],"skins":[{"unified":"1f41d","native":"🐝"}],"version":1},"beetle":{"id":"beetle","name":"Beetle","keywords":["insect"],"skins":[{"unified":"1fab2","native":"🪲"}],"version":13},"ladybug":{"id":"ladybug","name":"Lady Beetle","keywords":["ladybug","animal","insect","nature"],"skins":[{"unified":"1f41e","native":"🐞"}],"version":1},"cricket":{"id":"cricket","name":"Cricket","keywords":["animal","chirp"],"skins":[{"unified":"1f997","native":"🦗"}],"version":5},"cockroach":{"id":"cockroach","name":"Cockroach","keywords":["insect","pests"],"skins":[{"unified":"1fab3","native":"🪳"}],"version":13},"spider":{"id":"spider","name":"Spider","keywords":["animal","arachnid"],"skins":[{"unified":"1f577-fe0f","native":"🕷️"}],"version":1},"spider_web":{"id":"spider_web","name":"Spider Web","keywords":["animal","insect","arachnid","silk"],"skins":[{"unified":"1f578-fe0f","native":"🕸️"}],"version":1},"scorpion":{"id":"scorpion","name":"Scorpion","keywords":["animal","arachnid"],"skins":[{"unified":"1f982","native":"🦂"}],"version":1},"mosquito":{"id":"mosquito","name":"Mosquito","keywords":["animal","nature","insect","malaria"],"skins":[{"unified":"1f99f","native":"🦟"}],"version":11},"fly":{"id":"fly","name":"Fly","keywords":["insect"],"skins":[{"unified":"1fab0","native":"🪰"}],"version":13},"worm":{"id":"worm","name":"Worm","keywords":["animal"],"skins":[{"unified":"1fab1","native":"🪱"}],"version":13},"microbe":{"id":"microbe","name":"Microbe","keywords":["amoeba","bacteria","germs","virus","covid"],"skins":[{"unified":"1f9a0","native":"🦠"}],"version":11},"bouquet":{"id":"bouquet","name":"Bouquet","keywords":["flowers","nature","spring"],"skins":[{"unified":"1f490","native":"💐"}],"version":1},"cherry_blossom":{"id":"cherry_blossom","name":"Cherry Blossom","keywords":["nature","plant","spring","flower"],"skins":[{"unified":"1f338","native":"🌸"}],"version":1},"white_flower":{"id":"white_flower","name":"White Flower","keywords":["japanese","spring"],"skins":[{"unified":"1f4ae","native":"💮"}],"version":1},"lotus":{"id":"lotus","name":"Lotus","keywords":["flower","calm","meditation"],"skins":[{"unified":"1fab7","native":"🪷"}],"version":14},"rosette":{"id":"rosette","name":"Rosette","keywords":["flower","decoration","military"],"skins":[{"unified":"1f3f5-fe0f","native":"🏵️"}],"version":1},"rose":{"id":"rose","name":"Rose","keywords":["flowers","valentines","love","spring"],"skins":[{"unified":"1f339","native":"🌹"}],"version":1},"wilted_flower":{"id":"wilted_flower","name":"Wilted Flower","keywords":["plant","nature","rose"],"skins":[{"unified":"1f940","native":"🥀"}],"version":3},"hibiscus":{"id":"hibiscus","name":"Hibiscus","keywords":["plant","vegetable","flowers","beach"],"skins":[{"unified":"1f33a","native":"🌺"}],"version":1},"sunflower":{"id":"sunflower","name":"Sunflower","keywords":["nature","plant","fall"],"skins":[{"unified":"1f33b","native":"🌻"}],"version":1},"blossom":{"id":"blossom","name":"Blossom","keywords":["nature","flowers","yellow"],"skins":[{"unified":"1f33c","native":"🌼"}],"version":1},"tulip":{"id":"tulip","name":"Tulip","keywords":["flowers","plant","nature","summer","spring"],"skins":[{"unified":"1f337","native":"🌷"}],"version":1},"hyacinth":{"id":"hyacinth","name":"Hyacinth","keywords":["flower","lavender"],"skins":[{"unified":"1fabb","native":"🪻"}],"version":15},"seedling":{"id":"seedling","name":"Seedling","keywords":["plant","nature","grass","lawn","spring"],"skins":[{"unified":"1f331","native":"🌱"}],"version":1},"potted_plant":{"id":"potted_plant","name":"Potted Plant","keywords":["greenery","house"],"skins":[{"unified":"1fab4","native":"🪴"}],"version":13},"evergreen_tree":{"id":"evergreen_tree","name":"Evergreen Tree","keywords":["plant","nature"],"skins":[{"unified":"1f332","native":"🌲"}],"version":1},"deciduous_tree":{"id":"deciduous_tree","name":"Deciduous Tree","keywords":["plant","nature"],"skins":[{"unified":"1f333","native":"🌳"}],"version":1},"palm_tree":{"id":"palm_tree","name":"Palm Tree","keywords":["plant","vegetable","nature","summer","beach","mojito","tropical"],"skins":[{"unified":"1f334","native":"🌴"}],"version":1},"cactus":{"id":"cactus","name":"Cactus","keywords":["vegetable","plant","nature"],"skins":[{"unified":"1f335","native":"🌵"}],"version":1},"ear_of_rice":{"id":"ear_of_rice","name":"Ear of Rice","keywords":["sheaf","nature","plant"],"skins":[{"unified":"1f33e","native":"🌾"}],"version":1},"herb":{"id":"herb","name":"Herb","keywords":["vegetable","plant","medicine","weed","grass","lawn"],"skins":[{"unified":"1f33f","native":"🌿"}],"version":1},"shamrock":{"id":"shamrock","name":"Shamrock","keywords":["vegetable","plant","nature","irish","clover"],"skins":[{"unified":"2618-fe0f","native":"☘️"}],"version":1},"four_leaf_clover":{"id":"four_leaf_clover","name":"Four Leaf Clover","keywords":["vegetable","plant","nature","lucky","irish"],"skins":[{"unified":"1f340","native":"🍀"}],"version":1},"maple_leaf":{"id":"maple_leaf","name":"Maple Leaf","keywords":["nature","plant","vegetable","ca","fall"],"skins":[{"unified":"1f341","native":"🍁"}],"version":1},"fallen_leaf":{"id":"fallen_leaf","name":"Fallen Leaf","keywords":["nature","plant","vegetable","leaves"],"skins":[{"unified":"1f342","native":"🍂"}],"version":1},"leaves":{"id":"leaves","name":"Leaf Fluttering in Wind","keywords":["leaves","nature","plant","tree","vegetable","grass","lawn","spring"],"skins":[{"unified":"1f343","native":"🍃"}],"version":1},"empty_nest":{"id":"empty_nest","name":"Empty Nest","keywords":["bird"],"skins":[{"unified":"1fab9","native":"🪹"}],"version":14},"nest_with_eggs":{"id":"nest_with_eggs","name":"Nest with Eggs","keywords":["bird"],"skins":[{"unified":"1faba","native":"🪺"}],"version":14},"mushroom":{"id":"mushroom","name":"Mushroom","keywords":["plant","vegetable"],"skins":[{"unified":"1f344","native":"🍄"}],"version":1},"grapes":{"id":"grapes","name":"Grapes","keywords":["fruit","food","wine"],"skins":[{"unified":"1f347","native":"🍇"}],"version":1},"melon":{"id":"melon","name":"Melon","keywords":["fruit","nature","food"],"skins":[{"unified":"1f348","native":"🍈"}],"version":1},"watermelon":{"id":"watermelon","name":"Watermelon","keywords":["fruit","food","picnic","summer"],"skins":[{"unified":"1f349","native":"🍉"}],"version":1},"tangerine":{"id":"tangerine","name":"Tangerine","keywords":["food","fruit","nature","orange"],"skins":[{"unified":"1f34a","native":"🍊"}],"version":1},"lemon":{"id":"lemon","name":"Lemon","keywords":["fruit","nature"],"skins":[{"unified":"1f34b","native":"🍋"}],"version":1},"banana":{"id":"banana","name":"Banana","keywords":["fruit","food","monkey"],"skins":[{"unified":"1f34c","native":"🍌"}],"version":1},"pineapple":{"id":"pineapple","name":"Pineapple","keywords":["fruit","nature","food"],"skins":[{"unified":"1f34d","native":"🍍"}],"version":1},"mango":{"id":"mango","name":"Mango","keywords":["fruit","food","tropical"],"skins":[{"unified":"1f96d","native":"🥭"}],"version":11},"apple":{"id":"apple","name":"Red Apple","keywords":["fruit","mac","school"],"skins":[{"unified":"1f34e","native":"🍎"}],"version":1},"green_apple":{"id":"green_apple","name":"Green Apple","keywords":["fruit","nature"],"skins":[{"unified":"1f34f","native":"🍏"}],"version":1},"pear":{"id":"pear","name":"Pear","keywords":["fruit","nature","food"],"skins":[{"unified":"1f350","native":"🍐"}],"version":1},"peach":{"id":"peach","name":"Peach","keywords":["fruit","nature","food"],"skins":[{"unified":"1f351","native":"🍑"}],"version":1},"cherries":{"id":"cherries","name":"Cherries","keywords":["food","fruit"],"skins":[{"unified":"1f352","native":"🍒"}],"version":1},"strawberry":{"id":"strawberry","name":"Strawberry","keywords":["fruit","food","nature"],"skins":[{"unified":"1f353","native":"🍓"}],"version":1},"blueberries":{"id":"blueberries","name":"Blueberries","keywords":["fruit"],"skins":[{"unified":"1fad0","native":"🫐"}],"version":13},"kiwifruit":{"id":"kiwifruit","name":"Kiwifruit","keywords":["kiwi","fruit","food"],"skins":[{"unified":"1f95d","native":"🥝"}],"version":3},"tomato":{"id":"tomato","name":"Tomato","keywords":["fruit","vegetable","nature","food"],"skins":[{"unified":"1f345","native":"🍅"}],"version":1},"olive":{"id":"olive","name":"Olive","keywords":["fruit"],"skins":[{"unified":"1fad2","native":"🫒"}],"version":13},"coconut":{"id":"coconut","name":"Coconut","keywords":["fruit","nature","food","palm"],"skins":[{"unified":"1f965","native":"🥥"}],"version":5},"avocado":{"id":"avocado","name":"Avocado","keywords":["fruit","food"],"skins":[{"unified":"1f951","native":"🥑"}],"version":3},"eggplant":{"id":"eggplant","name":"Eggplant","keywords":["vegetable","nature","food","aubergine"],"skins":[{"unified":"1f346","native":"🍆"}],"version":1},"potato":{"id":"potato","name":"Potato","keywords":["food","tuber","vegatable","starch"],"skins":[{"unified":"1f954","native":"🥔"}],"version":3},"carrot":{"id":"carrot","name":"Carrot","keywords":["vegetable","food","orange"],"skins":[{"unified":"1f955","native":"🥕"}],"version":3},"corn":{"id":"corn","name":"Ear of Corn","keywords":["food","vegetable","plant"],"skins":[{"unified":"1f33d","native":"🌽"}],"version":1},"hot_pepper":{"id":"hot_pepper","name":"Hot Pepper","keywords":["food","spicy","chilli","chili"],"skins":[{"unified":"1f336-fe0f","native":"🌶️"}],"version":1},"bell_pepper":{"id":"bell_pepper","name":"Bell Pepper","keywords":["fruit","plant"],"skins":[{"unified":"1fad1","native":"🫑"}],"version":13},"cucumber":{"id":"cucumber","name":"Cucumber","keywords":["fruit","food","pickle"],"skins":[{"unified":"1f952","native":"🥒"}],"version":3},"leafy_green":{"id":"leafy_green","name":"Leafy Green","keywords":["food","vegetable","plant","bok","choy","cabbage","kale","lettuce"],"skins":[{"unified":"1f96c","native":"🥬"}],"version":11},"broccoli":{"id":"broccoli","name":"Broccoli","keywords":["fruit","food","vegetable"],"skins":[{"unified":"1f966","native":"🥦"}],"version":5},"garlic":{"id":"garlic","name":"Garlic","keywords":["food","spice","cook"],"skins":[{"unified":"1f9c4","native":"🧄"}],"version":12},"onion":{"id":"onion","name":"Onion","keywords":["cook","food","spice"],"skins":[{"unified":"1f9c5","native":"🧅"}],"version":12},"peanuts":{"id":"peanuts","name":"Peanuts","keywords":["food","nut"],"skins":[{"unified":"1f95c","native":"🥜"}],"version":3},"beans":{"id":"beans","name":"Beans","keywords":["food"],"skins":[{"unified":"1fad8","native":"🫘"}],"version":14},"chestnut":{"id":"chestnut","name":"Chestnut","keywords":["food","squirrel"],"skins":[{"unified":"1f330","native":"🌰"}],"version":1},"ginger_root":{"id":"ginger_root","name":"Ginger Root","keywords":["spice","yellow","cooking","gingerbread"],"skins":[{"unified":"1fada","native":"🫚"}],"version":15},"pea_pod":{"id":"pea_pod","name":"Pea Pod","keywords":["cozy","green"],"skins":[{"unified":"1fadb","native":"🫛"}],"version":15},"bread":{"id":"bread","name":"Bread","keywords":["food","wheat","breakfast","toast"],"skins":[{"unified":"1f35e","native":"🍞"}],"version":1},"croissant":{"id":"croissant","name":"Croissant","keywords":["food","bread","french"],"skins":[{"unified":"1f950","native":"🥐"}],"version":3},"baguette_bread":{"id":"baguette_bread","name":"Baguette Bread","keywords":["food","french","france","bakery"],"skins":[{"unified":"1f956","native":"🥖"}],"version":3},"flatbread":{"id":"flatbread","name":"Flatbread","keywords":["flour","food","bakery"],"skins":[{"unified":"1fad3","native":"🫓"}],"version":13},"pretzel":{"id":"pretzel","name":"Pretzel","keywords":["food","bread","twisted","germany","bakery"],"skins":[{"unified":"1f968","native":"🥨"}],"version":5},"bagel":{"id":"bagel","name":"Bagel","keywords":["food","bread","bakery","schmear","jewish"],"skins":[{"unified":"1f96f","native":"🥯"}],"version":11},"pancakes":{"id":"pancakes","name":"Pancakes","keywords":["food","breakfast","flapjacks","hotcakes","brunch"],"skins":[{"unified":"1f95e","native":"🥞"}],"version":3},"waffle":{"id":"waffle","name":"Waffle","keywords":["food","breakfast","brunch"],"skins":[{"unified":"1f9c7","native":"🧇"}],"version":12},"cheese_wedge":{"id":"cheese_wedge","name":"Cheese Wedge","keywords":["food","chadder","swiss"],"skins":[{"unified":"1f9c0","native":"🧀"}],"version":1},"meat_on_bone":{"id":"meat_on_bone","name":"Meat on Bone","keywords":["good","food","drumstick"],"skins":[{"unified":"1f356","native":"🍖"}],"version":1},"poultry_leg":{"id":"poultry_leg","name":"Poultry Leg","keywords":["food","meat","drumstick","bird","chicken","turkey"],"skins":[{"unified":"1f357","native":"🍗"}],"version":1},"cut_of_meat":{"id":"cut_of_meat","name":"Cut of Meat","keywords":["food","cow","chop","lambchop","porkchop"],"skins":[{"unified":"1f969","native":"🥩"}],"version":5},"bacon":{"id":"bacon","name":"Bacon","keywords":["food","breakfast","pork","pig","meat","brunch"],"skins":[{"unified":"1f953","native":"🥓"}],"version":3},"hamburger":{"id":"hamburger","name":"Hamburger","keywords":["meat","fast","food","beef","cheeseburger","mcdonalds","burger","king"],"skins":[{"unified":"1f354","native":"🍔"}],"version":1},"fries":{"id":"fries","name":"French Fries","keywords":["chips","snack","fast","food","potato"],"skins":[{"unified":"1f35f","native":"🍟"}],"version":1},"pizza":{"id":"pizza","name":"Pizza","keywords":["food","party","italy"],"skins":[{"unified":"1f355","native":"🍕"}],"version":1},"hotdog":{"id":"hotdog","name":"Hot Dog","keywords":["hotdog","food","frankfurter","america"],"skins":[{"unified":"1f32d","native":"🌭"}],"version":1},"sandwich":{"id":"sandwich","name":"Sandwich","keywords":["food","lunch","bread","toast","bakery"],"skins":[{"unified":"1f96a","native":"🥪"}],"version":5},"taco":{"id":"taco","name":"Taco","keywords":["food","mexican"],"skins":[{"unified":"1f32e","native":"🌮"}],"version":1},"burrito":{"id":"burrito","name":"Burrito","keywords":["food","mexican"],"skins":[{"unified":"1f32f","native":"🌯"}],"version":1},"tamale":{"id":"tamale","name":"Tamale","keywords":["food","masa"],"skins":[{"unified":"1fad4","native":"🫔"}],"version":13},"stuffed_flatbread":{"id":"stuffed_flatbread","name":"Stuffed Flatbread","keywords":["food","gyro","mediterranean"],"skins":[{"unified":"1f959","native":"🥙"}],"version":3},"falafel":{"id":"falafel","name":"Falafel","keywords":["food","mediterranean"],"skins":[{"unified":"1f9c6","native":"🧆"}],"version":12},"egg":{"id":"egg","name":"Egg","keywords":["food","chicken","breakfast"],"skins":[{"unified":"1f95a","native":"🥚"}],"version":3},"fried_egg":{"id":"fried_egg","name":"Cooking","keywords":["fried","egg","food","breakfast","kitchen","skillet"],"skins":[{"unified":"1f373","native":"🍳"}],"version":1},"shallow_pan_of_food":{"id":"shallow_pan_of_food","name":"Shallow Pan of Food","keywords":["cooking","casserole","paella","skillet"],"skins":[{"unified":"1f958","native":"🥘"}],"version":3},"stew":{"id":"stew","name":"Pot of Food","keywords":["stew","meat","soup","hot"],"skins":[{"unified":"1f372","native":"🍲"}],"version":1},"fondue":{"id":"fondue","name":"Fondue","keywords":["cheese","pot","food"],"skins":[{"unified":"1fad5","native":"🫕"}],"version":13},"bowl_with_spoon":{"id":"bowl_with_spoon","name":"Bowl with Spoon","keywords":["food","breakfast","cereal","oatmeal","porridge"],"skins":[{"unified":"1f963","native":"🥣"}],"version":5},"green_salad":{"id":"green_salad","name":"Green Salad","keywords":["food","healthy","lettuce","vegetable"],"skins":[{"unified":"1f957","native":"🥗"}],"version":3},"popcorn":{"id":"popcorn","name":"Popcorn","keywords":["food","movie","theater","films","snack","drama"],"skins":[{"unified":"1f37f","native":"🍿"}],"version":1},"butter":{"id":"butter","name":"Butter","keywords":["food","cook"],"skins":[{"unified":"1f9c8","native":"🧈"}],"version":12},"salt":{"id":"salt","name":"Salt","keywords":["condiment","shaker"],"skins":[{"unified":"1f9c2","native":"🧂"}],"version":11},"canned_food":{"id":"canned_food","name":"Canned Food","keywords":["soup","tomatoes"],"skins":[{"unified":"1f96b","native":"🥫"}],"version":5},"bento":{"id":"bento","name":"Bento Box","keywords":["food","japanese","lunch"],"skins":[{"unified":"1f371","native":"🍱"}],"version":1},"rice_cracker":{"id":"rice_cracker","name":"Rice Cracker","keywords":["food","japanese","snack"],"skins":[{"unified":"1f358","native":"🍘"}],"version":1},"rice_ball":{"id":"rice_ball","name":"Rice Ball","keywords":["food","japanese"],"skins":[{"unified":"1f359","native":"🍙"}],"version":1},"rice":{"id":"rice","name":"Cooked Rice","keywords":["food","asian"],"skins":[{"unified":"1f35a","native":"🍚"}],"version":1},"curry":{"id":"curry","name":"Curry Rice","keywords":["food","spicy","hot","indian"],"skins":[{"unified":"1f35b","native":"🍛"}],"version":1},"ramen":{"id":"ramen","name":"Steaming Bowl","keywords":["ramen","food","japanese","noodle","chopsticks"],"skins":[{"unified":"1f35c","native":"🍜"}],"version":1},"spaghetti":{"id":"spaghetti","name":"Spaghetti","keywords":["food","italian","pasta","noodle"],"skins":[{"unified":"1f35d","native":"🍝"}],"version":1},"sweet_potato":{"id":"sweet_potato","name":"Roasted Sweet Potato","keywords":["food","nature","plant"],"skins":[{"unified":"1f360","native":"🍠"}],"version":1},"oden":{"id":"oden","name":"Oden","keywords":["food","japanese"],"skins":[{"unified":"1f362","native":"🍢"}],"version":1},"sushi":{"id":"sushi","name":"Sushi","keywords":["food","fish","japanese","rice"],"skins":[{"unified":"1f363","native":"🍣"}],"version":1},"fried_shrimp":{"id":"fried_shrimp","name":"Fried Shrimp","keywords":["food","animal","appetizer","summer"],"skins":[{"unified":"1f364","native":"🍤"}],"version":1},"fish_cake":{"id":"fish_cake","name":"Fish Cake with Swirl","keywords":["food","japan","sea","beach","narutomaki","pink","kamaboko","surimi","ramen"],"skins":[{"unified":"1f365","native":"🍥"}],"version":1},"moon_cake":{"id":"moon_cake","name":"Moon Cake","keywords":["food","autumn","dessert"],"skins":[{"unified":"1f96e","native":"🥮"}],"version":11},"dango":{"id":"dango","name":"Dango","keywords":["food","dessert","sweet","japanese","barbecue","meat"],"skins":[{"unified":"1f361","native":"🍡"}],"version":1},"dumpling":{"id":"dumpling","name":"Dumpling","keywords":["food","empanada","pierogi","potsticker","gyoza"],"skins":[{"unified":"1f95f","native":"🥟"}],"version":5},"fortune_cookie":{"id":"fortune_cookie","name":"Fortune Cookie","keywords":["food","prophecy","dessert"],"skins":[{"unified":"1f960","native":"🥠"}],"version":5},"takeout_box":{"id":"takeout_box","name":"Takeout Box","keywords":["food","leftovers"],"skins":[{"unified":"1f961","native":"🥡"}],"version":5},"crab":{"id":"crab","name":"Crab","keywords":["animal","crustacean"],"skins":[{"unified":"1f980","native":"🦀"}],"version":1},"lobster":{"id":"lobster","name":"Lobster","keywords":["animal","nature","bisque","claws","seafood"],"skins":[{"unified":"1f99e","native":"🦞"}],"version":11},"shrimp":{"id":"shrimp","name":"Shrimp","keywords":["animal","ocean","nature","seafood"],"skins":[{"unified":"1f990","native":"🦐"}],"version":3},"squid":{"id":"squid","name":"Squid","keywords":["animal","nature","ocean","sea"],"skins":[{"unified":"1f991","native":"🦑"}],"version":3},"oyster":{"id":"oyster","name":"Oyster","keywords":["food"],"skins":[{"unified":"1f9aa","native":"🦪"}],"version":12},"icecream":{"id":"icecream","name":"Soft Ice Cream","keywords":["icecream","food","hot","dessert","summer"],"skins":[{"unified":"1f366","native":"🍦"}],"version":1},"shaved_ice":{"id":"shaved_ice","name":"Shaved Ice","keywords":["hot","dessert","summer"],"skins":[{"unified":"1f367","native":"🍧"}],"version":1},"ice_cream":{"id":"ice_cream","name":"Ice Cream","keywords":["food","hot","dessert"],"skins":[{"unified":"1f368","native":"🍨"}],"version":1},"doughnut":{"id":"doughnut","name":"Doughnut","keywords":["food","dessert","snack","sweet","donut"],"skins":[{"unified":"1f369","native":"🍩"}],"version":1},"cookie":{"id":"cookie","name":"Cookie","keywords":["food","snack","oreo","chocolate","sweet","dessert"],"skins":[{"unified":"1f36a","native":"🍪"}],"version":1},"birthday":{"id":"birthday","name":"Birthday Cake","keywords":["food","dessert"],"skins":[{"unified":"1f382","native":"🎂"}],"version":1},"cake":{"id":"cake","name":"Shortcake","keywords":["cake","food","dessert"],"skins":[{"unified":"1f370","native":"🍰"}],"version":1},"cupcake":{"id":"cupcake","name":"Cupcake","keywords":["food","dessert","bakery","sweet"],"skins":[{"unified":"1f9c1","native":"🧁"}],"version":11},"pie":{"id":"pie","name":"Pie","keywords":["food","dessert","pastry"],"skins":[{"unified":"1f967","native":"🥧"}],"version":5},"chocolate_bar":{"id":"chocolate_bar","name":"Chocolate Bar","keywords":["food","snack","dessert","sweet"],"skins":[{"unified":"1f36b","native":"🍫"}],"version":1},"candy":{"id":"candy","name":"Candy","keywords":["snack","dessert","sweet","lolly"],"skins":[{"unified":"1f36c","native":"🍬"}],"version":1},"lollipop":{"id":"lollipop","name":"Lollipop","keywords":["food","snack","candy","sweet"],"skins":[{"unified":"1f36d","native":"🍭"}],"version":1},"custard":{"id":"custard","name":"Custard","keywords":["dessert","food"],"skins":[{"unified":"1f36e","native":"🍮"}],"version":1},"honey_pot":{"id":"honey_pot","name":"Honey Pot","keywords":["bees","sweet","kitchen"],"skins":[{"unified":"1f36f","native":"🍯"}],"version":1},"baby_bottle":{"id":"baby_bottle","name":"Baby Bottle","keywords":["food","container","milk"],"skins":[{"unified":"1f37c","native":"🍼"}],"version":1},"glass_of_milk":{"id":"glass_of_milk","name":"Glass of Milk","keywords":["beverage","drink","cow"],"skins":[{"unified":"1f95b","native":"🥛"}],"version":3},"coffee":{"id":"coffee","name":"Hot Beverage","keywords":["coffee","caffeine","latte","espresso","mug"],"skins":[{"unified":"2615","native":"☕"}],"version":1},"teapot":{"id":"teapot","name":"Teapot","keywords":["drink","hot"],"skins":[{"unified":"1fad6","native":"🫖"}],"version":13},"tea":{"id":"tea","name":"Teacup Without Handle","keywords":["tea","drink","bowl","breakfast","green","british"],"skins":[{"unified":"1f375","native":"🍵"}],"version":1},"sake":{"id":"sake","name":"Sake","keywords":["wine","drink","drunk","beverage","japanese","alcohol","booze"],"skins":[{"unified":"1f376","native":"🍶"}],"version":1},"champagne":{"id":"champagne","name":"Bottle with Popping Cork","keywords":["champagne","drink","wine","celebration"],"skins":[{"unified":"1f37e","native":"🍾"}],"version":1},"wine_glass":{"id":"wine_glass","name":"Wine Glass","keywords":["drink","beverage","drunk","alcohol","booze"],"skins":[{"unified":"1f377","native":"🍷"}],"version":1},"cocktail":{"id":"cocktail","name":"Cocktail Glass","keywords":["drink","drunk","alcohol","beverage","booze","mojito"],"skins":[{"unified":"1f378","native":"🍸"}],"version":1},"tropical_drink":{"id":"tropical_drink","name":"Tropical Drink","keywords":["beverage","cocktail","summer","beach","alcohol","booze","mojito"],"skins":[{"unified":"1f379","native":"🍹"}],"version":1},"beer":{"id":"beer","name":"Beer Mug","keywords":["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],"skins":[{"unified":"1f37a","native":"🍺"}],"version":1},"beers":{"id":"beers","name":"Clinking Beer Mugs","keywords":["beers","relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],"skins":[{"unified":"1f37b","native":"🍻"}],"version":1},"clinking_glasses":{"id":"clinking_glasses","name":"Clinking Glasses","keywords":["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],"skins":[{"unified":"1f942","native":"🥂"}],"version":3},"tumbler_glass":{"id":"tumbler_glass","name":"Tumbler Glass","keywords":["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","shot"],"skins":[{"unified":"1f943","native":"🥃"}],"version":3},"pouring_liquid":{"id":"pouring_liquid","name":"Pouring Liquid","keywords":["cup","water"],"skins":[{"unified":"1fad7","native":"🫗"}],"version":14},"cup_with_straw":{"id":"cup_with_straw","name":"Cup with Straw","keywords":["drink","soda"],"skins":[{"unified":"1f964","native":"🥤"}],"version":5},"bubble_tea":{"id":"bubble_tea","name":"Bubble Tea","keywords":["taiwan","boba","milk","straw"],"skins":[{"unified":"1f9cb","native":"🧋"}],"version":13},"beverage_box":{"id":"beverage_box","name":"Beverage Box","keywords":["drink"],"skins":[{"unified":"1f9c3","native":"🧃"}],"version":12},"mate_drink":{"id":"mate_drink","name":"Mate","keywords":["drink","tea","beverage"],"skins":[{"unified":"1f9c9","native":"🧉"}],"version":12},"ice_cube":{"id":"ice_cube","name":"Ice","keywords":["cube","water","cold"],"skins":[{"unified":"1f9ca","native":"🧊"}],"version":12},"chopsticks":{"id":"chopsticks","name":"Chopsticks","keywords":["food"],"skins":[{"unified":"1f962","native":"🥢"}],"version":5},"knife_fork_plate":{"id":"knife_fork_plate","name":"Fork and Knife with Plate","keywords":["food","eat","meal","lunch","dinner","restaurant"],"skins":[{"unified":"1f37d-fe0f","native":"🍽️"}],"version":1},"fork_and_knife":{"id":"fork_and_knife","name":"Fork and Knife","keywords":["cutlery","kitchen"],"skins":[{"unified":"1f374","native":"🍴"}],"version":1},"spoon":{"id":"spoon","name":"Spoon","keywords":["cutlery","kitchen","tableware"],"skins":[{"unified":"1f944","native":"🥄"}],"version":3},"hocho":{"id":"hocho","name":"Hocho","keywords":["knife","kitchen","blade","cutlery","weapon"],"skins":[{"unified":"1f52a","native":"🔪"}],"version":1},"jar":{"id":"jar","name":"Jar","keywords":["container","sauce"],"skins":[{"unified":"1fad9","native":"🫙"}],"version":14},"amphora":{"id":"amphora","name":"Amphora","keywords":["vase","jar"],"skins":[{"unified":"1f3fa","native":"🏺"}],"version":1},"earth_africa":{"id":"earth_africa","name":"Earth Globe Europe-Africa","keywords":["africa","showing","europe","world","international"],"skins":[{"unified":"1f30d","native":"🌍"}],"version":1},"earth_americas":{"id":"earth_americas","name":"Earth Globe Americas","keywords":["showing","world","USA","international"],"skins":[{"unified":"1f30e","native":"🌎"}],"version":1},"earth_asia":{"id":"earth_asia","name":"Earth Globe Asia-Australia","keywords":["asia","showing","australia","world","east","international"],"skins":[{"unified":"1f30f","native":"🌏"}],"version":1},"globe_with_meridians":{"id":"globe_with_meridians","name":"Globe with Meridians","keywords":["earth","international","world","internet","interweb","i18n"],"skins":[{"unified":"1f310","native":"🌐"}],"version":1},"world_map":{"id":"world_map","name":"World Map","keywords":["location","direction"],"skins":[{"unified":"1f5fa-fe0f","native":"🗺️"}],"version":1},"japan":{"id":"japan","name":"Map of Japan","keywords":["nation","country","japanese","asia"],"skins":[{"unified":"1f5fe","native":"🗾"}],"version":1},"compass":{"id":"compass","name":"Compass","keywords":["magnetic","navigation","orienteering"],"skins":[{"unified":"1f9ed","native":"🧭"}],"version":11},"snow_capped_mountain":{"id":"snow_capped_mountain","name":"Snow-Capped Mountain","keywords":["snow","capped","photo","nature","environment","winter","cold"],"skins":[{"unified":"1f3d4-fe0f","native":"🏔️"}],"version":1},"mountain":{"id":"mountain","name":"Mountain","keywords":["photo","nature","environment"],"skins":[{"unified":"26f0-fe0f","native":"⛰️"}],"version":1},"volcano":{"id":"volcano","name":"Volcano","keywords":["photo","nature","disaster"],"skins":[{"unified":"1f30b","native":"🌋"}],"version":1},"mount_fuji":{"id":"mount_fuji","name":"Mount Fuji","keywords":["photo","mountain","nature","japanese"],"skins":[{"unified":"1f5fb","native":"🗻"}],"version":1},"camping":{"id":"camping","name":"Camping","keywords":["photo","outdoors","tent"],"skins":[{"unified":"1f3d5-fe0f","native":"🏕️"}],"version":1},"beach_with_umbrella":{"id":"beach_with_umbrella","name":"Beach with Umbrella","keywords":["weather","summer","sunny","sand","mojito"],"skins":[{"unified":"1f3d6-fe0f","native":"🏖️"}],"version":1},"desert":{"id":"desert","name":"Desert","keywords":["photo","warm","saharah"],"skins":[{"unified":"1f3dc-fe0f","native":"🏜️"}],"version":1},"desert_island":{"id":"desert_island","name":"Desert Island","keywords":["photo","tropical","mojito"],"skins":[{"unified":"1f3dd-fe0f","native":"🏝️"}],"version":1},"national_park":{"id":"national_park","name":"National Park","keywords":["photo","environment","nature"],"skins":[{"unified":"1f3de-fe0f","native":"🏞️"}],"version":1},"stadium":{"id":"stadium","name":"Stadium","keywords":["photo","place","sports","concert","venue"],"skins":[{"unified":"1f3df-fe0f","native":"🏟️"}],"version":1},"classical_building":{"id":"classical_building","name":"Classical Building","keywords":["art","culture","history"],"skins":[{"unified":"1f3db-fe0f","native":"🏛️"}],"version":1},"building_construction":{"id":"building_construction","name":"Building Construction","keywords":["wip","working","progress"],"skins":[{"unified":"1f3d7-fe0f","native":"🏗️"}],"version":1},"bricks":{"id":"bricks","name":"Brick","keywords":["bricks"],"skins":[{"unified":"1f9f1","native":"🧱"}],"version":11},"rock":{"id":"rock","name":"Rock","keywords":["stone"],"skins":[{"unified":"1faa8","native":"🪨"}],"version":13},"wood":{"id":"wood","name":"Wood","keywords":["nature","timber","trunk"],"skins":[{"unified":"1fab5","native":"🪵"}],"version":13},"hut":{"id":"hut","name":"Hut","keywords":["house","structure"],"skins":[{"unified":"1f6d6","native":"🛖"}],"version":13},"house_buildings":{"id":"house_buildings","name":"Houses","keywords":["house","buildings","photo"],"skins":[{"unified":"1f3d8-fe0f","native":"🏘️"}],"version":1},"derelict_house_building":{"id":"derelict_house_building","name":"Derelict House","keywords":["building","abandon","evict","broken"],"skins":[{"unified":"1f3da-fe0f","native":"🏚️"}],"version":1},"house":{"id":"house","name":"House","keywords":["building","home"],"skins":[{"unified":"1f3e0","native":"🏠"}],"version":1},"house_with_garden":{"id":"house_with_garden","name":"House with Garden","keywords":["home","plant","nature"],"skins":[{"unified":"1f3e1","native":"🏡"}],"version":1},"office":{"id":"office","name":"Office Building","keywords":["bureau","work"],"skins":[{"unified":"1f3e2","native":"🏢"}],"version":1},"post_office":{"id":"post_office","name":"Japanese Post Office","keywords":["building","envelope","communication"],"skins":[{"unified":"1f3e3","native":"🏣"}],"version":1},"european_post_office":{"id":"european_post_office","name":"Post Office","keywords":["european","building","email"],"skins":[{"unified":"1f3e4","native":"🏤"}],"version":1},"hospital":{"id":"hospital","name":"Hospital","keywords":["building","health","surgery","doctor"],"skins":[{"unified":"1f3e5","native":"🏥"}],"version":1},"bank":{"id":"bank","name":"Bank","keywords":["building","money","sales","cash","business","enterprise"],"skins":[{"unified":"1f3e6","native":"🏦"}],"version":1},"hotel":{"id":"hotel","name":"Hotel","keywords":["building","accomodation","checkin"],"skins":[{"unified":"1f3e8","native":"🏨"}],"version":1},"love_hotel":{"id":"love_hotel","name":"Love Hotel","keywords":["like","affection","dating"],"skins":[{"unified":"1f3e9","native":"🏩"}],"version":1},"convenience_store":{"id":"convenience_store","name":"Convenience Store","keywords":["building","shopping","groceries"],"skins":[{"unified":"1f3ea","native":"🏪"}],"version":1},"school":{"id":"school","name":"School","keywords":["building","student","education","learn","teach"],"skins":[{"unified":"1f3eb","native":"🏫"}],"version":1},"department_store":{"id":"department_store","name":"Department Store","keywords":["building","shopping","mall"],"skins":[{"unified":"1f3ec","native":"🏬"}],"version":1},"factory":{"id":"factory","name":"Factory","keywords":["building","industry","pollution","smoke"],"skins":[{"unified":"1f3ed","native":"🏭"}],"version":1},"japanese_castle":{"id":"japanese_castle","name":"Japanese Castle","keywords":["photo","building"],"skins":[{"unified":"1f3ef","native":"🏯"}],"version":1},"european_castle":{"id":"european_castle","name":"Castle","keywords":["european","building","royalty","history"],"skins":[{"unified":"1f3f0","native":"🏰"}],"version":1},"wedding":{"id":"wedding","name":"Wedding","keywords":["love","like","affection","couple","marriage","bride","groom"],"skins":[{"unified":"1f492","native":"💒"}],"version":1},"tokyo_tower":{"id":"tokyo_tower","name":"Tokyo Tower","keywords":["photo","japanese"],"skins":[{"unified":"1f5fc","native":"🗼"}],"version":1},"statue_of_liberty":{"id":"statue_of_liberty","name":"Statue of Liberty","keywords":["american","newyork"],"skins":[{"unified":"1f5fd","native":"🗽"}],"version":1},"church":{"id":"church","name":"Church","keywords":["building","religion","christ"],"skins":[{"unified":"26ea","native":"⛪"}],"version":1},"mosque":{"id":"mosque","name":"Mosque","keywords":["islam","worship","minaret"],"skins":[{"unified":"1f54c","native":"🕌"}],"version":1},"hindu_temple":{"id":"hindu_temple","name":"Hindu Temple","keywords":["religion"],"skins":[{"unified":"1f6d5","native":"🛕"}],"version":12},"synagogue":{"id":"synagogue","name":"Synagogue","keywords":["judaism","worship","temple","jewish"],"skins":[{"unified":"1f54d","native":"🕍"}],"version":1},"shinto_shrine":{"id":"shinto_shrine","name":"Shinto Shrine","keywords":["temple","japan","kyoto"],"skins":[{"unified":"26e9-fe0f","native":"⛩️"}],"version":1},"kaaba":{"id":"kaaba","name":"Kaaba","keywords":["mecca","mosque","islam"],"skins":[{"unified":"1f54b","native":"🕋"}],"version":1},"fountain":{"id":"fountain","name":"Fountain","keywords":["photo","summer","water","fresh"],"skins":[{"unified":"26f2","native":"⛲"}],"version":1},"tent":{"id":"tent","name":"Tent","keywords":["photo","camping","outdoors"],"skins":[{"unified":"26fa","native":"⛺"}],"version":1},"foggy":{"id":"foggy","name":"Foggy","keywords":["photo","mountain"],"skins":[{"unified":"1f301","native":"🌁"}],"version":1},"night_with_stars":{"id":"night_with_stars","name":"Night with Stars","keywords":["evening","city","downtown"],"skins":[{"unified":"1f303","native":"🌃"}],"version":1},"cityscape":{"id":"cityscape","name":"Cityscape","keywords":["photo","night","life","urban"],"skins":[{"unified":"1f3d9-fe0f","native":"🏙️"}],"version":1},"sunrise_over_mountains":{"id":"sunrise_over_mountains","name":"Sunrise over Mountains","keywords":["view","vacation","photo"],"skins":[{"unified":"1f304","native":"🌄"}],"version":1},"sunrise":{"id":"sunrise","name":"Sunrise","keywords":["morning","view","vacation","photo"],"skins":[{"unified":"1f305","native":"🌅"}],"version":1},"city_sunset":{"id":"city_sunset","name":"Cityscape at Dusk","keywords":["city","sunset","photo","evening","sky","buildings"],"skins":[{"unified":"1f306","native":"🌆"}],"version":1},"city_sunrise":{"id":"city_sunrise","name":"Sunset","keywords":["city","sunrise","photo","good","morning","dawn"],"skins":[{"unified":"1f307","native":"🌇"}],"version":1},"bridge_at_night":{"id":"bridge_at_night","name":"Bridge at Night","keywords":["photo","sanfrancisco"],"skins":[{"unified":"1f309","native":"🌉"}],"version":1},"hotsprings":{"id":"hotsprings","name":"Hot Springs","keywords":["hotsprings","bath","warm","relax"],"skins":[{"unified":"2668-fe0f","native":"♨️"}],"version":1},"carousel_horse":{"id":"carousel_horse","name":"Carousel Horse","keywords":["photo","carnival"],"skins":[{"unified":"1f3a0","native":"🎠"}],"version":1},"playground_slide":{"id":"playground_slide","name":"Playground Slide","keywords":["fun","park"],"skins":[{"unified":"1f6dd","native":"🛝"}],"version":14},"ferris_wheel":{"id":"ferris_wheel","name":"Ferris Wheel","keywords":["photo","carnival","londoneye"],"skins":[{"unified":"1f3a1","native":"🎡"}],"version":1},"roller_coaster":{"id":"roller_coaster","name":"Roller Coaster","keywords":["carnival","playground","photo","fun"],"skins":[{"unified":"1f3a2","native":"🎢"}],"version":1},"barber":{"id":"barber","name":"Barber Pole","keywords":["hair","salon","style"],"skins":[{"unified":"1f488","native":"💈"}],"version":1},"circus_tent":{"id":"circus_tent","name":"Circus Tent","keywords":["festival","carnival","party"],"skins":[{"unified":"1f3aa","native":"🎪"}],"version":1},"steam_locomotive":{"id":"steam_locomotive","name":"Locomotive","keywords":["steam","transportation","vehicle","train"],"skins":[{"unified":"1f682","native":"🚂"}],"version":1},"railway_car":{"id":"railway_car","name":"Railway Car","keywords":["transportation","vehicle"],"skins":[{"unified":"1f683","native":"🚃"}],"version":1},"bullettrain_side":{"id":"bullettrain_side","name":"High-Speed Train","keywords":["bullettrain","side","high","speed","transportation","vehicle"],"skins":[{"unified":"1f684","native":"🚄"}],"version":1},"bullettrain_front":{"id":"bullettrain_front","name":"Bullet Train","keywords":["bullettrain","front","transportation","vehicle","speed","fast","public","travel"],"skins":[{"unified":"1f685","native":"🚅"}],"version":1},"train2":{"id":"train2","name":"Train","keywords":["train2","transportation","vehicle"],"skins":[{"unified":"1f686","native":"🚆"}],"version":1},"metro":{"id":"metro","name":"Metro","keywords":["transportation","blue","square","mrt","underground","tube"],"skins":[{"unified":"1f687","native":"🚇"}],"version":1},"light_rail":{"id":"light_rail","name":"Light Rail","keywords":["transportation","vehicle"],"skins":[{"unified":"1f688","native":"🚈"}],"version":1},"station":{"id":"station","name":"Station","keywords":["transportation","vehicle","public"],"skins":[{"unified":"1f689","native":"🚉"}],"version":1},"tram":{"id":"tram","name":"Tram","keywords":["transportation","vehicle"],"skins":[{"unified":"1f68a","native":"🚊"}],"version":1},"monorail":{"id":"monorail","name":"Monorail","keywords":["transportation","vehicle"],"skins":[{"unified":"1f69d","native":"🚝"}],"version":1},"mountain_railway":{"id":"mountain_railway","name":"Mountain Railway","keywords":["transportation","vehicle"],"skins":[{"unified":"1f69e","native":"🚞"}],"version":1},"train":{"id":"train","name":"Tram Car","keywords":["train","transportation","vehicle","carriage","public","travel"],"skins":[{"unified":"1f68b","native":"🚋"}],"version":1},"bus":{"id":"bus","name":"Bus","keywords":["car","vehicle","transportation"],"skins":[{"unified":"1f68c","native":"🚌"}],"version":1},"oncoming_bus":{"id":"oncoming_bus","name":"Oncoming Bus","keywords":["vehicle","transportation"],"skins":[{"unified":"1f68d","native":"🚍"}],"version":1},"trolleybus":{"id":"trolleybus","name":"Trolleybus","keywords":["bart","transportation","vehicle"],"skins":[{"unified":"1f68e","native":"🚎"}],"version":1},"minibus":{"id":"minibus","name":"Minibus","keywords":["vehicle","car","transportation"],"skins":[{"unified":"1f690","native":"🚐"}],"version":1},"ambulance":{"id":"ambulance","name":"Ambulance","keywords":["health","911","hospital"],"skins":[{"unified":"1f691","native":"🚑"}],"version":1},"fire_engine":{"id":"fire_engine","name":"Fire Engine","keywords":["transportation","cars","vehicle"],"skins":[{"unified":"1f692","native":"🚒"}],"version":1},"police_car":{"id":"police_car","name":"Police Car","keywords":["vehicle","cars","transportation","law","legal","enforcement"],"skins":[{"unified":"1f693","native":"🚓"}],"version":1},"oncoming_police_car":{"id":"oncoming_police_car","name":"Oncoming Police Car","keywords":["vehicle","law","legal","enforcement","911"],"skins":[{"unified":"1f694","native":"🚔"}],"version":1},"taxi":{"id":"taxi","name":"Taxi","keywords":["uber","vehicle","cars","transportation"],"skins":[{"unified":"1f695","native":"🚕"}],"version":1},"oncoming_taxi":{"id":"oncoming_taxi","name":"Oncoming Taxi","keywords":["vehicle","cars","uber"],"skins":[{"unified":"1f696","native":"🚖"}],"version":1},"car":{"id":"car","name":"Automobile","keywords":["car","red","transportation","vehicle"],"skins":[{"unified":"1f697","native":"🚗"}],"version":1},"oncoming_automobile":{"id":"oncoming_automobile","name":"Oncoming Automobile","keywords":["car","vehicle","transportation"],"skins":[{"unified":"1f698","native":"🚘"}],"version":1},"blue_car":{"id":"blue_car","name":"Recreational Vehicle","keywords":["blue","car","sport","utility","transportation"],"skins":[{"unified":"1f699","native":"🚙"}],"version":1},"pickup_truck":{"id":"pickup_truck","name":"Pickup Truck","keywords":["car","transportation"],"skins":[{"unified":"1f6fb","native":"🛻"}],"version":13},"truck":{"id":"truck","name":"Delivery Truck","keywords":["cars","transportation"],"skins":[{"unified":"1f69a","native":"🚚"}],"version":1},"articulated_lorry":{"id":"articulated_lorry","name":"Articulated Lorry","keywords":["vehicle","cars","transportation","express"],"skins":[{"unified":"1f69b","native":"🚛"}],"version":1},"tractor":{"id":"tractor","name":"Tractor","keywords":["vehicle","car","farming","agriculture"],"skins":[{"unified":"1f69c","native":"🚜"}],"version":1},"racing_car":{"id":"racing_car","name":"Racing Car","keywords":["sports","race","fast","formula","f1"],"skins":[{"unified":"1f3ce-fe0f","native":"🏎️"}],"version":1},"racing_motorcycle":{"id":"racing_motorcycle","name":"Motorcycle","keywords":["racing","race","sports","fast"],"skins":[{"unified":"1f3cd-fe0f","native":"🏍️"}],"version":1},"motor_scooter":{"id":"motor_scooter","name":"Motor Scooter","keywords":["vehicle","vespa","sasha"],"skins":[{"unified":"1f6f5","native":"🛵"}],"version":3},"manual_wheelchair":{"id":"manual_wheelchair","name":"Manual Wheelchair","keywords":["accessibility"],"skins":[{"unified":"1f9bd","native":"🦽"}],"version":12},"motorized_wheelchair":{"id":"motorized_wheelchair","name":"Motorized Wheelchair","keywords":["accessibility"],"skins":[{"unified":"1f9bc","native":"🦼"}],"version":12},"auto_rickshaw":{"id":"auto_rickshaw","name":"Auto Rickshaw","keywords":["move","transportation"],"skins":[{"unified":"1f6fa","native":"🛺"}],"version":12},"bike":{"id":"bike","name":"Bicycle","keywords":["bike","sports","exercise","hipster"],"skins":[{"unified":"1f6b2","native":"🚲"}],"version":1},"scooter":{"id":"scooter","name":"Scooter","keywords":["kick","vehicle","razor"],"skins":[{"unified":"1f6f4","native":"🛴"}],"version":3},"skateboard":{"id":"skateboard","name":"Skateboard","keywords":["board"],"skins":[{"unified":"1f6f9","native":"🛹"}],"version":11},"roller_skate":{"id":"roller_skate","name":"Roller Skate","keywords":["footwear","sports"],"skins":[{"unified":"1f6fc","native":"🛼"}],"version":13},"busstop":{"id":"busstop","name":"Bus Stop","keywords":["busstop","transportation","wait"],"skins":[{"unified":"1f68f","native":"🚏"}],"version":1},"motorway":{"id":"motorway","name":"Motorway","keywords":["road","cupertino","interstate","highway"],"skins":[{"unified":"1f6e3-fe0f","native":"🛣️"}],"version":1},"railway_track":{"id":"railway_track","name":"Railway Track","keywords":["train","transportation"],"skins":[{"unified":"1f6e4-fe0f","native":"🛤️"}],"version":1},"oil_drum":{"id":"oil_drum","name":"Oil Drum","keywords":["barrell"],"skins":[{"unified":"1f6e2-fe0f","native":"🛢️"}],"version":1},"fuelpump":{"id":"fuelpump","name":"Fuel Pump","keywords":["fuelpump","gas","station","petroleum"],"skins":[{"unified":"26fd","native":"⛽"}],"version":1},"wheel":{"id":"wheel","name":"Wheel","keywords":["car","transport"],"skins":[{"unified":"1f6de","native":"🛞"}],"version":14},"rotating_light":{"id":"rotating_light","name":"Police Car Light","keywords":["rotating","ambulance","911","emergency","alert","error","pinged","law","legal"],"skins":[{"unified":"1f6a8","native":"🚨"}],"version":1},"traffic_light":{"id":"traffic_light","name":"Horizontal Traffic Light","keywords":["transportation","signal"],"skins":[{"unified":"1f6a5","native":"🚥"}],"version":1},"vertical_traffic_light":{"id":"vertical_traffic_light","name":"Vertical Traffic Light","keywords":["transportation","driving"],"skins":[{"unified":"1f6a6","native":"🚦"}],"version":1},"octagonal_sign":{"id":"octagonal_sign","name":"Stop Sign","keywords":["octagonal"],"skins":[{"unified":"1f6d1","native":"🛑"}],"version":3},"construction":{"id":"construction","name":"Construction","keywords":["wip","progress","caution","warning"],"skins":[{"unified":"1f6a7","native":"🚧"}],"version":1},"anchor":{"id":"anchor","name":"Anchor","keywords":["ship","ferry","sea","boat"],"skins":[{"unified":"2693","native":"⚓"}],"version":1},"ring_buoy":{"id":"ring_buoy","name":"Ring Buoy","keywords":["life","saver","preserver"],"skins":[{"unified":"1f6df","native":"🛟"}],"version":14},"boat":{"id":"boat","name":"Sailboat","keywords":["boat","ship","summer","transportation","water","sailing"],"skins":[{"unified":"26f5","native":"⛵"}],"version":1},"canoe":{"id":"canoe","name":"Canoe","keywords":["boat","paddle","water","ship"],"skins":[{"unified":"1f6f6","native":"🛶"}],"version":3},"speedboat":{"id":"speedboat","name":"Speedboat","keywords":["ship","transportation","vehicle","summer"],"skins":[{"unified":"1f6a4","native":"🚤"}],"version":1},"passenger_ship":{"id":"passenger_ship","name":"Passenger Ship","keywords":["yacht","cruise","ferry"],"skins":[{"unified":"1f6f3-fe0f","native":"🛳️"}],"version":1},"ferry":{"id":"ferry","name":"Ferry","keywords":["boat","ship","yacht"],"skins":[{"unified":"26f4-fe0f","native":"⛴️"}],"version":1},"motor_boat":{"id":"motor_boat","name":"Motor Boat","keywords":["ship"],"skins":[{"unified":"1f6e5-fe0f","native":"🛥️"}],"version":1},"ship":{"id":"ship","name":"Ship","keywords":["transportation","titanic","deploy"],"skins":[{"unified":"1f6a2","native":"🚢"}],"version":1},"airplane":{"id":"airplane","name":"Airplane","keywords":["vehicle","transportation","flight","fly"],"skins":[{"unified":"2708-fe0f","native":"✈️"}],"version":1},"small_airplane":{"id":"small_airplane","name":"Small Airplane","keywords":["flight","transportation","fly","vehicle"],"skins":[{"unified":"1f6e9-fe0f","native":"🛩️"}],"version":1},"airplane_departure":{"id":"airplane_departure","name":"Airplane Departure","keywords":["airport","flight","landing"],"skins":[{"unified":"1f6eb","native":"🛫"}],"version":1},"airplane_arriving":{"id":"airplane_arriving","name":"Airplane Arrival","keywords":["arriving","airport","flight","boarding"],"skins":[{"unified":"1f6ec","native":"🛬"}],"version":1},"parachute":{"id":"parachute","name":"Parachute","keywords":["fly","glide"],"skins":[{"unified":"1fa82","native":"🪂"}],"version":12},"seat":{"id":"seat","name":"Seat","keywords":["sit","airplane","transport","bus","flight","fly"],"skins":[{"unified":"1f4ba","native":"💺"}],"version":1},"helicopter":{"id":"helicopter","name":"Helicopter","keywords":["transportation","vehicle","fly"],"skins":[{"unified":"1f681","native":"🚁"}],"version":1},"suspension_railway":{"id":"suspension_railway","name":"Suspension Railway","keywords":["vehicle","transportation"],"skins":[{"unified":"1f69f","native":"🚟"}],"version":1},"mountain_cableway":{"id":"mountain_cableway","name":"Mountain Cableway","keywords":["transportation","vehicle","ski"],"skins":[{"unified":"1f6a0","native":"🚠"}],"version":1},"aerial_tramway":{"id":"aerial_tramway","name":"Aerial Tramway","keywords":["transportation","vehicle","ski"],"skins":[{"unified":"1f6a1","native":"🚡"}],"version":1},"satellite":{"id":"satellite","name":"Satellite","keywords":["communication","gps","orbit","spaceflight","NASA","ISS"],"skins":[{"unified":"1f6f0-fe0f","native":"🛰️"}],"version":1},"rocket":{"id":"rocket","name":"Rocket","keywords":["launch","ship","staffmode","NASA","outer","space","fly"],"skins":[{"unified":"1f680","native":"🚀"}],"version":1},"flying_saucer":{"id":"flying_saucer","name":"Flying Saucer","keywords":["transportation","vehicle","ufo"],"skins":[{"unified":"1f6f8","native":"🛸"}],"version":5},"bellhop_bell":{"id":"bellhop_bell","name":"Bellhop Bell","keywords":["service"],"skins":[{"unified":"1f6ce-fe0f","native":"🛎️"}],"version":1},"luggage":{"id":"luggage","name":"Luggage","keywords":["packing","travel"],"skins":[{"unified":"1f9f3","native":"🧳"}],"version":11},"hourglass":{"id":"hourglass","name":"Hourglass","keywords":["done","time","clock","oldschool","limit","exam","quiz","test"],"skins":[{"unified":"231b","native":"⌛"}],"version":1},"hourglass_flowing_sand":{"id":"hourglass_flowing_sand","name":"Hourglass Not Done","keywords":["flowing","sand","oldschool","time","countdown"],"skins":[{"unified":"23f3","native":"⏳"}],"version":1},"watch":{"id":"watch","name":"Watch","keywords":["time","accessories"],"skins":[{"unified":"231a","native":"⌚"}],"version":1},"alarm_clock":{"id":"alarm_clock","name":"Alarm Clock","keywords":["time","wake"],"skins":[{"unified":"23f0","native":"⏰"}],"version":1},"stopwatch":{"id":"stopwatch","name":"Stopwatch","keywords":["time","deadline"],"skins":[{"unified":"23f1-fe0f","native":"⏱️"}],"version":1},"timer_clock":{"id":"timer_clock","name":"Timer Clock","keywords":["alarm"],"skins":[{"unified":"23f2-fe0f","native":"⏲️"}],"version":1},"mantelpiece_clock":{"id":"mantelpiece_clock","name":"Mantelpiece Clock","keywords":["time"],"skins":[{"unified":"1f570-fe0f","native":"🕰️"}],"version":1},"clock12":{"id":"clock12","name":"Twelve O’clock","keywords":["clock12","o","clock","12","00:00","0000","12:00","1200","time","noon","midnight","midday","late","early","schedule"],"skins":[{"unified":"1f55b","native":"🕛"}],"version":1},"clock1230":{"id":"clock1230","name":"Twelve-Thirty","keywords":["clock1230","twelve","thirty","00:30","0030","12:30","1230","time","late","early","schedule"],"skins":[{"unified":"1f567","native":"🕧"}],"version":1},"clock1":{"id":"clock1","name":"One O’clock","keywords":["clock1","o","clock","1","1:00","100","13:00","1300","time","late","early","schedule"],"skins":[{"unified":"1f550","native":"🕐"}],"version":1},"clock130":{"id":"clock130","name":"One-Thirty","keywords":["clock130","one","thirty","1:30","130","13:30","1330","time","late","early","schedule"],"skins":[{"unified":"1f55c","native":"🕜"}],"version":1},"clock2":{"id":"clock2","name":"Two O’clock","keywords":["clock2","o","clock","2","2:00","200","14:00","1400","time","late","early","schedule"],"skins":[{"unified":"1f551","native":"🕑"}],"version":1},"clock230":{"id":"clock230","name":"Two-Thirty","keywords":["clock230","two","thirty","2:30","230","14:30","1430","time","late","early","schedule"],"skins":[{"unified":"1f55d","native":"🕝"}],"version":1},"clock3":{"id":"clock3","name":"Three O’clock","keywords":["clock3","o","clock","3","3:00","300","15:00","1500","time","late","early","schedule"],"skins":[{"unified":"1f552","native":"🕒"}],"version":1},"clock330":{"id":"clock330","name":"Three-Thirty","keywords":["clock330","three","thirty","3:30","330","15:30","1530","time","late","early","schedule"],"skins":[{"unified":"1f55e","native":"🕞"}],"version":1},"clock4":{"id":"clock4","name":"Four O’clock","keywords":["clock4","o","clock","4","4:00","400","16:00","1600","time","late","early","schedule"],"skins":[{"unified":"1f553","native":"🕓"}],"version":1},"clock430":{"id":"clock430","name":"Four-Thirty","keywords":["clock430","four","thirty","4:30","430","16:30","1630","time","late","early","schedule"],"skins":[{"unified":"1f55f","native":"🕟"}],"version":1},"clock5":{"id":"clock5","name":"Five O’clock","keywords":["clock5","o","clock","5","5:00","500","17:00","1700","time","late","early","schedule"],"skins":[{"unified":"1f554","native":"🕔"}],"version":1},"clock530":{"id":"clock530","name":"Five-Thirty","keywords":["clock530","five","thirty","5:30","530","17:30","1730","time","late","early","schedule"],"skins":[{"unified":"1f560","native":"🕠"}],"version":1},"clock6":{"id":"clock6","name":"Six O’clock","keywords":["clock6","o","clock","6","6:00","600","18:00","1800","time","late","early","schedule","dawn","dusk"],"skins":[{"unified":"1f555","native":"🕕"}],"version":1},"clock630":{"id":"clock630","name":"Six-Thirty","keywords":["clock630","six","thirty","6:30","630","18:30","1830","time","late","early","schedule"],"skins":[{"unified":"1f561","native":"🕡"}],"version":1},"clock7":{"id":"clock7","name":"Seven O’clock","keywords":["clock7","o","clock","7","7:00","700","19:00","1900","time","late","early","schedule"],"skins":[{"unified":"1f556","native":"🕖"}],"version":1},"clock730":{"id":"clock730","name":"Seven-Thirty","keywords":["clock730","seven","thirty","7:30","730","19:30","1930","time","late","early","schedule"],"skins":[{"unified":"1f562","native":"🕢"}],"version":1},"clock8":{"id":"clock8","name":"Eight O’clock","keywords":["clock8","o","clock","8","8:00","800","20:00","2000","time","late","early","schedule"],"skins":[{"unified":"1f557","native":"🕗"}],"version":1},"clock830":{"id":"clock830","name":"Eight-Thirty","keywords":["clock830","eight","thirty","8:30","830","20:30","2030","time","late","early","schedule"],"skins":[{"unified":"1f563","native":"🕣"}],"version":1},"clock9":{"id":"clock9","name":"Nine O’clock","keywords":["clock9","o","clock","9","9:00","900","21:00","2100","time","late","early","schedule"],"skins":[{"unified":"1f558","native":"🕘"}],"version":1},"clock930":{"id":"clock930","name":"Nine-Thirty","keywords":["clock930","nine","thirty","9:30","930","21:30","2130","time","late","early","schedule"],"skins":[{"unified":"1f564","native":"🕤"}],"version":1},"clock10":{"id":"clock10","name":"Ten O’clock","keywords":["clock10","o","clock","10","10:00","1000","22:00","2200","time","late","early","schedule"],"skins":[{"unified":"1f559","native":"🕙"}],"version":1},"clock1030":{"id":"clock1030","name":"Ten-Thirty","keywords":["clock1030","ten","thirty","10:30","1030","22:30","2230","time","late","early","schedule"],"skins":[{"unified":"1f565","native":"🕥"}],"version":1},"clock11":{"id":"clock11","name":"Eleven O’clock","keywords":["clock11","o","clock","11","11:00","1100","23:00","2300","time","late","early","schedule"],"skins":[{"unified":"1f55a","native":"🕚"}],"version":1},"clock1130":{"id":"clock1130","name":"Eleven-Thirty","keywords":["clock1130","eleven","thirty","11:30","1130","23:30","2330","time","late","early","schedule"],"skins":[{"unified":"1f566","native":"🕦"}],"version":1},"new_moon":{"id":"new_moon","name":"New Moon","keywords":["nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f311","native":"🌑"}],"version":1},"waxing_crescent_moon":{"id":"waxing_crescent_moon","name":"Waxing Crescent Moon","keywords":["nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f312","native":"🌒"}],"version":1},"first_quarter_moon":{"id":"first_quarter_moon","name":"First Quarter Moon","keywords":["nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f313","native":"🌓"}],"version":1},"moon":{"id":"moon","name":"Waxing Gibbous Moon","keywords":["nature","night","sky","gray","twilight","planet","space","evening","sleep"],"skins":[{"unified":"1f314","native":"🌔"}],"version":1},"full_moon":{"id":"full_moon","name":"Full Moon","keywords":["nature","yellow","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f315","native":"🌕"}],"version":1},"waning_gibbous_moon":{"id":"waning_gibbous_moon","name":"Waning Gibbous Moon","keywords":["nature","twilight","planet","space","night","evening","sleep","waxing"],"skins":[{"unified":"1f316","native":"🌖"}],"version":1},"last_quarter_moon":{"id":"last_quarter_moon","name":"Last Quarter Moon","keywords":["nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f317","native":"🌗"}],"version":1},"waning_crescent_moon":{"id":"waning_crescent_moon","name":"Waning Crescent Moon","keywords":["nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f318","native":"🌘"}],"version":1},"crescent_moon":{"id":"crescent_moon","name":"Crescent Moon","keywords":["night","sleep","sky","evening","magic"],"skins":[{"unified":"1f319","native":"🌙"}],"version":1},"new_moon_with_face":{"id":"new_moon_with_face","name":"New Moon Face","keywords":["with","nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f31a","native":"🌚"}],"version":1},"first_quarter_moon_with_face":{"id":"first_quarter_moon_with_face","name":"First Quarter Moon Face","keywords":["with","nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f31b","native":"🌛"}],"version":1},"last_quarter_moon_with_face":{"id":"last_quarter_moon_with_face","name":"Last Quarter Moon Face","keywords":["with","nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f31c","native":"🌜"}],"version":1},"thermometer":{"id":"thermometer","name":"Thermometer","keywords":["weather","temperature","hot","cold"],"skins":[{"unified":"1f321-fe0f","native":"🌡️"}],"version":1},"sunny":{"id":"sunny","name":"Sun","keywords":["sunny","weather","nature","brightness","summer","beach","spring"],"skins":[{"unified":"2600-fe0f","native":"☀️"}],"version":1},"full_moon_with_face":{"id":"full_moon_with_face","name":"Full Moon Face","keywords":["with","nature","twilight","planet","space","night","evening","sleep"],"skins":[{"unified":"1f31d","native":"🌝"}],"version":1},"sun_with_face":{"id":"sun_with_face","name":"Sun with Face","keywords":["nature","morning","sky"],"skins":[{"unified":"1f31e","native":"🌞"}],"version":1},"ringed_planet":{"id":"ringed_planet","name":"Ringed Planet","keywords":["outerspace"],"skins":[{"unified":"1fa90","native":"🪐"}],"version":12},"star":{"id":"star","name":"Star","keywords":["night","yellow"],"skins":[{"unified":"2b50","native":"⭐"}],"version":1},"star2":{"id":"star2","name":"Glowing Star","keywords":["star2","night","sparkle","awesome","good","magic"],"skins":[{"unified":"1f31f","native":"🌟"}],"version":1},"stars":{"id":"stars","name":"Shooting Star","keywords":["stars","night","photo"],"skins":[{"unified":"1f320","native":"🌠"}],"version":1},"milky_way":{"id":"milky_way","name":"Milky Way","keywords":["photo","space","stars"],"skins":[{"unified":"1f30c","native":"🌌"}],"version":1},"cloud":{"id":"cloud","name":"Cloud","keywords":["weather","sky"],"skins":[{"unified":"2601-fe0f","native":"☁️"}],"version":1},"partly_sunny":{"id":"partly_sunny","name":"Sun Behind Cloud","keywords":["partly","sunny","weather","nature","cloudy","morning","fall","spring"],"skins":[{"unified":"26c5","native":"⛅"}],"version":1},"thunder_cloud_and_rain":{"id":"thunder_cloud_and_rain","name":"Cloud with Lightning and Rain","keywords":["thunder","weather"],"skins":[{"unified":"26c8-fe0f","native":"⛈️"}],"version":1},"mostly_sunny":{"id":"mostly_sunny","name":"Sun Behind Small Cloud","keywords":["mostly","sunny","weather"],"skins":[{"unified":"1f324-fe0f","native":"🌤️"}],"version":1},"barely_sunny":{"id":"barely_sunny","name":"Sun Behind Large Cloud","keywords":["barely","sunny","weather"],"skins":[{"unified":"1f325-fe0f","native":"🌥️"}],"version":1},"partly_sunny_rain":{"id":"partly_sunny_rain","name":"Sun Behind Rain Cloud","keywords":["partly","sunny","weather"],"skins":[{"unified":"1f326-fe0f","native":"🌦️"}],"version":1},"rain_cloud":{"id":"rain_cloud","name":"Cloud with Rain","keywords":["weather"],"skins":[{"unified":"1f327-fe0f","native":"🌧️"}],"version":1},"snow_cloud":{"id":"snow_cloud","name":"Cloud with Snow","keywords":["weather"],"skins":[{"unified":"1f328-fe0f","native":"🌨️"}],"version":1},"lightning":{"id":"lightning","name":"Cloud with Lightning","keywords":["weather","thunder"],"skins":[{"unified":"1f329-fe0f","native":"🌩️"}],"version":1},"tornado":{"id":"tornado","name":"Tornado","keywords":["cloud","weather","cyclone","twister"],"skins":[{"unified":"1f32a-fe0f","native":"🌪️"}],"version":1},"fog":{"id":"fog","name":"Fog","keywords":["weather"],"skins":[{"unified":"1f32b-fe0f","native":"🌫️"}],"version":1},"wind_blowing_face":{"id":"wind_blowing_face","name":"Wind Face","keywords":["blowing","gust","air"],"skins":[{"unified":"1f32c-fe0f","native":"🌬️"}],"version":1},"cyclone":{"id":"cyclone","name":"Cyclone","keywords":["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],"skins":[{"unified":"1f300","native":"🌀"}],"version":1},"rainbow":{"id":"rainbow","name":"Rainbow","keywords":["nature","happy","unicorn","face","photo","sky","spring"],"skins":[{"unified":"1f308","native":"🌈"}],"version":1},"closed_umbrella":{"id":"closed_umbrella","name":"Closed Umbrella","keywords":["weather","rain","drizzle"],"skins":[{"unified":"1f302","native":"🌂"}],"version":1},"umbrella":{"id":"umbrella","name":"Umbrella","keywords":["weather","spring"],"skins":[{"unified":"2602-fe0f","native":"☂️"}],"version":1},"umbrella_with_rain_drops":{"id":"umbrella_with_rain_drops","name":"Umbrella with Rain Drops","keywords":["rainy","weather","spring"],"skins":[{"unified":"2614","native":"☔"}],"version":1},"umbrella_on_ground":{"id":"umbrella_on_ground","name":"Umbrella on Ground","keywords":["weather","summer"],"skins":[{"unified":"26f1-fe0f","native":"⛱️"}],"version":1},"zap":{"id":"zap","name":"High Voltage","keywords":["zap","thunder","weather","lightning","bolt","fast"],"skins":[{"unified":"26a1","native":"⚡"}],"version":1},"snowflake":{"id":"snowflake","name":"Snowflake","keywords":["winter","season","cold","weather","christmas","xmas"],"skins":[{"unified":"2744-fe0f","native":"❄️"}],"version":1},"snowman":{"id":"snowman","name":"Snowman","keywords":["winter","season","cold","weather","christmas","xmas","frozen"],"skins":[{"unified":"2603-fe0f","native":"☃️"}],"version":1},"snowman_without_snow":{"id":"snowman_without_snow","name":"Snowman Without Snow","keywords":["winter","season","cold","weather","christmas","xmas","frozen"],"skins":[{"unified":"26c4","native":"⛄"}],"version":1},"comet":{"id":"comet","name":"Comet","keywords":["space"],"skins":[{"unified":"2604-fe0f","native":"☄️"}],"version":1},"fire":{"id":"fire","name":"Fire","keywords":["hot","cook","flame"],"skins":[{"unified":"1f525","native":"🔥"}],"version":1},"droplet":{"id":"droplet","name":"Droplet","keywords":["water","drip","faucet","spring"],"skins":[{"unified":"1f4a7","native":"💧"}],"version":1},"ocean":{"id":"ocean","name":"Water Wave","keywords":["ocean","sea","nature","tsunami","disaster"],"skins":[{"unified":"1f30a","native":"🌊"}],"version":1},"jack_o_lantern":{"id":"jack_o_lantern","name":"Jack-O-Lantern","keywords":["jack","o","lantern","halloween","light","pumpkin","creepy","fall"],"skins":[{"unified":"1f383","native":"🎃"}],"version":1},"christmas_tree":{"id":"christmas_tree","name":"Christmas Tree","keywords":["festival","vacation","december","xmas","celebration"],"skins":[{"unified":"1f384","native":"🎄"}],"version":1},"fireworks":{"id":"fireworks","name":"Fireworks","keywords":["photo","festival","carnival","congratulations"],"skins":[{"unified":"1f386","native":"🎆"}],"version":1},"sparkler":{"id":"sparkler","name":"Sparkler","keywords":["stars","night","shine"],"skins":[{"unified":"1f387","native":"🎇"}],"version":1},"firecracker":{"id":"firecracker","name":"Firecracker","keywords":["dynamite","boom","explode","explosion","explosive"],"skins":[{"unified":"1f9e8","native":"🧨"}],"version":11},"sparkles":{"id":"sparkles","name":"Sparkles","keywords":["stars","shine","shiny","cool","awesome","good","magic"],"skins":[{"unified":"2728","native":"✨"}],"version":1},"balloon":{"id":"balloon","name":"Balloon","keywords":["party","celebration","birthday","circus"],"skins":[{"unified":"1f388","native":"🎈"}],"version":1},"tada":{"id":"tada","name":"Party Popper","keywords":["tada","congratulations","birthday","magic","circus","celebration"],"skins":[{"unified":"1f389","native":"🎉"}],"version":1},"confetti_ball":{"id":"confetti_ball","name":"Confetti Ball","keywords":["festival","party","birthday","circus"],"skins":[{"unified":"1f38a","native":"🎊"}],"version":1},"tanabata_tree":{"id":"tanabata_tree","name":"Tanabata Tree","keywords":["plant","nature","branch","summer","bamboo","wish","star","festival","tanzaku"],"skins":[{"unified":"1f38b","native":"🎋"}],"version":1},"bamboo":{"id":"bamboo","name":"Pine Decoration","keywords":["bamboo","japanese","plant","nature","vegetable","panda","new","years"],"skins":[{"unified":"1f38d","native":"🎍"}],"version":1},"dolls":{"id":"dolls","name":"Japanese Dolls","keywords":["toy","kimono"],"skins":[{"unified":"1f38e","native":"🎎"}],"version":1},"flags":{"id":"flags","name":"Carp Streamer","keywords":["flags","fish","japanese","koinobori","banner"],"skins":[{"unified":"1f38f","native":"🎏"}],"version":1},"wind_chime":{"id":"wind_chime","name":"Wind Chime","keywords":["nature","ding","spring","bell"],"skins":[{"unified":"1f390","native":"🎐"}],"version":1},"rice_scene":{"id":"rice_scene","name":"Moon Viewing Ceremony","keywords":["rice","scene","photo","japan","asia","tsukimi"],"skins":[{"unified":"1f391","native":"🎑"}],"version":1},"red_envelope":{"id":"red_envelope","name":"Red Envelope","keywords":["gift"],"skins":[{"unified":"1f9e7","native":"🧧"}],"version":11},"ribbon":{"id":"ribbon","name":"Ribbon","keywords":["decoration","pink","girl","bowtie"],"skins":[{"unified":"1f380","native":"🎀"}],"version":1},"gift":{"id":"gift","name":"Wrapped Gift","keywords":["present","birthday","christmas","xmas"],"skins":[{"unified":"1f381","native":"🎁"}],"version":1},"reminder_ribbon":{"id":"reminder_ribbon","name":"Reminder Ribbon","keywords":["sports","cause","support","awareness"],"skins":[{"unified":"1f397-fe0f","native":"🎗️"}],"version":1},"admission_tickets":{"id":"admission_tickets","name":"Admission Tickets","keywords":["sports","concert","entrance"],"skins":[{"unified":"1f39f-fe0f","native":"🎟️"}],"version":1},"ticket":{"id":"ticket","name":"Ticket","keywords":["event","concert","pass"],"skins":[{"unified":"1f3ab","native":"🎫"}],"version":1},"medal":{"id":"medal","name":"Military Medal","keywords":["award","winning","army"],"skins":[{"unified":"1f396-fe0f","native":"🎖️"}],"version":1},"trophy":{"id":"trophy","name":"Trophy","keywords":["win","award","contest","place","ftw","ceremony"],"skins":[{"unified":"1f3c6","native":"🏆"}],"version":1},"sports_medal":{"id":"sports_medal","name":"Sports Medal","keywords":["award","winning"],"skins":[{"unified":"1f3c5","native":"🏅"}],"version":1},"first_place_medal":{"id":"first_place_medal","name":"1st Place Medal","keywords":["first","award","winning"],"skins":[{"unified":"1f947","native":"🥇"}],"version":3},"second_place_medal":{"id":"second_place_medal","name":"2nd Place Medal","keywords":["second","award"],"skins":[{"unified":"1f948","native":"🥈"}],"version":3},"third_place_medal":{"id":"third_place_medal","name":"3rd Place Medal","keywords":["third","award"],"skins":[{"unified":"1f949","native":"🥉"}],"version":3},"soccer":{"id":"soccer","name":"Soccer Ball","keywords":["sports","football"],"skins":[{"unified":"26bd","native":"⚽"}],"version":1},"baseball":{"id":"baseball","name":"Baseball","keywords":["sports","balls"],"skins":[{"unified":"26be","native":"⚾"}],"version":1},"softball":{"id":"softball","name":"Softball","keywords":["sports","balls"],"skins":[{"unified":"1f94e","native":"🥎"}],"version":11},"basketball":{"id":"basketball","name":"Basketball","keywords":["sports","balls","NBA"],"skins":[{"unified":"1f3c0","native":"🏀"}],"version":1},"volleyball":{"id":"volleyball","name":"Volleyball","keywords":["sports","balls"],"skins":[{"unified":"1f3d0","native":"🏐"}],"version":1},"football":{"id":"football","name":"American Football","keywords":["sports","balls","NFL"],"skins":[{"unified":"1f3c8","native":"🏈"}],"version":1},"rugby_football":{"id":"rugby_football","name":"Rugby Football","keywords":["sports","team"],"skins":[{"unified":"1f3c9","native":"🏉"}],"version":1},"tennis":{"id":"tennis","name":"Tennis","keywords":["sports","balls","green"],"skins":[{"unified":"1f3be","native":"🎾"}],"version":1},"flying_disc":{"id":"flying_disc","name":"Flying Disc","keywords":["sports","frisbee","ultimate"],"skins":[{"unified":"1f94f","native":"🥏"}],"version":11},"bowling":{"id":"bowling","name":"Bowling","keywords":["sports","fun","play"],"skins":[{"unified":"1f3b3","native":"🎳"}],"version":1},"cricket_bat_and_ball":{"id":"cricket_bat_and_ball","name":"Cricket Game","keywords":["bat","and","ball","sports"],"skins":[{"unified":"1f3cf","native":"🏏"}],"version":1},"field_hockey_stick_and_ball":{"id":"field_hockey_stick_and_ball","name":"Field Hockey","keywords":["stick","and","ball","sports"],"skins":[{"unified":"1f3d1","native":"🏑"}],"version":1},"ice_hockey_stick_and_puck":{"id":"ice_hockey_stick_and_puck","name":"Ice Hockey","keywords":["stick","and","puck","sports"],"skins":[{"unified":"1f3d2","native":"🏒"}],"version":1},"lacrosse":{"id":"lacrosse","name":"Lacrosse","keywords":["sports","ball","stick"],"skins":[{"unified":"1f94d","native":"🥍"}],"version":11},"table_tennis_paddle_and_ball":{"id":"table_tennis_paddle_and_ball","name":"Ping Pong","keywords":["table","tennis","paddle","and","ball","sports","pingpong"],"skins":[{"unified":"1f3d3","native":"🏓"}],"version":1},"badminton_racquet_and_shuttlecock":{"id":"badminton_racquet_and_shuttlecock","name":"Badminton","keywords":["racquet","and","shuttlecock","sports"],"skins":[{"unified":"1f3f8","native":"🏸"}],"version":1},"boxing_glove":{"id":"boxing_glove","name":"Boxing Glove","keywords":["sports","fighting"],"skins":[{"unified":"1f94a","native":"🥊"}],"version":3},"martial_arts_uniform":{"id":"martial_arts_uniform","name":"Martial Arts Uniform","keywords":["judo","karate","taekwondo"],"skins":[{"unified":"1f94b","native":"🥋"}],"version":3},"goal_net":{"id":"goal_net","name":"Goal Net","keywords":["sports"],"skins":[{"unified":"1f945","native":"🥅"}],"version":3},"golf":{"id":"golf","name":"Flag in Hole","keywords":["golf","sports","business","summer"],"skins":[{"unified":"26f3","native":"⛳"}],"version":1},"ice_skate":{"id":"ice_skate","name":"Ice Skate","keywords":["sports"],"skins":[{"unified":"26f8-fe0f","native":"⛸️"}],"version":1},"fishing_pole_and_fish":{"id":"fishing_pole_and_fish","name":"Fishing Pole","keywords":["and","fish","food","hobby","summer"],"skins":[{"unified":"1f3a3","native":"🎣"}],"version":1},"diving_mask":{"id":"diving_mask","name":"Diving Mask","keywords":["sport","ocean"],"skins":[{"unified":"1f93f","native":"🤿"}],"version":12},"running_shirt_with_sash":{"id":"running_shirt_with_sash","name":"Running Shirt","keywords":["with","sash","play","pageant"],"skins":[{"unified":"1f3bd","native":"🎽"}],"version":1},"ski":{"id":"ski","name":"Skis","keywords":["ski","sports","winter","cold","snow"],"skins":[{"unified":"1f3bf","native":"🎿"}],"version":1},"sled":{"id":"sled","name":"Sled","keywords":["sleigh","luge","toboggan"],"skins":[{"unified":"1f6f7","native":"🛷"}],"version":5},"curling_stone":{"id":"curling_stone","name":"Curling Stone","keywords":["sports"],"skins":[{"unified":"1f94c","native":"🥌"}],"version":5},"dart":{"id":"dart","name":"Bullseye","keywords":["dart","direct","hit","game","play","bar","target"],"skins":[{"unified":"1f3af","native":"🎯"}],"version":1},"yo-yo":{"id":"yo-yo","name":"Yo-Yo","keywords":["yo","toy"],"skins":[{"unified":"1fa80","native":"🪀"}],"version":12},"kite":{"id":"kite","name":"Kite","keywords":["wind","fly"],"skins":[{"unified":"1fa81","native":"🪁"}],"version":12},"gun":{"id":"gun","name":"Pistol","keywords":["gun","violence","weapon","revolver"],"skins":[{"unified":"1f52b","native":"🔫"}],"version":1},"8ball":{"id":"8ball","name":"Billiards","keywords":["8ball","pool","8","ball","hobby","game","luck","magic"],"skins":[{"unified":"1f3b1","native":"🎱"}],"version":1},"crystal_ball":{"id":"crystal_ball","name":"Crystal Ball","keywords":["disco","party","magic","circus","fortune","teller"],"skins":[{"unified":"1f52e","native":"🔮"}],"version":1},"magic_wand":{"id":"magic_wand","name":"Magic Wand","keywords":["supernature","power"],"skins":[{"unified":"1fa84","native":"🪄"}],"version":13},"video_game":{"id":"video_game","name":"Video Game","keywords":["play","console","PS4","controller"],"skins":[{"unified":"1f3ae","native":"🎮"}],"version":1},"joystick":{"id":"joystick","name":"Joystick","keywords":["game","play"],"skins":[{"unified":"1f579-fe0f","native":"🕹️"}],"version":1},"slot_machine":{"id":"slot_machine","name":"Slot Machine","keywords":["bet","gamble","vegas","fruit","luck","casino"],"skins":[{"unified":"1f3b0","native":"🎰"}],"version":1},"game_die":{"id":"game_die","name":"Game Die","keywords":["dice","random","tabletop","play","luck"],"skins":[{"unified":"1f3b2","native":"🎲"}],"version":1},"jigsaw":{"id":"jigsaw","name":"Puzzle Piece","keywords":["jigsaw","interlocking"],"skins":[{"unified":"1f9e9","native":"🧩"}],"version":11},"teddy_bear":{"id":"teddy_bear","name":"Teddy Bear","keywords":["plush","stuffed"],"skins":[{"unified":"1f9f8","native":"🧸"}],"version":11},"pinata":{"id":"pinata","name":"Pinata","keywords":["mexico","candy","celebration"],"skins":[{"unified":"1fa85","native":"🪅"}],"version":13},"mirror_ball":{"id":"mirror_ball","name":"Mirror Ball","keywords":["disco","dance","party"],"skins":[{"unified":"1faa9","native":"🪩"}],"version":14},"nesting_dolls":{"id":"nesting_dolls","name":"Nesting Dolls","keywords":["matryoshka","toy"],"skins":[{"unified":"1fa86","native":"🪆"}],"version":13},"spades":{"id":"spades","name":"Spade Suit","keywords":["spades","poker","cards","suits","magic"],"skins":[{"unified":"2660-fe0f","native":"♠️"}],"version":1},"hearts":{"id":"hearts","name":"Heart Suit","keywords":["hearts","poker","cards","magic","suits"],"skins":[{"unified":"2665-fe0f","native":"♥️"}],"version":1},"diamonds":{"id":"diamonds","name":"Diamond Suit","keywords":["diamonds","poker","cards","magic","suits"],"skins":[{"unified":"2666-fe0f","native":"♦️"}],"version":1},"clubs":{"id":"clubs","name":"Club Suit","keywords":["clubs","poker","cards","magic","suits"],"skins":[{"unified":"2663-fe0f","native":"♣️"}],"version":1},"chess_pawn":{"id":"chess_pawn","name":"Chess Pawn","keywords":["expendable"],"skins":[{"unified":"265f-fe0f","native":"♟️"}],"version":11},"black_joker":{"id":"black_joker","name":"Joker","keywords":["black","poker","cards","game","play","magic"],"skins":[{"unified":"1f0cf","native":"🃏"}],"version":1},"mahjong":{"id":"mahjong","name":"Mahjong Red Dragon","keywords":["game","play","chinese","kanji"],"skins":[{"unified":"1f004","native":"🀄"}],"version":1},"flower_playing_cards":{"id":"flower_playing_cards","name":"Flower Playing Cards","keywords":["game","sunset","red"],"skins":[{"unified":"1f3b4","native":"🎴"}],"version":1},"performing_arts":{"id":"performing_arts","name":"Performing Arts","keywords":["acting","theater","drama"],"skins":[{"unified":"1f3ad","native":"🎭"}],"version":1},"frame_with_picture":{"id":"frame_with_picture","name":"Framed Picture","keywords":["frame","with","photography"],"skins":[{"unified":"1f5bc-fe0f","native":"🖼️"}],"version":1},"art":{"id":"art","name":"Artist Palette","keywords":["art","design","paint","draw","colors"],"skins":[{"unified":"1f3a8","native":"🎨"}],"version":1},"thread":{"id":"thread","name":"Thread","keywords":["needle","sewing","spool","string"],"skins":[{"unified":"1f9f5","native":"🧵"}],"version":11},"sewing_needle":{"id":"sewing_needle","name":"Sewing Needle","keywords":["stitches"],"skins":[{"unified":"1faa1","native":"🪡"}],"version":13},"yarn":{"id":"yarn","name":"Yarn","keywords":["ball","crochet","knit"],"skins":[{"unified":"1f9f6","native":"🧶"}],"version":11},"knot":{"id":"knot","name":"Knot","keywords":["rope","scout"],"skins":[{"unified":"1faa2","native":"🪢"}],"version":13},"eyeglasses":{"id":"eyeglasses","name":"Glasses","keywords":["eyeglasses","fashion","accessories","eyesight","nerdy","dork","geek"],"skins":[{"unified":"1f453","native":"👓"}],"version":1},"dark_sunglasses":{"id":"dark_sunglasses","name":"Sunglasses","keywords":["dark","face","cool","accessories"],"skins":[{"unified":"1f576-fe0f","native":"🕶️"}],"version":1},"goggles":{"id":"goggles","name":"Goggles","keywords":["eyes","protection","safety"],"skins":[{"unified":"1f97d","native":"🥽"}],"version":11},"lab_coat":{"id":"lab_coat","name":"Lab Coat","keywords":["doctor","experiment","scientist","chemist"],"skins":[{"unified":"1f97c","native":"🥼"}],"version":11},"safety_vest":{"id":"safety_vest","name":"Safety Vest","keywords":["protection"],"skins":[{"unified":"1f9ba","native":"🦺"}],"version":12},"necktie":{"id":"necktie","name":"Necktie","keywords":["shirt","suitup","formal","fashion","cloth","business"],"skins":[{"unified":"1f454","native":"👔"}],"version":1},"shirt":{"id":"shirt","name":"T-Shirt","keywords":["shirt","tshirt","t","fashion","cloth","casual","tee"],"skins":[{"unified":"1f455","native":"👕"}],"version":1},"jeans":{"id":"jeans","name":"Jeans","keywords":["fashion","shopping"],"skins":[{"unified":"1f456","native":"👖"}],"version":1},"scarf":{"id":"scarf","name":"Scarf","keywords":["neck","winter","clothes"],"skins":[{"unified":"1f9e3","native":"🧣"}],"version":5},"gloves":{"id":"gloves","name":"Gloves","keywords":["hands","winter","clothes"],"skins":[{"unified":"1f9e4","native":"🧤"}],"version":5},"coat":{"id":"coat","name":"Coat","keywords":["jacket"],"skins":[{"unified":"1f9e5","native":"🧥"}],"version":5},"socks":{"id":"socks","name":"Socks","keywords":["stockings","clothes"],"skins":[{"unified":"1f9e6","native":"🧦"}],"version":5},"dress":{"id":"dress","name":"Dress","keywords":["clothes","fashion","shopping"],"skins":[{"unified":"1f457","native":"👗"}],"version":1},"kimono":{"id":"kimono","name":"Kimono","keywords":["dress","fashion","women","female","japanese"],"skins":[{"unified":"1f458","native":"👘"}],"version":1},"sari":{"id":"sari","name":"Sari","keywords":["dress"],"skins":[{"unified":"1f97b","native":"🥻"}],"version":12},"one-piece_swimsuit":{"id":"one-piece_swimsuit","name":"One-Piece Swimsuit","keywords":["one","piece","fashion"],"skins":[{"unified":"1fa71","native":"🩱"}],"version":12},"briefs":{"id":"briefs","name":"Briefs","keywords":["clothing"],"skins":[{"unified":"1fa72","native":"🩲"}],"version":12},"shorts":{"id":"shorts","name":"Shorts","keywords":["clothing"],"skins":[{"unified":"1fa73","native":"🩳"}],"version":12},"bikini":{"id":"bikini","name":"Bikini","keywords":["swimming","female","woman","girl","fashion","beach","summer"],"skins":[{"unified":"1f459","native":"👙"}],"version":1},"womans_clothes":{"id":"womans_clothes","name":"Womans Clothes","keywords":["woman","s","fashion","shopping","bags","female"],"skins":[{"unified":"1f45a","native":"👚"}],"version":1},"folding_hand_fan":{"id":"folding_hand_fan","name":"Folding Hand Fan","keywords":["flamenco","hot"],"skins":[{"unified":"1faad","native":"🪭"}],"version":15},"purse":{"id":"purse","name":"Purse","keywords":["fashion","accessories","money","sales","shopping"],"skins":[{"unified":"1f45b","native":"👛"}],"version":1},"handbag":{"id":"handbag","name":"Handbag","keywords":["fashion","accessory","accessories","shopping"],"skins":[{"unified":"1f45c","native":"👜"}],"version":1},"pouch":{"id":"pouch","name":"Pouch","keywords":["clutch","bag","accessories","shopping"],"skins":[{"unified":"1f45d","native":"👝"}],"version":1},"shopping_bags":{"id":"shopping_bags","name":"Shopping Bags","keywords":["mall","buy","purchase"],"skins":[{"unified":"1f6cd-fe0f","native":"🛍️"}],"version":1},"school_satchel":{"id":"school_satchel","name":"Backpack","keywords":["school","satchel","student","education","bag"],"skins":[{"unified":"1f392","native":"🎒"}],"version":1},"thong_sandal":{"id":"thong_sandal","name":"Thong Sandal","keywords":["footwear","summer"],"skins":[{"unified":"1fa74","native":"🩴"}],"version":13},"mans_shoe":{"id":"mans_shoe","name":"Mans Shoe","keywords":["man","s","fashion","male"],"skins":[{"unified":"1f45e","native":"👞"}],"version":1},"athletic_shoe":{"id":"athletic_shoe","name":"Running Shoe","keywords":["athletic","shoes","sports","sneakers"],"skins":[{"unified":"1f45f","native":"👟"}],"version":1},"hiking_boot":{"id":"hiking_boot","name":"Hiking Boot","keywords":["backpacking","camping"],"skins":[{"unified":"1f97e","native":"🥾"}],"version":11},"womans_flat_shoe":{"id":"womans_flat_shoe","name":"Flat Shoe","keywords":["womans","ballet","slip","on","slipper"],"skins":[{"unified":"1f97f","native":"🥿"}],"version":11},"high_heel":{"id":"high_heel","name":"High-Heeled Shoe","keywords":["high","heel","heeled","fashion","shoes","female","pumps","stiletto"],"skins":[{"unified":"1f460","native":"👠"}],"version":1},"sandal":{"id":"sandal","name":"Womans Sandal","keywords":["woman","s","shoes","fashion","flip","flops"],"skins":[{"unified":"1f461","native":"👡"}],"version":1},"ballet_shoes":{"id":"ballet_shoes","name":"Ballet Shoes","keywords":["dance"],"skins":[{"unified":"1fa70","native":"🩰"}],"version":12},"boot":{"id":"boot","name":"Womans Boots","keywords":["boot","woman","s","shoes","fashion"],"skins":[{"unified":"1f462","native":"👢"}],"version":1},"hair_pick":{"id":"hair_pick","name":"Hair Pick","keywords":["afro","comb"],"skins":[{"unified":"1faae","native":"🪮"}],"version":15},"crown":{"id":"crown","name":"Crown","keywords":["king","kod","leader","royalty","lord"],"skins":[{"unified":"1f451","native":"👑"}],"version":1},"womans_hat":{"id":"womans_hat","name":"Womans Hat","keywords":["woman","s","fashion","accessories","female","lady","spring"],"skins":[{"unified":"1f452","native":"👒"}],"version":1},"tophat":{"id":"tophat","name":"Top Hat","keywords":["tophat","magic","gentleman","classy","circus"],"skins":[{"unified":"1f3a9","native":"🎩"}],"version":1},"mortar_board":{"id":"mortar_board","name":"Graduation Cap","keywords":["mortar","board","school","college","degree","university","hat","legal","learn","education"],"skins":[{"unified":"1f393","native":"🎓"}],"version":1},"billed_cap":{"id":"billed_cap","name":"Billed Cap","keywords":["baseball"],"skins":[{"unified":"1f9e2","native":"🧢"}],"version":5},"military_helmet":{"id":"military_helmet","name":"Military Helmet","keywords":["army","protection"],"skins":[{"unified":"1fa96","native":"🪖"}],"version":13},"helmet_with_white_cross":{"id":"helmet_with_white_cross","name":"Rescue Worker’s Helmet","keywords":["with","white","cross","worker","s","construction","build"],"skins":[{"unified":"26d1-fe0f","native":"⛑️"}],"version":1},"prayer_beads":{"id":"prayer_beads","name":"Prayer Beads","keywords":["dhikr","religious"],"skins":[{"unified":"1f4ff","native":"📿"}],"version":1},"lipstick":{"id":"lipstick","name":"Lipstick","keywords":["female","girl","fashion","woman"],"skins":[{"unified":"1f484","native":"💄"}],"version":1},"ring":{"id":"ring","name":"Ring","keywords":["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],"skins":[{"unified":"1f48d","native":"💍"}],"version":1},"gem":{"id":"gem","name":"Gem Stone","keywords":["blue","ruby","diamond","jewelry"],"skins":[{"unified":"1f48e","native":"💎"}],"version":1},"mute":{"id":"mute","name":"Muted Speaker","keywords":["mute","sound","volume","silence","quiet"],"skins":[{"unified":"1f507","native":"🔇"}],"version":1},"speaker":{"id":"speaker","name":"Speaker","keywords":["low","volume","sound","silence","broadcast"],"skins":[{"unified":"1f508","native":"🔈"}],"version":1},"sound":{"id":"sound","name":"Speaker Medium Volume","keywords":["sound","broadcast"],"skins":[{"unified":"1f509","native":"🔉"}],"version":1},"loud_sound":{"id":"loud_sound","name":"Speaker High Volume","keywords":["loud","sound","noise","noisy","broadcast"],"skins":[{"unified":"1f50a","native":"🔊"}],"version":1},"loudspeaker":{"id":"loudspeaker","name":"Loudspeaker","keywords":["volume","sound"],"skins":[{"unified":"1f4e2","native":"📢"}],"version":1},"mega":{"id":"mega","name":"Megaphone","keywords":["mega","sound","speaker","volume"],"skins":[{"unified":"1f4e3","native":"📣"}],"version":1},"postal_horn":{"id":"postal_horn","name":"Postal Horn","keywords":["instrument","music"],"skins":[{"unified":"1f4ef","native":"📯"}],"version":1},"bell":{"id":"bell","name":"Bell","keywords":["sound","notification","christmas","xmas","chime"],"skins":[{"unified":"1f514","native":"🔔"}],"version":1},"no_bell":{"id":"no_bell","name":"Bell with Slash","keywords":["no","sound","volume","mute","quiet","silent"],"skins":[{"unified":"1f515","native":"🔕"}],"version":1},"musical_score":{"id":"musical_score","name":"Musical Score","keywords":["treble","clef","compose"],"skins":[{"unified":"1f3bc","native":"🎼"}],"version":1},"musical_note":{"id":"musical_note","name":"Musical Note","keywords":["score","tone","sound"],"skins":[{"unified":"1f3b5","native":"🎵"}],"version":1},"notes":{"id":"notes","name":"Musical Notes","keywords":["music","score"],"skins":[{"unified":"1f3b6","native":"🎶"}],"version":1},"studio_microphone":{"id":"studio_microphone","name":"Studio Microphone","keywords":["sing","recording","artist","talkshow"],"skins":[{"unified":"1f399-fe0f","native":"🎙️"}],"version":1},"level_slider":{"id":"level_slider","name":"Level Slider","keywords":["scale"],"skins":[{"unified":"1f39a-fe0f","native":"🎚️"}],"version":1},"control_knobs":{"id":"control_knobs","name":"Control Knobs","keywords":["dial"],"skins":[{"unified":"1f39b-fe0f","native":"🎛️"}],"version":1},"microphone":{"id":"microphone","name":"Microphone","keywords":["sound","music","PA","sing","talkshow"],"skins":[{"unified":"1f3a4","native":"🎤"}],"version":1},"headphones":{"id":"headphones","name":"Headphone","keywords":["headphones","music","score","gadgets"],"skins":[{"unified":"1f3a7","native":"🎧"}],"version":1},"radio":{"id":"radio","name":"Radio","keywords":["communication","music","podcast","program"],"skins":[{"unified":"1f4fb","native":"📻"}],"version":1},"saxophone":{"id":"saxophone","name":"Saxophone","keywords":["music","instrument","jazz","blues"],"skins":[{"unified":"1f3b7","native":"🎷"}],"version":1},"accordion":{"id":"accordion","name":"Accordion","keywords":["music"],"skins":[{"unified":"1fa97","native":"🪗"}],"version":13},"guitar":{"id":"guitar","name":"Guitar","keywords":["music","instrument"],"skins":[{"unified":"1f3b8","native":"🎸"}],"version":1},"musical_keyboard":{"id":"musical_keyboard","name":"Musical Keyboard","keywords":["piano","instrument","compose"],"skins":[{"unified":"1f3b9","native":"🎹"}],"version":1},"trumpet":{"id":"trumpet","name":"Trumpet","keywords":["music","brass"],"skins":[{"unified":"1f3ba","native":"🎺"}],"version":1},"violin":{"id":"violin","name":"Violin","keywords":["music","instrument","orchestra","symphony"],"skins":[{"unified":"1f3bb","native":"🎻"}],"version":1},"banjo":{"id":"banjo","name":"Banjo","keywords":["music","instructment"],"skins":[{"unified":"1fa95","native":"🪕"}],"version":12},"drum_with_drumsticks":{"id":"drum_with_drumsticks","name":"Drum","keywords":["with","drumsticks","music","instrument","snare"],"skins":[{"unified":"1f941","native":"🥁"}],"version":3},"long_drum":{"id":"long_drum","name":"Long Drum","keywords":["music"],"skins":[{"unified":"1fa98","native":"🪘"}],"version":13},"maracas":{"id":"maracas","name":"Maracas","keywords":["music","instrument","percussion"],"skins":[{"unified":"1fa87","native":"🪇"}],"version":15},"flute":{"id":"flute","name":"Flute","keywords":["bamboo","music","instrument","pied","piper"],"skins":[{"unified":"1fa88","native":"🪈"}],"version":15},"iphone":{"id":"iphone","name":"Mobile Phone","keywords":["iphone","technology","apple","gadgets","dial"],"skins":[{"unified":"1f4f1","native":"📱"}],"version":1},"calling":{"id":"calling","name":"Mobile Phone with Arrow","keywords":["calling","iphone","incoming"],"skins":[{"unified":"1f4f2","native":"📲"}],"version":1},"phone":{"id":"phone","name":"Telephone","keywords":["phone","technology","communication","dial"],"skins":[{"unified":"260e-fe0f","native":"☎️"}],"version":1},"telephone_receiver":{"id":"telephone_receiver","name":"Telephone Receiver","keywords":["technology","communication","dial"],"skins":[{"unified":"1f4de","native":"📞"}],"version":1},"pager":{"id":"pager","name":"Pager","keywords":["bbcall","oldschool","90s"],"skins":[{"unified":"1f4df","native":"📟"}],"version":1},"fax":{"id":"fax","name":"Fax Machine","keywords":["communication","technology"],"skins":[{"unified":"1f4e0","native":"📠"}],"version":1},"battery":{"id":"battery","name":"Battery","keywords":["power","energy","sustain"],"skins":[{"unified":"1f50b","native":"🔋"}],"version":1},"low_battery":{"id":"low_battery","name":"Low Battery","keywords":["drained","dead"],"skins":[{"unified":"1faab","native":"🪫"}],"version":14},"electric_plug":{"id":"electric_plug","name":"Electric Plug","keywords":["charger","power"],"skins":[{"unified":"1f50c","native":"🔌"}],"version":1},"computer":{"id":"computer","name":"Laptop","keywords":["computer","technology","screen","display","monitor"],"skins":[{"unified":"1f4bb","native":"💻"}],"version":1},"desktop_computer":{"id":"desktop_computer","name":"Desktop Computer","keywords":["technology","computing","screen"],"skins":[{"unified":"1f5a5-fe0f","native":"🖥️"}],"version":1},"printer":{"id":"printer","name":"Printer","keywords":["paper","ink"],"skins":[{"unified":"1f5a8-fe0f","native":"🖨️"}],"version":1},"keyboard":{"id":"keyboard","name":"Keyboard","keywords":["technology","computer","type","input","text"],"skins":[{"unified":"2328-fe0f","native":"⌨️"}],"version":1},"three_button_mouse":{"id":"three_button_mouse","name":"Computer Mouse","keywords":["three","button","click"],"skins":[{"unified":"1f5b1-fe0f","native":"🖱️"}],"version":1},"trackball":{"id":"trackball","name":"Trackball","keywords":["technology","trackpad"],"skins":[{"unified":"1f5b2-fe0f","native":"🖲️"}],"version":1},"minidisc":{"id":"minidisc","name":"Minidisc","keywords":["computer","disk","technology","record","data","90s"],"skins":[{"unified":"1f4bd","native":"💽"}],"version":1},"floppy_disk":{"id":"floppy_disk","name":"Floppy Disk","keywords":["oldschool","technology","save","90s","80s"],"skins":[{"unified":"1f4be","native":"💾"}],"version":1},"cd":{"id":"cd","name":"Optical Disc","keywords":["cd","disk","technology","dvd","90s"],"skins":[{"unified":"1f4bf","native":"💿"}],"version":1},"dvd":{"id":"dvd","name":"Dvd","keywords":["cd","disk","disc"],"skins":[{"unified":"1f4c0","native":"📀"}],"version":1},"abacus":{"id":"abacus","name":"Abacus","keywords":["calculation"],"skins":[{"unified":"1f9ee","native":"🧮"}],"version":11},"movie_camera":{"id":"movie_camera","name":"Movie Camera","keywords":["film","record"],"skins":[{"unified":"1f3a5","native":"🎥"}],"version":1},"film_frames":{"id":"film_frames","name":"Film Frames","keywords":["movie"],"skins":[{"unified":"1f39e-fe0f","native":"🎞️"}],"version":1},"film_projector":{"id":"film_projector","name":"Film Projector","keywords":["video","tape","record","movie"],"skins":[{"unified":"1f4fd-fe0f","native":"📽️"}],"version":1},"clapper":{"id":"clapper","name":"Clapper Board","keywords":["movie","film","record"],"skins":[{"unified":"1f3ac","native":"🎬"}],"version":1},"tv":{"id":"tv","name":"Television","keywords":["tv","technology","program","oldschool","show"],"skins":[{"unified":"1f4fa","native":"📺"}],"version":1},"camera":{"id":"camera","name":"Camera","keywords":["gadgets","photography"],"skins":[{"unified":"1f4f7","native":"📷"}],"version":1},"camera_with_flash":{"id":"camera_with_flash","name":"Camera with Flash","keywords":["photography","gadgets"],"skins":[{"unified":"1f4f8","native":"📸"}],"version":1},"video_camera":{"id":"video_camera","name":"Video Camera","keywords":["film","record"],"skins":[{"unified":"1f4f9","native":"📹"}],"version":1},"vhs":{"id":"vhs","name":"Videocassette","keywords":["vhs","record","video","oldschool","90s","80s"],"skins":[{"unified":"1f4fc","native":"📼"}],"version":1},"mag":{"id":"mag","name":"Magnifying Glass Tilted Left","keywords":["mag","search","zoom","find","detective"],"skins":[{"unified":"1f50d","native":"🔍"}],"version":1},"mag_right":{"id":"mag_right","name":"Magnifying Glass Tilted Right","keywords":["mag","search","zoom","find","detective"],"skins":[{"unified":"1f50e","native":"🔎"}],"version":1},"candle":{"id":"candle","name":"Candle","keywords":["fire","wax"],"skins":[{"unified":"1f56f-fe0f","native":"🕯️"}],"version":1},"bulb":{"id":"bulb","name":"Light Bulb","keywords":["electricity","idea"],"skins":[{"unified":"1f4a1","native":"💡"}],"version":1},"flashlight":{"id":"flashlight","name":"Flashlight","keywords":["dark","camping","sight","night"],"skins":[{"unified":"1f526","native":"🔦"}],"version":1},"izakaya_lantern":{"id":"izakaya_lantern","name":"Izakaya Lantern","keywords":["red","paper","light","halloween","spooky"],"skins":[{"unified":"1f3ee","native":"🏮"}],"version":1},"diya_lamp":{"id":"diya_lamp","name":"Diya Lamp","keywords":["lighting"],"skins":[{"unified":"1fa94","native":"🪔"}],"version":12},"notebook_with_decorative_cover":{"id":"notebook_with_decorative_cover","name":"Notebook with Decorative Cover","keywords":["classroom","notes","record","paper","study"],"skins":[{"unified":"1f4d4","native":"📔"}],"version":1},"closed_book":{"id":"closed_book","name":"Closed Book","keywords":["read","library","knowledge","textbook","learn"],"skins":[{"unified":"1f4d5","native":"📕"}],"version":1},"book":{"id":"book","name":"Open Book","keywords":["read","library","knowledge","literature","learn","study"],"skins":[{"unified":"1f4d6","native":"📖"}],"version":1},"green_book":{"id":"green_book","name":"Green Book","keywords":["read","library","knowledge","study"],"skins":[{"unified":"1f4d7","native":"📗"}],"version":1},"blue_book":{"id":"blue_book","name":"Blue Book","keywords":["read","library","knowledge","learn","study"],"skins":[{"unified":"1f4d8","native":"📘"}],"version":1},"orange_book":{"id":"orange_book","name":"Orange Book","keywords":["read","library","knowledge","textbook","study"],"skins":[{"unified":"1f4d9","native":"📙"}],"version":1},"books":{"id":"books","name":"Books","keywords":["literature","library","study"],"skins":[{"unified":"1f4da","native":"📚"}],"version":1},"notebook":{"id":"notebook","name":"Notebook","keywords":["stationery","record","notes","paper","study"],"skins":[{"unified":"1f4d3","native":"📓"}],"version":1},"ledger":{"id":"ledger","name":"Ledger","keywords":["notes","paper"],"skins":[{"unified":"1f4d2","native":"📒"}],"version":1},"page_with_curl":{"id":"page_with_curl","name":"Page with Curl","keywords":["documents","office","paper"],"skins":[{"unified":"1f4c3","native":"📃"}],"version":1},"scroll":{"id":"scroll","name":"Scroll","keywords":["documents","ancient","history","paper"],"skins":[{"unified":"1f4dc","native":"📜"}],"version":1},"page_facing_up":{"id":"page_facing_up","name":"Page Facing Up","keywords":["documents","office","paper","information"],"skins":[{"unified":"1f4c4","native":"📄"}],"version":1},"newspaper":{"id":"newspaper","name":"Newspaper","keywords":["press","headline"],"skins":[{"unified":"1f4f0","native":"📰"}],"version":1},"rolled_up_newspaper":{"id":"rolled_up_newspaper","name":"Rolled-Up Newspaper","keywords":["rolled","up","press","headline"],"skins":[{"unified":"1f5de-fe0f","native":"🗞️"}],"version":1},"bookmark_tabs":{"id":"bookmark_tabs","name":"Bookmark Tabs","keywords":["favorite","save","order","tidy"],"skins":[{"unified":"1f4d1","native":"📑"}],"version":1},"bookmark":{"id":"bookmark","name":"Bookmark","keywords":["favorite","label","save"],"skins":[{"unified":"1f516","native":"🔖"}],"version":1},"label":{"id":"label","name":"Label","keywords":["sale","tag"],"skins":[{"unified":"1f3f7-fe0f","native":"🏷️"}],"version":1},"moneybag":{"id":"moneybag","name":"Money Bag","keywords":["moneybag","dollar","payment","coins","sale"],"skins":[{"unified":"1f4b0","native":"💰"}],"version":1},"coin":{"id":"coin","name":"Coin","keywords":["money","currency"],"skins":[{"unified":"1fa99","native":"🪙"}],"version":13},"yen":{"id":"yen","name":"Yen Banknote","keywords":["money","sales","japanese","dollar","currency"],"skins":[{"unified":"1f4b4","native":"💴"}],"version":1},"dollar":{"id":"dollar","name":"Dollar Banknote","keywords":["money","sales","bill","currency"],"skins":[{"unified":"1f4b5","native":"💵"}],"version":1},"euro":{"id":"euro","name":"Euro Banknote","keywords":["money","sales","dollar","currency"],"skins":[{"unified":"1f4b6","native":"💶"}],"version":1},"pound":{"id":"pound","name":"Pound Banknote","keywords":["british","sterling","money","sales","bills","uk","england","currency"],"skins":[{"unified":"1f4b7","native":"💷"}],"version":1},"money_with_wings":{"id":"money_with_wings","name":"Money with Wings","keywords":["dollar","bills","payment","sale"],"skins":[{"unified":"1f4b8","native":"💸"}],"version":1},"credit_card":{"id":"credit_card","name":"Credit Card","keywords":["money","sales","dollar","bill","payment","shopping"],"skins":[{"unified":"1f4b3","native":"💳"}],"version":1},"receipt":{"id":"receipt","name":"Receipt","keywords":["accounting","expenses"],"skins":[{"unified":"1f9fe","native":"🧾"}],"version":11},"chart":{"id":"chart","name":"Chart Increasing with Yen","keywords":["green","square","graph","presentation","stats"],"skins":[{"unified":"1f4b9","native":"💹"}],"version":1},"email":{"id":"email","name":"Envelope","keywords":["email","letter","postal","inbox","communication"],"skins":[{"unified":"2709-fe0f","native":"✉️"}],"version":1},"e-mail":{"id":"e-mail","name":"E-Mail","keywords":["e","mail","communication","inbox"],"skins":[{"unified":"1f4e7","native":"📧"}],"version":1},"incoming_envelope":{"id":"incoming_envelope","name":"Incoming Envelope","keywords":["email","inbox"],"skins":[{"unified":"1f4e8","native":"📨"}],"version":1},"envelope_with_arrow":{"id":"envelope_with_arrow","name":"Envelope with Arrow","keywords":["email","communication"],"skins":[{"unified":"1f4e9","native":"📩"}],"version":1},"outbox_tray":{"id":"outbox_tray","name":"Outbox Tray","keywords":["inbox","email"],"skins":[{"unified":"1f4e4","native":"📤"}],"version":1},"inbox_tray":{"id":"inbox_tray","name":"Inbox Tray","keywords":["email","documents"],"skins":[{"unified":"1f4e5","native":"📥"}],"version":1},"package":{"id":"package","name":"Package","keywords":["mail","gift","cardboard","box","moving"],"skins":[{"unified":"1f4e6","native":"📦"}],"version":1},"mailbox":{"id":"mailbox","name":"Closed Mailbox with Raised Flag","keywords":["email","inbox","communication"],"skins":[{"unified":"1f4eb","native":"📫"}],"version":1},"mailbox_closed":{"id":"mailbox_closed","name":"Closed Mailbox with Lowered Flag","keywords":["email","communication","inbox"],"skins":[{"unified":"1f4ea","native":"📪"}],"version":1},"mailbox_with_mail":{"id":"mailbox_with_mail","name":"Open Mailbox with Raised Flag","keywords":["mail","email","inbox","communication"],"skins":[{"unified":"1f4ec","native":"📬"}],"version":1},"mailbox_with_no_mail":{"id":"mailbox_with_no_mail","name":"Open Mailbox with Lowered Flag","keywords":["no","mail","email","inbox"],"skins":[{"unified":"1f4ed","native":"📭"}],"version":1},"postbox":{"id":"postbox","name":"Postbox","keywords":["email","letter","envelope"],"skins":[{"unified":"1f4ee","native":"📮"}],"version":1},"ballot_box_with_ballot":{"id":"ballot_box_with_ballot","name":"Ballot Box with Ballot","keywords":["election","vote"],"skins":[{"unified":"1f5f3-fe0f","native":"🗳️"}],"version":1},"pencil2":{"id":"pencil2","name":"Pencil","keywords":["pencil2","stationery","write","paper","writing","school","study"],"skins":[{"unified":"270f-fe0f","native":"✏️"}],"version":1},"black_nib":{"id":"black_nib","name":"Black Nib","keywords":["pen","stationery","writing","write"],"skins":[{"unified":"2712-fe0f","native":"✒️"}],"version":1},"lower_left_fountain_pen":{"id":"lower_left_fountain_pen","name":"Fountain Pen","keywords":["lower","left","stationery","writing","write"],"skins":[{"unified":"1f58b-fe0f","native":"🖋️"}],"version":1},"lower_left_ballpoint_pen":{"id":"lower_left_ballpoint_pen","name":"Pen","keywords":["lower","left","ballpoint","stationery","writing","write"],"skins":[{"unified":"1f58a-fe0f","native":"🖊️"}],"version":1},"lower_left_paintbrush":{"id":"lower_left_paintbrush","name":"Paintbrush","keywords":["lower","left","drawing","creativity","art"],"skins":[{"unified":"1f58c-fe0f","native":"🖌️"}],"version":1},"lower_left_crayon":{"id":"lower_left_crayon","name":"Crayon","keywords":["lower","left","drawing","creativity"],"skins":[{"unified":"1f58d-fe0f","native":"🖍️"}],"version":1},"memo":{"id":"memo","name":"Memo","keywords":["pencil","write","documents","stationery","paper","writing","legal","exam","quiz","test","study","compose"],"skins":[{"unified":"1f4dd","native":"📝"}],"version":1},"briefcase":{"id":"briefcase","name":"Briefcase","keywords":["business","documents","work","law","legal","job","career"],"skins":[{"unified":"1f4bc","native":"💼"}],"version":1},"file_folder":{"id":"file_folder","name":"File Folder","keywords":["documents","business","office"],"skins":[{"unified":"1f4c1","native":"📁"}],"version":1},"open_file_folder":{"id":"open_file_folder","name":"Open File Folder","keywords":["documents","load"],"skins":[{"unified":"1f4c2","native":"📂"}],"version":1},"card_index_dividers":{"id":"card_index_dividers","name":"Card Index Dividers","keywords":["organizing","business","stationery"],"skins":[{"unified":"1f5c2-fe0f","native":"🗂️"}],"version":1},"date":{"id":"date","name":"Calendar","keywords":["date","schedule"],"skins":[{"unified":"1f4c5","native":"📅"}],"version":1},"calendar":{"id":"calendar","name":"Tear-off Calendar","keywords":["tear","off","schedule","date","planning"],"skins":[{"unified":"1f4c6","native":"📆"}],"version":1},"spiral_note_pad":{"id":"spiral_note_pad","name":"Spiral Notepad","keywords":["note","pad","memo","stationery"],"skins":[{"unified":"1f5d2-fe0f","native":"🗒️"}],"version":1},"spiral_calendar_pad":{"id":"spiral_calendar_pad","name":"Spiral Calendar","keywords":["pad","date","schedule","planning"],"skins":[{"unified":"1f5d3-fe0f","native":"🗓️"}],"version":1},"card_index":{"id":"card_index","name":"Card Index","keywords":["business","stationery"],"skins":[{"unified":"1f4c7","native":"📇"}],"version":1},"chart_with_upwards_trend":{"id":"chart_with_upwards_trend","name":"Chart Increasing","keywords":["with","upwards","trend","graph","presentation","stats","recovery","business","economics","money","sales","good","success"],"skins":[{"unified":"1f4c8","native":"📈"}],"version":1},"chart_with_downwards_trend":{"id":"chart_with_downwards_trend","name":"Chart Decreasing","keywords":["with","downwards","trend","graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],"skins":[{"unified":"1f4c9","native":"📉"}],"version":1},"bar_chart":{"id":"bar_chart","name":"Bar Chart","keywords":["graph","presentation","stats"],"skins":[{"unified":"1f4ca","native":"📊"}],"version":1},"clipboard":{"id":"clipboard","name":"Clipboard","keywords":["stationery","documents"],"skins":[{"unified":"1f4cb","native":"📋"}],"version":1},"pushpin":{"id":"pushpin","name":"Pushpin","keywords":["stationery","mark","here"],"skins":[{"unified":"1f4cc","native":"📌"}],"version":1},"round_pushpin":{"id":"round_pushpin","name":"Round Pushpin","keywords":["stationery","location","map","here"],"skins":[{"unified":"1f4cd","native":"📍"}],"version":1},"paperclip":{"id":"paperclip","name":"Paperclip","keywords":["documents","stationery"],"skins":[{"unified":"1f4ce","native":"📎"}],"version":1},"linked_paperclips":{"id":"linked_paperclips","name":"Linked Paperclips","keywords":["documents","stationery"],"skins":[{"unified":"1f587-fe0f","native":"🖇️"}],"version":1},"straight_ruler":{"id":"straight_ruler","name":"Straight Ruler","keywords":["stationery","calculate","length","math","school","drawing","architect","sketch"],"skins":[{"unified":"1f4cf","native":"📏"}],"version":1},"triangular_ruler":{"id":"triangular_ruler","name":"Triangular Ruler","keywords":["stationery","math","architect","sketch"],"skins":[{"unified":"1f4d0","native":"📐"}],"version":1},"scissors":{"id":"scissors","name":"Scissors","keywords":["stationery","cut"],"skins":[{"unified":"2702-fe0f","native":"✂️"}],"version":1},"card_file_box":{"id":"card_file_box","name":"Card File Box","keywords":["business","stationery"],"skins":[{"unified":"1f5c3-fe0f","native":"🗃️"}],"version":1},"file_cabinet":{"id":"file_cabinet","name":"File Cabinet","keywords":["filing","organizing"],"skins":[{"unified":"1f5c4-fe0f","native":"🗄️"}],"version":1},"wastebasket":{"id":"wastebasket","name":"Wastebasket","keywords":["bin","trash","rubbish","garbage","toss"],"skins":[{"unified":"1f5d1-fe0f","native":"🗑️"}],"version":1},"lock":{"id":"lock","name":"Lock","keywords":["locked","security","password","padlock"],"skins":[{"unified":"1f512","native":"🔒"}],"version":1},"unlock":{"id":"unlock","name":"Unlocked","keywords":["unlock","privacy","security"],"skins":[{"unified":"1f513","native":"🔓"}],"version":1},"lock_with_ink_pen":{"id":"lock_with_ink_pen","name":"Locked with Pen","keywords":["lock","ink","security","secret"],"skins":[{"unified":"1f50f","native":"🔏"}],"version":1},"closed_lock_with_key":{"id":"closed_lock_with_key","name":"Locked with Key","keywords":["closed","lock","security","privacy"],"skins":[{"unified":"1f510","native":"🔐"}],"version":1},"key":{"id":"key","name":"Key","keywords":["lock","door","password"],"skins":[{"unified":"1f511","native":"🔑"}],"version":1},"old_key":{"id":"old_key","name":"Old Key","keywords":["lock","door","password"],"skins":[{"unified":"1f5dd-fe0f","native":"🗝️"}],"version":1},"hammer":{"id":"hammer","name":"Hammer","keywords":["tools","build","create"],"skins":[{"unified":"1f528","native":"🔨"}],"version":1},"axe":{"id":"axe","name":"Axe","keywords":["tool","chop","cut"],"skins":[{"unified":"1fa93","native":"🪓"}],"version":12},"pick":{"id":"pick","name":"Pick","keywords":["tools","dig"],"skins":[{"unified":"26cf-fe0f","native":"⛏️"}],"version":1},"hammer_and_pick":{"id":"hammer_and_pick","name":"Hammer and Pick","keywords":["tools","build","create"],"skins":[{"unified":"2692-fe0f","native":"⚒️"}],"version":1},"hammer_and_wrench":{"id":"hammer_and_wrench","name":"Hammer and Wrench","keywords":["tools","build","create"],"skins":[{"unified":"1f6e0-fe0f","native":"🛠️"}],"version":1},"dagger_knife":{"id":"dagger_knife","name":"Dagger","keywords":["knife","weapon"],"skins":[{"unified":"1f5e1-fe0f","native":"🗡️"}],"version":1},"crossed_swords":{"id":"crossed_swords","name":"Crossed Swords","keywords":["weapon"],"skins":[{"unified":"2694-fe0f","native":"⚔️"}],"version":1},"bomb":{"id":"bomb","name":"Bomb","keywords":["boom","explode","explosion","terrorism"],"skins":[{"unified":"1f4a3","native":"💣"}],"version":1},"boomerang":{"id":"boomerang","name":"Boomerang","keywords":["weapon"],"skins":[{"unified":"1fa83","native":"🪃"}],"version":13},"bow_and_arrow":{"id":"bow_and_arrow","name":"Bow and Arrow","keywords":["sports"],"skins":[{"unified":"1f3f9","native":"🏹"}],"version":1},"shield":{"id":"shield","name":"Shield","keywords":["protection","security"],"skins":[{"unified":"1f6e1-fe0f","native":"🛡️"}],"version":1},"carpentry_saw":{"id":"carpentry_saw","name":"Carpentry Saw","keywords":["cut","chop"],"skins":[{"unified":"1fa9a","native":"🪚"}],"version":13},"wrench":{"id":"wrench","name":"Wrench","keywords":["tools","diy","ikea","fix","maintainer"],"skins":[{"unified":"1f527","native":"🔧"}],"version":1},"screwdriver":{"id":"screwdriver","name":"Screwdriver","keywords":["tools"],"skins":[{"unified":"1fa9b","native":"🪛"}],"version":13},"nut_and_bolt":{"id":"nut_and_bolt","name":"Nut and Bolt","keywords":["handy","tools","fix"],"skins":[{"unified":"1f529","native":"🔩"}],"version":1},"gear":{"id":"gear","name":"Gear","keywords":["cog"],"skins":[{"unified":"2699-fe0f","native":"⚙️"}],"version":1},"compression":{"id":"compression","name":"Clamp","keywords":["compression","tool"],"skins":[{"unified":"1f5dc-fe0f","native":"🗜️"}],"version":1},"scales":{"id":"scales","name":"Balance Scale","keywords":["scales","law","fairness","weight"],"skins":[{"unified":"2696-fe0f","native":"⚖️"}],"version":1},"probing_cane":{"id":"probing_cane","name":"White Cane","keywords":["probing","accessibility"],"skins":[{"unified":"1f9af","native":"🦯"}],"version":12},"link":{"id":"link","name":"Link","keywords":["rings","url"],"skins":[{"unified":"1f517","native":"🔗"}],"version":1},"chains":{"id":"chains","name":"Chains","keywords":["lock","arrest"],"skins":[{"unified":"26d3-fe0f","native":"⛓️"}],"version":1},"hook":{"id":"hook","name":"Hook","keywords":["tools"],"skins":[{"unified":"1fa9d","native":"🪝"}],"version":13},"toolbox":{"id":"toolbox","name":"Toolbox","keywords":["tools","diy","fix","maintainer","mechanic"],"skins":[{"unified":"1f9f0","native":"🧰"}],"version":11},"magnet":{"id":"magnet","name":"Magnet","keywords":["attraction","magnetic"],"skins":[{"unified":"1f9f2","native":"🧲"}],"version":11},"ladder":{"id":"ladder","name":"Ladder","keywords":["tools"],"skins":[{"unified":"1fa9c","native":"🪜"}],"version":13},"alembic":{"id":"alembic","name":"Alembic","keywords":["distilling","science","experiment","chemistry"],"skins":[{"unified":"2697-fe0f","native":"⚗️"}],"version":1},"test_tube":{"id":"test_tube","name":"Test Tube","keywords":["chemistry","experiment","lab","science"],"skins":[{"unified":"1f9ea","native":"🧪"}],"version":11},"petri_dish":{"id":"petri_dish","name":"Petri Dish","keywords":["bacteria","biology","culture","lab"],"skins":[{"unified":"1f9eb","native":"🧫"}],"version":11},"dna":{"id":"dna","name":"Dna","keywords":["biologist","genetics","life"],"skins":[{"unified":"1f9ec","native":"🧬"}],"version":11},"microscope":{"id":"microscope","name":"Microscope","keywords":["laboratory","experiment","zoomin","science","study"],"skins":[{"unified":"1f52c","native":"🔬"}],"version":1},"telescope":{"id":"telescope","name":"Telescope","keywords":["stars","space","zoom","science","astronomy"],"skins":[{"unified":"1f52d","native":"🔭"}],"version":1},"satellite_antenna":{"id":"satellite_antenna","name":"Satellite Antenna","keywords":["communication","future","radio","space"],"skins":[{"unified":"1f4e1","native":"📡"}],"version":1},"syringe":{"id":"syringe","name":"Syringe","keywords":["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],"skins":[{"unified":"1f489","native":"💉"}],"version":1},"drop_of_blood":{"id":"drop_of_blood","name":"Drop of Blood","keywords":["period","hurt","harm","wound"],"skins":[{"unified":"1fa78","native":"🩸"}],"version":12},"pill":{"id":"pill","name":"Pill","keywords":["health","medicine","doctor","pharmacy","drug"],"skins":[{"unified":"1f48a","native":"💊"}],"version":1},"adhesive_bandage":{"id":"adhesive_bandage","name":"Adhesive Bandage","keywords":["heal"],"skins":[{"unified":"1fa79","native":"🩹"}],"version":12},"crutch":{"id":"crutch","name":"Crutch","keywords":["accessibility","assist"],"skins":[{"unified":"1fa7c","native":"🩼"}],"version":14},"stethoscope":{"id":"stethoscope","name":"Stethoscope","keywords":["health"],"skins":[{"unified":"1fa7a","native":"🩺"}],"version":12},"x-ray":{"id":"x-ray","name":"X-Ray","keywords":["x","ray","skeleton","medicine"],"skins":[{"unified":"1fa7b","native":"🩻"}],"version":14},"door":{"id":"door","name":"Door","keywords":["house","entry","exit"],"skins":[{"unified":"1f6aa","native":"🚪"}],"version":1},"elevator":{"id":"elevator","name":"Elevator","keywords":["lift"],"skins":[{"unified":"1f6d7","native":"🛗"}],"version":13},"mirror":{"id":"mirror","name":"Mirror","keywords":["reflection"],"skins":[{"unified":"1fa9e","native":"🪞"}],"version":13},"window":{"id":"window","name":"Window","keywords":["scenery"],"skins":[{"unified":"1fa9f","native":"🪟"}],"version":13},"bed":{"id":"bed","name":"Bed","keywords":["sleep","rest"],"skins":[{"unified":"1f6cf-fe0f","native":"🛏️"}],"version":1},"couch_and_lamp":{"id":"couch_and_lamp","name":"Couch and Lamp","keywords":["read","chill"],"skins":[{"unified":"1f6cb-fe0f","native":"🛋️"}],"version":1},"chair":{"id":"chair","name":"Chair","keywords":["sit","furniture"],"skins":[{"unified":"1fa91","native":"🪑"}],"version":12},"toilet":{"id":"toilet","name":"Toilet","keywords":["restroom","wc","washroom","bathroom","potty"],"skins":[{"unified":"1f6bd","native":"🚽"}],"version":1},"plunger":{"id":"plunger","name":"Plunger","keywords":["toilet"],"skins":[{"unified":"1faa0","native":"🪠"}],"version":13},"shower":{"id":"shower","name":"Shower","keywords":["clean","water","bathroom"],"skins":[{"unified":"1f6bf","native":"🚿"}],"version":1},"bathtub":{"id":"bathtub","name":"Bathtub","keywords":["clean","shower","bathroom"],"skins":[{"unified":"1f6c1","native":"🛁"}],"version":1},"mouse_trap":{"id":"mouse_trap","name":"Mouse Trap","keywords":["cheese"],"skins":[{"unified":"1faa4","native":"🪤"}],"version":13},"razor":{"id":"razor","name":"Razor","keywords":["cut"],"skins":[{"unified":"1fa92","native":"🪒"}],"version":12},"lotion_bottle":{"id":"lotion_bottle","name":"Lotion Bottle","keywords":["moisturizer","sunscreen"],"skins":[{"unified":"1f9f4","native":"🧴"}],"version":11},"safety_pin":{"id":"safety_pin","name":"Safety Pin","keywords":["diaper"],"skins":[{"unified":"1f9f7","native":"🧷"}],"version":11},"broom":{"id":"broom","name":"Broom","keywords":["cleaning","sweeping","witch"],"skins":[{"unified":"1f9f9","native":"🧹"}],"version":11},"basket":{"id":"basket","name":"Basket","keywords":["laundry"],"skins":[{"unified":"1f9fa","native":"🧺"}],"version":11},"roll_of_paper":{"id":"roll_of_paper","name":"Roll of Paper","keywords":[],"skins":[{"unified":"1f9fb","native":"🧻"}],"version":11},"bucket":{"id":"bucket","name":"Bucket","keywords":["water","container"],"skins":[{"unified":"1faa3","native":"🪣"}],"version":13},"soap":{"id":"soap","name":"Soap","keywords":["bar","bathing","cleaning","lather"],"skins":[{"unified":"1f9fc","native":"🧼"}],"version":11},"bubbles":{"id":"bubbles","name":"Bubbles","keywords":["soap","fun","carbonation","sparkling"],"skins":[{"unified":"1fae7","native":"🫧"}],"version":14},"toothbrush":{"id":"toothbrush","name":"Toothbrush","keywords":["hygiene","dental"],"skins":[{"unified":"1faa5","native":"🪥"}],"version":13},"sponge":{"id":"sponge","name":"Sponge","keywords":["absorbing","cleaning","porous"],"skins":[{"unified":"1f9fd","native":"🧽"}],"version":11},"fire_extinguisher":{"id":"fire_extinguisher","name":"Fire Extinguisher","keywords":["quench"],"skins":[{"unified":"1f9ef","native":"🧯"}],"version":11},"shopping_trolley":{"id":"shopping_trolley","name":"Shopping Cart","keywords":["trolley"],"skins":[{"unified":"1f6d2","native":"🛒"}],"version":3},"smoking":{"id":"smoking","name":"Cigarette","keywords":["smoking","kills","tobacco","joint","smoke"],"skins":[{"unified":"1f6ac","native":"🚬"}],"version":1},"coffin":{"id":"coffin","name":"Coffin","keywords":["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],"skins":[{"unified":"26b0-fe0f","native":"⚰️"}],"version":1},"headstone":{"id":"headstone","name":"Headstone","keywords":["death","rip","grave"],"skins":[{"unified":"1faa6","native":"🪦"}],"version":13},"funeral_urn":{"id":"funeral_urn","name":"Funeral Urn","keywords":["dead","die","death","rip","ashes"],"skins":[{"unified":"26b1-fe0f","native":"⚱️"}],"version":1},"nazar_amulet":{"id":"nazar_amulet","name":"Nazar Amulet","keywords":["bead","charm"],"skins":[{"unified":"1f9ff","native":"🧿"}],"version":11},"hamsa":{"id":"hamsa","name":"Hamsa","keywords":["religion","protection"],"skins":[{"unified":"1faac","native":"🪬"}],"version":14},"moyai":{"id":"moyai","name":"Moai","keywords":["moyai","rock","easter","island"],"skins":[{"unified":"1f5ff","native":"🗿"}],"version":1},"placard":{"id":"placard","name":"Placard","keywords":["announcement"],"skins":[{"unified":"1faa7","native":"🪧"}],"version":13},"identification_card":{"id":"identification_card","name":"Identification Card","keywords":["document"],"skins":[{"unified":"1faaa","native":"🪪"}],"version":14},"atm":{"id":"atm","name":"Atm Sign","keywords":["money","sales","cash","blue","square","payment","bank"],"skins":[{"unified":"1f3e7","native":"🏧"}],"version":1},"put_litter_in_its_place":{"id":"put_litter_in_its_place","name":"Litter in Bin Sign","keywords":["put","its","place","blue","square","human","info"],"skins":[{"unified":"1f6ae","native":"🚮"}],"version":1},"potable_water":{"id":"potable_water","name":"Potable Water","keywords":["blue","square","liquid","restroom","cleaning","faucet"],"skins":[{"unified":"1f6b0","native":"🚰"}],"version":1},"wheelchair":{"id":"wheelchair","name":"Wheelchair Symbol","keywords":["blue","square","disabled","accessibility"],"skins":[{"unified":"267f","native":"♿"}],"version":1},"mens":{"id":"mens","name":"Men’s Room","keywords":["mens","men","s","toilet","restroom","wc","blue","square","gender","male"],"skins":[{"unified":"1f6b9","native":"🚹"}],"version":1},"womens":{"id":"womens","name":"Women’s Room","keywords":["womens","women","s","purple","square","woman","female","toilet","loo","restroom","gender"],"skins":[{"unified":"1f6ba","native":"🚺"}],"version":1},"restroom":{"id":"restroom","name":"Restroom","keywords":["blue","square","toilet","refresh","wc","gender"],"skins":[{"unified":"1f6bb","native":"🚻"}],"version":1},"baby_symbol":{"id":"baby_symbol","name":"Baby Symbol","keywords":["orange","square","child"],"skins":[{"unified":"1f6bc","native":"🚼"}],"version":1},"wc":{"id":"wc","name":"Water Closet","keywords":["wc","toilet","restroom","blue","square"],"skins":[{"unified":"1f6be","native":"🚾"}],"version":1},"passport_control":{"id":"passport_control","name":"Passport Control","keywords":["custom","blue","square"],"skins":[{"unified":"1f6c2","native":"🛂"}],"version":1},"customs":{"id":"customs","name":"Customs","keywords":["passport","border","blue","square"],"skins":[{"unified":"1f6c3","native":"🛃"}],"version":1},"baggage_claim":{"id":"baggage_claim","name":"Baggage Claim","keywords":["blue","square","airport","transport"],"skins":[{"unified":"1f6c4","native":"🛄"}],"version":1},"left_luggage":{"id":"left_luggage","name":"Left Luggage","keywords":["blue","square","travel"],"skins":[{"unified":"1f6c5","native":"🛅"}],"version":1},"warning":{"id":"warning","name":"Warning","keywords":["exclamation","wip","alert","error","problem","issue"],"skins":[{"unified":"26a0-fe0f","native":"⚠️"}],"version":1},"children_crossing":{"id":"children_crossing","name":"Children Crossing","keywords":["school","warning","danger","sign","driving","yellow","diamond"],"skins":[{"unified":"1f6b8","native":"🚸"}],"version":1},"no_entry":{"id":"no_entry","name":"No Entry","keywords":["limit","security","privacy","bad","denied","stop","circle"],"skins":[{"unified":"26d4","native":"⛔"}],"version":1},"no_entry_sign":{"id":"no_entry_sign","name":"Prohibited","keywords":["no","entry","sign","forbid","stop","limit","denied","disallow","circle"],"skins":[{"unified":"1f6ab","native":"🚫"}],"version":1},"no_bicycles":{"id":"no_bicycles","name":"No Bicycles","keywords":["cyclist","prohibited","circle"],"skins":[{"unified":"1f6b3","native":"🚳"}],"version":1},"no_smoking":{"id":"no_smoking","name":"No Smoking","keywords":["cigarette","blue","square","smell","smoke"],"skins":[{"unified":"1f6ad","native":"🚭"}],"version":1},"do_not_litter":{"id":"do_not_litter","name":"No Littering","keywords":["do","not","litter","trash","bin","garbage","circle"],"skins":[{"unified":"1f6af","native":"🚯"}],"version":1},"non-potable_water":{"id":"non-potable_water","name":"Non-Potable Water","keywords":["non","potable","drink","faucet","tap","circle"],"skins":[{"unified":"1f6b1","native":"🚱"}],"version":1},"no_pedestrians":{"id":"no_pedestrians","name":"No Pedestrians","keywords":["rules","crossing","walking","circle"],"skins":[{"unified":"1f6b7","native":"🚷"}],"version":1},"no_mobile_phones":{"id":"no_mobile_phones","name":"No Mobile Phones","keywords":["iphone","mute","circle"],"skins":[{"unified":"1f4f5","native":"📵"}],"version":1},"underage":{"id":"underage","name":"No One Under Eighteen","keywords":["underage","18","drink","pub","night","minor","circle"],"skins":[{"unified":"1f51e","native":"🔞"}],"version":1},"radioactive_sign":{"id":"radioactive_sign","name":"Radioactive","keywords":["sign","nuclear","danger"],"skins":[{"unified":"2622-fe0f","native":"☢️"}],"version":1},"biohazard_sign":{"id":"biohazard_sign","name":"Biohazard","keywords":["sign","danger"],"skins":[{"unified":"2623-fe0f","native":"☣️"}],"version":1},"arrow_up":{"id":"arrow_up","name":"Up Arrow","keywords":["blue","square","continue","top","direction"],"skins":[{"unified":"2b06-fe0f","native":"⬆️"}],"version":1},"arrow_upper_right":{"id":"arrow_upper_right","name":"Up-Right Arrow","keywords":["upper","right","up","blue","square","point","direction","diagonal","northeast"],"skins":[{"unified":"2197-fe0f","native":"↗️"}],"version":1},"arrow_right":{"id":"arrow_right","name":"Right Arrow","keywords":["blue","square","next"],"skins":[{"unified":"27a1-fe0f","native":"➡️"}],"version":1},"arrow_lower_right":{"id":"arrow_lower_right","name":"South East Arrow","keywords":["lower","right","down","blue","square","direction","diagonal","southeast"],"skins":[{"unified":"2198-fe0f","native":"↘️"}],"version":1},"arrow_down":{"id":"arrow_down","name":"Down Arrow","keywords":["blue","square","direction","bottom"],"skins":[{"unified":"2b07-fe0f","native":"⬇️"}],"version":1},"arrow_lower_left":{"id":"arrow_lower_left","name":"Down-Left Arrow","keywords":["lower","left","down","blue","square","direction","diagonal","southwest"],"skins":[{"unified":"2199-fe0f","native":"↙️"}],"version":1},"arrow_left":{"id":"arrow_left","name":"Left Arrow","keywords":["blue","square","previous","back"],"skins":[{"unified":"2b05-fe0f","native":"⬅️"}],"version":1},"arrow_upper_left":{"id":"arrow_upper_left","name":"Up-Left Arrow","keywords":["upper","left","up","blue","square","point","direction","diagonal","northwest"],"skins":[{"unified":"2196-fe0f","native":"↖️"}],"version":1},"arrow_up_down":{"id":"arrow_up_down","name":"Up Down Arrow","keywords":["blue","square","direction","way","vertical"],"skins":[{"unified":"2195-fe0f","native":"↕️"}],"version":1},"left_right_arrow":{"id":"left_right_arrow","name":"Left Right Arrow","keywords":["shape","direction","horizontal","sideways"],"skins":[{"unified":"2194-fe0f","native":"↔️"}],"version":1},"leftwards_arrow_with_hook":{"id":"leftwards_arrow_with_hook","name":"Right Arrow Curving Left","keywords":["leftwards","with","hook","back","return","blue","square","undo","enter"],"skins":[{"unified":"21a9-fe0f","native":"↩️"}],"version":1},"arrow_right_hook":{"id":"arrow_right_hook","name":"Left Arrow Curving Right","keywords":["hook","blue","square","return","rotate","direction"],"skins":[{"unified":"21aa-fe0f","native":"↪️"}],"version":1},"arrow_heading_up":{"id":"arrow_heading_up","name":"Right Arrow Curving Up","keywords":["heading","blue","square","direction","top"],"skins":[{"unified":"2934-fe0f","native":"⤴️"}],"version":1},"arrow_heading_down":{"id":"arrow_heading_down","name":"Right Arrow Curving Down","keywords":["heading","blue","square","direction","bottom"],"skins":[{"unified":"2935-fe0f","native":"⤵️"}],"version":1},"arrows_clockwise":{"id":"arrows_clockwise","name":"Clockwise Vertical Arrows","keywords":["sync","cycle","round","repeat"],"skins":[{"unified":"1f503","native":"🔃"}],"version":1},"arrows_counterclockwise":{"id":"arrows_counterclockwise","name":"Counterclockwise Arrows Button","keywords":["blue","square","sync","cycle"],"skins":[{"unified":"1f504","native":"🔄"}],"version":1},"back":{"id":"back","name":"Back Arrow","keywords":["words","return"],"skins":[{"unified":"1f519","native":"🔙"}],"version":1},"end":{"id":"end","name":"End Arrow","keywords":["words"],"skins":[{"unified":"1f51a","native":"🔚"}],"version":1},"on":{"id":"on","name":"On! Arrow","keywords":["on","words"],"skins":[{"unified":"1f51b","native":"🔛"}],"version":1},"soon":{"id":"soon","name":"Soon Arrow","keywords":["words"],"skins":[{"unified":"1f51c","native":"🔜"}],"version":1},"top":{"id":"top","name":"Top Arrow","keywords":["words","blue","square"],"skins":[{"unified":"1f51d","native":"🔝"}],"version":1},"place_of_worship":{"id":"place_of_worship","name":"Place of Worship","keywords":["religion","church","temple","prayer"],"skins":[{"unified":"1f6d0","native":"🛐"}],"version":1},"atom_symbol":{"id":"atom_symbol","name":"Atom Symbol","keywords":["science","physics","chemistry"],"skins":[{"unified":"269b-fe0f","native":"⚛️"}],"version":1},"om_symbol":{"id":"om_symbol","name":"Om","keywords":["symbol","hinduism","buddhism","sikhism","jainism"],"skins":[{"unified":"1f549-fe0f","native":"🕉️"}],"version":1},"star_of_david":{"id":"star_of_david","name":"Star of David","keywords":["judaism"],"skins":[{"unified":"2721-fe0f","native":"✡️"}],"version":1},"wheel_of_dharma":{"id":"wheel_of_dharma","name":"Wheel of Dharma","keywords":["hinduism","buddhism","sikhism","jainism"],"skins":[{"unified":"2638-fe0f","native":"☸️"}],"version":1},"yin_yang":{"id":"yin_yang","name":"Yin Yang","keywords":["balance"],"skins":[{"unified":"262f-fe0f","native":"☯️"}],"version":1},"latin_cross":{"id":"latin_cross","name":"Latin Cross","keywords":["christianity"],"skins":[{"unified":"271d-fe0f","native":"✝️"}],"version":1},"orthodox_cross":{"id":"orthodox_cross","name":"Orthodox Cross","keywords":["suppedaneum","religion"],"skins":[{"unified":"2626-fe0f","native":"☦️"}],"version":1},"star_and_crescent":{"id":"star_and_crescent","name":"Star and Crescent","keywords":["islam"],"skins":[{"unified":"262a-fe0f","native":"☪️"}],"version":1},"peace_symbol":{"id":"peace_symbol","name":"Peace Symbol","keywords":["hippie"],"skins":[{"unified":"262e-fe0f","native":"☮️"}],"version":1},"menorah_with_nine_branches":{"id":"menorah_with_nine_branches","name":"Menorah","keywords":["with","nine","branches","hanukkah","candles","jewish"],"skins":[{"unified":"1f54e","native":"🕎"}],"version":1},"six_pointed_star":{"id":"six_pointed_star","name":"Dotted Six-Pointed Star","keywords":["six","pointed","purple","square","religion","jewish","hexagram"],"skins":[{"unified":"1f52f","native":"🔯"}],"version":1},"khanda":{"id":"khanda","name":"Khanda","keywords":["Sikhism","religion"],"skins":[{"unified":"1faaf","native":"🪯"}],"version":15},"aries":{"id":"aries","name":"Aries","keywords":["sign","purple","square","zodiac","astrology"],"skins":[{"unified":"2648","native":"♈"}],"version":1},"taurus":{"id":"taurus","name":"Taurus","keywords":["purple","square","sign","zodiac","astrology"],"skins":[{"unified":"2649","native":"♉"}],"version":1},"gemini":{"id":"gemini","name":"Gemini","keywords":["sign","zodiac","purple","square","astrology"],"skins":[{"unified":"264a","native":"♊"}],"version":1},"cancer":{"id":"cancer","name":"Cancer","keywords":["sign","zodiac","purple","square","astrology"],"skins":[{"unified":"264b","native":"♋"}],"version":1},"leo":{"id":"leo","name":"Leo","keywords":["sign","purple","square","zodiac","astrology"],"skins":[{"unified":"264c","native":"♌"}],"version":1},"virgo":{"id":"virgo","name":"Virgo","keywords":["sign","zodiac","purple","square","astrology"],"skins":[{"unified":"264d","native":"♍"}],"version":1},"libra":{"id":"libra","name":"Libra","keywords":["sign","purple","square","zodiac","astrology"],"skins":[{"unified":"264e","native":"♎"}],"version":1},"scorpius":{"id":"scorpius","name":"Scorpio","keywords":["scorpius","sign","zodiac","purple","square","astrology"],"skins":[{"unified":"264f","native":"♏"}],"version":1},"sagittarius":{"id":"sagittarius","name":"Sagittarius","keywords":["sign","zodiac","purple","square","astrology"],"skins":[{"unified":"2650","native":"♐"}],"version":1},"capricorn":{"id":"capricorn","name":"Capricorn","keywords":["sign","zodiac","purple","square","astrology"],"skins":[{"unified":"2651","native":"♑"}],"version":1},"aquarius":{"id":"aquarius","name":"Aquarius","keywords":["sign","purple","square","zodiac","astrology"],"skins":[{"unified":"2652","native":"♒"}],"version":1},"pisces":{"id":"pisces","name":"Pisces","keywords":["purple","square","sign","zodiac","astrology"],"skins":[{"unified":"2653","native":"♓"}],"version":1},"ophiuchus":{"id":"ophiuchus","name":"Ophiuchus","keywords":["sign","purple","square","constellation","astrology"],"skins":[{"unified":"26ce","native":"⛎"}],"version":1},"twisted_rightwards_arrows":{"id":"twisted_rightwards_arrows","name":"Shuffle Tracks Button","keywords":["twisted","rightwards","arrows","blue","square","music","random"],"skins":[{"unified":"1f500","native":"🔀"}],"version":1},"repeat":{"id":"repeat","name":"Repeat Button","keywords":["loop","record"],"skins":[{"unified":"1f501","native":"🔁"}],"version":1},"repeat_one":{"id":"repeat_one","name":"Repeat Single Button","keywords":["one","blue","square","loop"],"skins":[{"unified":"1f502","native":"🔂"}],"version":1},"arrow_forward":{"id":"arrow_forward","name":"Play Button","keywords":["arrow","forward","blue","square","right","direction"],"skins":[{"unified":"25b6-fe0f","native":"▶️"}],"version":1},"fast_forward":{"id":"fast_forward","name":"Fast-Forward Button","keywords":["fast","forward","blue","square","play","speed","continue"],"skins":[{"unified":"23e9","native":"⏩"}],"version":1},"black_right_pointing_double_triangle_with_vertical_bar":{"id":"black_right_pointing_double_triangle_with_vertical_bar","name":"Next Track Button","keywords":["black","right","pointing","double","triangle","with","vertical","bar","forward","blue","square"],"skins":[{"unified":"23ed-fe0f","native":"⏭️"}],"version":1},"black_right_pointing_triangle_with_double_vertical_bar":{"id":"black_right_pointing_triangle_with_double_vertical_bar","name":"Play or Pause Button","keywords":["black","right","pointing","triangle","with","double","vertical","bar","blue","square"],"skins":[{"unified":"23ef-fe0f","native":"⏯️"}],"version":1},"arrow_backward":{"id":"arrow_backward","name":"Reverse Button","keywords":["arrow","backward","blue","square","left","direction"],"skins":[{"unified":"25c0-fe0f","native":"◀️"}],"version":1},"rewind":{"id":"rewind","name":"Fast Reverse Button","keywords":["rewind","play","blue","square"],"skins":[{"unified":"23ea","native":"⏪"}],"version":1},"black_left_pointing_double_triangle_with_vertical_bar":{"id":"black_left_pointing_double_triangle_with_vertical_bar","name":"Last Track Button","keywords":["black","left","pointing","double","triangle","with","vertical","bar","backward"],"skins":[{"unified":"23ee-fe0f","native":"⏮️"}],"version":1},"arrow_up_small":{"id":"arrow_up_small","name":"Upwards Button","keywords":["arrow","up","small","blue","square","triangle","direction","point","forward","top"],"skins":[{"unified":"1f53c","native":"🔼"}],"version":1},"arrow_double_up":{"id":"arrow_double_up","name":"Fast Up Button","keywords":["arrow","double","blue","square","direction","top"],"skins":[{"unified":"23eb","native":"⏫"}],"version":1},"arrow_down_small":{"id":"arrow_down_small","name":"Downwards Button","keywords":["arrow","down","small","blue","square","direction","bottom"],"skins":[{"unified":"1f53d","native":"🔽"}],"version":1},"arrow_double_down":{"id":"arrow_double_down","name":"Fast Down Button","keywords":["arrow","double","blue","square","direction","bottom"],"skins":[{"unified":"23ec","native":"⏬"}],"version":1},"double_vertical_bar":{"id":"double_vertical_bar","name":"Pause Button","keywords":["double","vertical","bar","blue","square"],"skins":[{"unified":"23f8-fe0f","native":"⏸️"}],"version":1},"black_square_for_stop":{"id":"black_square_for_stop","name":"Stop Button","keywords":["black","square","for","blue"],"skins":[{"unified":"23f9-fe0f","native":"⏹️"}],"version":1},"black_circle_for_record":{"id":"black_circle_for_record","name":"Record Button","keywords":["black","circle","for","blue","square"],"skins":[{"unified":"23fa-fe0f","native":"⏺️"}],"version":1},"eject":{"id":"eject","name":"Eject Button","keywords":["blue","square"],"skins":[{"unified":"23cf-fe0f","native":"⏏️"}],"version":1},"cinema":{"id":"cinema","name":"Cinema","keywords":["blue","square","record","film","movie","curtain","stage","theater"],"skins":[{"unified":"1f3a6","native":"🎦"}],"version":1},"low_brightness":{"id":"low_brightness","name":"Dim Button","keywords":["low","brightness","sun","afternoon","warm","summer"],"skins":[{"unified":"1f505","native":"🔅"}],"version":1},"high_brightness":{"id":"high_brightness","name":"Bright Button","keywords":["high","brightness","sun","light"],"skins":[{"unified":"1f506","native":"🔆"}],"version":1},"signal_strength":{"id":"signal_strength","name":"Antenna Bars","keywords":["signal","strength","blue","square","reception","phone","internet","connection","wifi","bluetooth"],"skins":[{"unified":"1f4f6","native":"📶"}],"version":1},"wireless":{"id":"wireless","name":"Wireless","keywords":["wifi","internet","contactless","signal"],"skins":[{"unified":"1f6dc","native":"🛜"}],"version":15},"vibration_mode":{"id":"vibration_mode","name":"Vibration Mode","keywords":["orange","square","phone"],"skins":[{"unified":"1f4f3","native":"📳"}],"version":1},"mobile_phone_off":{"id":"mobile_phone_off","name":"Mobile Phone off","keywords":["mute","orange","square","silence","quiet"],"skins":[{"unified":"1f4f4","native":"📴"}],"version":1},"female_sign":{"id":"female_sign","name":"Female Sign","keywords":["woman","women","lady","girl"],"skins":[{"unified":"2640-fe0f","native":"♀️"}],"version":4},"male_sign":{"id":"male_sign","name":"Male Sign","keywords":["man","boy","men"],"skins":[{"unified":"2642-fe0f","native":"♂️"}],"version":4},"transgender_symbol":{"id":"transgender_symbol","name":"Transgender Symbol","keywords":["lgbtq"],"skins":[{"unified":"26a7-fe0f","native":"⚧️"}],"version":13},"heavy_multiplication_x":{"id":"heavy_multiplication_x","name":"Multiply","keywords":["heavy","multiplication","x","sign","math","calculation"],"skins":[{"unified":"2716-fe0f","native":"✖️"}],"version":1},"heavy_plus_sign":{"id":"heavy_plus_sign","name":"Plus","keywords":["heavy","sign","math","calculation","addition","more","increase"],"skins":[{"unified":"2795","native":"➕"}],"version":1},"heavy_minus_sign":{"id":"heavy_minus_sign","name":"Minus","keywords":["heavy","sign","math","calculation","subtract","less"],"skins":[{"unified":"2796","native":"➖"}],"version":1},"heavy_division_sign":{"id":"heavy_division_sign","name":"Divide","keywords":["heavy","division","sign","math","calculation"],"skins":[{"unified":"2797","native":"➗"}],"version":1},"heavy_equals_sign":{"id":"heavy_equals_sign","name":"Heavy Equals Sign","keywords":["math"],"skins":[{"unified":"1f7f0","native":"🟰"}],"version":14},"infinity":{"id":"infinity","name":"Infinity","keywords":["forever"],"skins":[{"unified":"267e-fe0f","native":"♾️"}],"version":11},"bangbang":{"id":"bangbang","name":"Double Exclamation Mark","keywords":["bangbang","surprise"],"skins":[{"unified":"203c-fe0f","native":"‼️"}],"version":1},"interrobang":{"id":"interrobang","name":"Exclamation Question Mark","keywords":["interrobang","wat","punctuation","surprise"],"skins":[{"unified":"2049-fe0f","native":"⁉️"}],"version":1},"question":{"id":"question","name":"Red Question Mark","keywords":["doubt","confused"],"skins":[{"unified":"2753","native":"❓"}],"version":1},"grey_question":{"id":"grey_question","name":"White Question Mark","keywords":["grey","doubts","gray","huh","confused"],"skins":[{"unified":"2754","native":"❔"}],"version":1},"grey_exclamation":{"id":"grey_exclamation","name":"White Exclamation Mark","keywords":["grey","surprise","punctuation","gray","wow","warning"],"skins":[{"unified":"2755","native":"❕"}],"version":1},"exclamation":{"id":"exclamation","name":"Red Exclamation Mark","keywords":["heavy","danger","surprise","punctuation","wow","warning"],"skins":[{"unified":"2757","native":"❗"}],"version":1},"wavy_dash":{"id":"wavy_dash","name":"Wavy Dash","keywords":["draw","line","moustache","mustache","squiggle","scribble"],"skins":[{"unified":"3030-fe0f","native":"〰️"}],"version":1},"currency_exchange":{"id":"currency_exchange","name":"Currency Exchange","keywords":["money","sales","dollar","travel"],"skins":[{"unified":"1f4b1","native":"💱"}],"version":1},"heavy_dollar_sign":{"id":"heavy_dollar_sign","name":"Heavy Dollar Sign","keywords":["money","sales","payment","currency","buck"],"skins":[{"unified":"1f4b2","native":"💲"}],"version":1},"medical_symbol":{"id":"medical_symbol","name":"Medical Symbol","keywords":["staff","of","aesculapius","health","hospital"],"skins":[{"unified":"2695-fe0f","native":"⚕️"}],"version":4},"recycle":{"id":"recycle","name":"Recycling Symbol","keywords":["recycle","arrow","environment","garbage","trash"],"skins":[{"unified":"267b-fe0f","native":"♻️"}],"version":1},"fleur_de_lis":{"id":"fleur_de_lis","name":"Fleur-De-Lis","keywords":["fleur","de","lis","decorative","scout"],"skins":[{"unified":"269c-fe0f","native":"⚜️"}],"version":1},"trident":{"id":"trident","name":"Trident Emblem","keywords":["weapon","spear"],"skins":[{"unified":"1f531","native":"🔱"}],"version":1},"name_badge":{"id":"name_badge","name":"Name Badge","keywords":["fire","forbid"],"skins":[{"unified":"1f4db","native":"📛"}],"version":1},"beginner":{"id":"beginner","name":"Japanese Symbol for Beginner","keywords":["badge","shield"],"skins":[{"unified":"1f530","native":"🔰"}],"version":1},"o":{"id":"o","name":"Hollow Red Circle","keywords":["o","round"],"skins":[{"unified":"2b55","native":"⭕"}],"version":1},"white_check_mark":{"id":"white_check_mark","name":"Check Mark Button","keywords":["white","green","square","ok","agree","vote","election","answer","tick"],"skins":[{"unified":"2705","native":"✅"}],"version":1},"ballot_box_with_check":{"id":"ballot_box_with_check","name":"Check Box with Check","keywords":["ballot","ok","agree","confirm","black","square","vote","election","yes","tick"],"skins":[{"unified":"2611-fe0f","native":"☑️"}],"version":1},"heavy_check_mark":{"id":"heavy_check_mark","name":"Check Mark","keywords":["heavy","ok","nike","answer","yes","tick"],"skins":[{"unified":"2714-fe0f","native":"✔️"}],"version":1},"x":{"id":"x","name":"Cross Mark","keywords":["x","no","delete","remove","cancel","red"],"skins":[{"unified":"274c","native":"❌"}],"version":1},"negative_squared_cross_mark":{"id":"negative_squared_cross_mark","name":"Cross Mark Button","keywords":["negative","squared","x","green","square","no","deny"],"skins":[{"unified":"274e","native":"❎"}],"version":1},"curly_loop":{"id":"curly_loop","name":"Curly Loop","keywords":["scribble","draw","shape","squiggle"],"skins":[{"unified":"27b0","native":"➰"}],"version":1},"loop":{"id":"loop","name":"Double Curly Loop","keywords":["tape","cassette"],"skins":[{"unified":"27bf","native":"➿"}],"version":1},"part_alternation_mark":{"id":"part_alternation_mark","name":"Part Alternation Mark","keywords":["graph","presentation","stats","business","economics","bad"],"skins":[{"unified":"303d-fe0f","native":"〽️"}],"version":1},"eight_spoked_asterisk":{"id":"eight_spoked_asterisk","name":"Eight Spoked Asterisk","keywords":["star","sparkle","green","square"],"skins":[{"unified":"2733-fe0f","native":"✳️"}],"version":1},"eight_pointed_black_star":{"id":"eight_pointed_black_star","name":"Eight-Pointed Star","keywords":["eight","pointed","black","orange","square","shape","polygon"],"skins":[{"unified":"2734-fe0f","native":"✴️"}],"version":1},"sparkle":{"id":"sparkle","name":"Sparkle","keywords":["stars","green","square","awesome","good","fireworks"],"skins":[{"unified":"2747-fe0f","native":"❇️"}],"version":1},"copyright":{"id":"copyright","name":"Copyright","keywords":["ip","license","circle","law","legal"],"skins":[{"unified":"00a9-fe0f","native":"©️"}],"version":1},"registered":{"id":"registered","name":"Registered","keywords":["alphabet","circle"],"skins":[{"unified":"00ae-fe0f","native":"®️"}],"version":1},"tm":{"id":"tm","name":"Trade Mark","keywords":["tm","trademark","brand","law","legal"],"skins":[{"unified":"2122-fe0f","native":"™️"}],"version":1},"hash":{"id":"hash","name":"Hash Key","keywords":["keycap","","symbol","blue","square","twitter"],"skins":[{"unified":"0023-fe0f-20e3","native":"#️⃣"}],"version":1},"keycap_star":{"id":"keycap_star","name":"Keycap: *","keywords":["keycap","star",""],"skins":[{"unified":"002a-fe0f-20e3","native":"*️⃣"}],"version":2},"zero":{"id":"zero","name":"Keycap 0","keywords":["zero","numbers","blue","square","null"],"skins":[{"unified":"0030-fe0f-20e3","native":"0️⃣"}],"version":1},"one":{"id":"one","name":"Keycap 1","keywords":["one","blue","square","numbers"],"skins":[{"unified":"0031-fe0f-20e3","native":"1️⃣"}],"version":1},"two":{"id":"two","name":"Keycap 2","keywords":["two","numbers","prime","blue","square"],"skins":[{"unified":"0032-fe0f-20e3","native":"2️⃣"}],"version":1},"three":{"id":"three","name":"Keycap 3","keywords":["three","numbers","prime","blue","square"],"skins":[{"unified":"0033-fe0f-20e3","native":"3️⃣"}],"version":1},"four":{"id":"four","name":"Keycap 4","keywords":["four","numbers","blue","square"],"skins":[{"unified":"0034-fe0f-20e3","native":"4️⃣"}],"version":1},"five":{"id":"five","name":"Keycap 5","keywords":["five","numbers","blue","square","prime"],"skins":[{"unified":"0035-fe0f-20e3","native":"5️⃣"}],"version":1},"six":{"id":"six","name":"Keycap 6","keywords":["six","numbers","blue","square"],"skins":[{"unified":"0036-fe0f-20e3","native":"6️⃣"}],"version":1},"seven":{"id":"seven","name":"Keycap 7","keywords":["seven","numbers","blue","square","prime"],"skins":[{"unified":"0037-fe0f-20e3","native":"7️⃣"}],"version":1},"eight":{"id":"eight","name":"Keycap 8","keywords":["eight","blue","square","numbers"],"skins":[{"unified":"0038-fe0f-20e3","native":"8️⃣"}],"version":1},"nine":{"id":"nine","name":"Keycap 9","keywords":["nine","blue","square","numbers"],"skins":[{"unified":"0039-fe0f-20e3","native":"9️⃣"}],"version":1},"keycap_ten":{"id":"keycap_ten","name":"Keycap 10","keywords":["ten","numbers","blue","square"],"skins":[{"unified":"1f51f","native":"🔟"}],"version":1},"capital_abcd":{"id":"capital_abcd","name":"Input Latin Uppercase","keywords":["capital","abcd","alphabet","words","blue","square"],"skins":[{"unified":"1f520","native":"🔠"}],"version":1},"abcd":{"id":"abcd","name":"Input Latin Lowercase","keywords":["abcd","blue","square","alphabet"],"skins":[{"unified":"1f521","native":"🔡"}],"version":1},"symbols":{"id":"symbols","name":"Input Symbols","keywords":["blue","square","music","note","ampersand","percent","glyphs","characters"],"skins":[{"unified":"1f523","native":"🔣"}],"version":1},"abc":{"id":"abc","name":"Input Latin Letters","keywords":["abc","blue","square","alphabet"],"skins":[{"unified":"1f524","native":"🔤"}],"version":1},"a":{"id":"a","name":"A Button (blood Type)","keywords":["red","square","alphabet","letter"],"skins":[{"unified":"1f170-fe0f","native":"🅰️"}],"version":1},"ab":{"id":"ab","name":"Negative Squared Ab","keywords":["button","red","square","alphabet"],"skins":[{"unified":"1f18e","native":"🆎"}],"version":1},"b":{"id":"b","name":"B Button (blood Type)","keywords":["red","square","alphabet","letter"],"skins":[{"unified":"1f171-fe0f","native":"🅱️"}],"version":1},"cl":{"id":"cl","name":"Cl Button","keywords":["alphabet","words","red","square"],"skins":[{"unified":"1f191","native":"🆑"}],"version":1},"cool":{"id":"cool","name":"Cool Button","keywords":["words","blue","square"],"skins":[{"unified":"1f192","native":"🆒"}],"version":1},"free":{"id":"free","name":"Free Button","keywords":["blue","square","words"],"skins":[{"unified":"1f193","native":"🆓"}],"version":1},"information_source":{"id":"information_source","name":"Information","keywords":["source","blue","square","alphabet","letter"],"skins":[{"unified":"2139-fe0f","native":"ℹ️"}],"version":1},"id":{"id":"id","name":"Id Button","keywords":["purple","square","words"],"skins":[{"unified":"1f194","native":"🆔"}],"version":1},"m":{"id":"m","name":"Circled M","keywords":["alphabet","blue","circle","letter"],"skins":[{"unified":"24c2-fe0f","native":"Ⓜ️"}],"version":1},"new":{"id":"new","name":"New Button","keywords":["blue","square","words","start"],"skins":[{"unified":"1f195","native":"🆕"}],"version":1},"ng":{"id":"ng","name":"Ng Button","keywords":["blue","square","words","shape","icon"],"skins":[{"unified":"1f196","native":"🆖"}],"version":1},"o2":{"id":"o2","name":"O Button (blood Type)","keywords":["o2","alphabet","red","square","letter"],"skins":[{"unified":"1f17e-fe0f","native":"🅾️"}],"version":1},"ok":{"id":"ok","name":"Ok Button","keywords":["good","agree","yes","blue","square"],"skins":[{"unified":"1f197","native":"🆗"}],"version":1},"parking":{"id":"parking","name":"P Button","keywords":["parking","cars","blue","square","alphabet","letter"],"skins":[{"unified":"1f17f-fe0f","native":"🅿️"}],"version":1},"sos":{"id":"sos","name":"Sos Button","keywords":["help","red","square","words","emergency","911"],"skins":[{"unified":"1f198","native":"🆘"}],"version":1},"up":{"id":"up","name":"Up! Button","keywords":["up","blue","square","above","high"],"skins":[{"unified":"1f199","native":"🆙"}],"version":1},"vs":{"id":"vs","name":"Vs Button","keywords":["words","orange","square"],"skins":[{"unified":"1f19a","native":"🆚"}],"version":1},"koko":{"id":"koko","name":"Squared Katakana Koko","keywords":["japanese","here","button","blue","square","destination"],"skins":[{"unified":"1f201","native":"🈁"}],"version":1},"sa":{"id":"sa","name":"Squared Katakana Sa","keywords":["japanese","service","charge","button","blue","square"],"skins":[{"unified":"1f202-fe0f","native":"🈂️"}],"version":1},"u6708":{"id":"u6708","name":"Japanese “monthly Amount” Button","keywords":["u6708","monthly","amount","chinese","month","moon","orange","square","kanji"],"skins":[{"unified":"1f237-fe0f","native":"🈷️"}],"version":1},"u6709":{"id":"u6709","name":"Squared Cjk Unified Ideograph-6709","keywords":["u6709","japanese","not","free","of","charge","button","orange","square","chinese","have","kanji"],"skins":[{"unified":"1f236","native":"🈶"}],"version":1},"u6307":{"id":"u6307","name":"Japanese “reserved” Button","keywords":["u6307","reserved","chinese","point","green","square","kanji"],"skins":[{"unified":"1f22f","native":"🈯"}],"version":1},"ideograph_advantage":{"id":"ideograph_advantage","name":"Japanese “bargain” Button","keywords":["ideograph","advantage","bargain","chinese","kanji","obtain","get","circle"],"skins":[{"unified":"1f250","native":"🉐"}],"version":1},"u5272":{"id":"u5272","name":"Japanese “discount” Button","keywords":["u5272","discount","cut","divide","chinese","kanji","pink","square"],"skins":[{"unified":"1f239","native":"🈹"}],"version":1},"u7121":{"id":"u7121","name":"Japanese “free of Charge” Button","keywords":["u7121","free","charge","nothing","chinese","kanji","orange","square"],"skins":[{"unified":"1f21a","native":"🈚"}],"version":1},"u7981":{"id":"u7981","name":"Japanese “prohibited” Button","keywords":["u7981","prohibited","kanji","chinese","forbidden","limit","restricted","red","square"],"skins":[{"unified":"1f232","native":"🈲"}],"version":1},"accept":{"id":"accept","name":"Circled Ideograph Accept","keywords":["japanese","acceptable","button","ok","good","chinese","kanji","agree","yes","orange","circle"],"skins":[{"unified":"1f251","native":"🉑"}],"version":1},"u7533":{"id":"u7533","name":"Japanese “application” Button","keywords":["u7533","application","chinese","kanji","orange","square"],"skins":[{"unified":"1f238","native":"🈸"}],"version":1},"u5408":{"id":"u5408","name":"Japanese “passing Grade” Button","keywords":["u5408","passing","grade","chinese","join","kanji","red","square"],"skins":[{"unified":"1f234","native":"🈴"}],"version":1},"u7a7a":{"id":"u7a7a","name":"Japanese “vacancy” Button","keywords":["u7a7a","vacancy","kanji","chinese","empty","sky","blue","square"],"skins":[{"unified":"1f233","native":"🈳"}],"version":1},"congratulations":{"id":"congratulations","name":"Circled Ideograph Congratulation","keywords":["congratulations","japanese","button","chinese","kanji","red","circle"],"skins":[{"unified":"3297-fe0f","native":"㊗️"}],"version":1},"secret":{"id":"secret","name":"Circled Ideograph Secret","keywords":["japanese","button","privacy","chinese","sshh","kanji","red","circle"],"skins":[{"unified":"3299-fe0f","native":"㊙️"}],"version":1},"u55b6":{"id":"u55b6","name":"Squared Cjk Unified Ideograph-55b6","keywords":["u55b6","japanese","open","for","business","button","opening","hours","orange","square"],"skins":[{"unified":"1f23a","native":"🈺"}],"version":1},"u6e80":{"id":"u6e80","name":"Japanese “no Vacancy” Button","keywords":["u6e80","no","vacancy","full","chinese","red","square","kanji"],"skins":[{"unified":"1f235","native":"🈵"}],"version":1},"red_circle":{"id":"red_circle","name":"Red Circle","keywords":["shape","error","danger"],"skins":[{"unified":"1f534","native":"🔴"}],"version":1},"large_orange_circle":{"id":"large_orange_circle","name":"Orange Circle","keywords":["large","round"],"skins":[{"unified":"1f7e0","native":"🟠"}],"version":12},"large_yellow_circle":{"id":"large_yellow_circle","name":"Yellow Circle","keywords":["large","round"],"skins":[{"unified":"1f7e1","native":"🟡"}],"version":12},"large_green_circle":{"id":"large_green_circle","name":"Green Circle","keywords":["large","round"],"skins":[{"unified":"1f7e2","native":"🟢"}],"version":12},"large_blue_circle":{"id":"large_blue_circle","name":"Blue Circle","keywords":["large","shape","icon","button"],"skins":[{"unified":"1f535","native":"🔵"}],"version":1},"large_purple_circle":{"id":"large_purple_circle","name":"Purple Circle","keywords":["large","round"],"skins":[{"unified":"1f7e3","native":"🟣"}],"version":12},"large_brown_circle":{"id":"large_brown_circle","name":"Brown Circle","keywords":["large","round"],"skins":[{"unified":"1f7e4","native":"🟤"}],"version":12},"black_circle":{"id":"black_circle","name":"Black Circle","keywords":["shape","button","round"],"skins":[{"unified":"26ab","native":"⚫"}],"version":1},"white_circle":{"id":"white_circle","name":"White Circle","keywords":["shape","round"],"skins":[{"unified":"26aa","native":"⚪"}],"version":1},"large_red_square":{"id":"large_red_square","name":"Red Square","keywords":["large"],"skins":[{"unified":"1f7e5","native":"🟥"}],"version":12},"large_orange_square":{"id":"large_orange_square","name":"Orange Square","keywords":["large"],"skins":[{"unified":"1f7e7","native":"🟧"}],"version":12},"large_yellow_square":{"id":"large_yellow_square","name":"Yellow Square","keywords":["large"],"skins":[{"unified":"1f7e8","native":"🟨"}],"version":12},"large_green_square":{"id":"large_green_square","name":"Green Square","keywords":["large"],"skins":[{"unified":"1f7e9","native":"🟩"}],"version":12},"large_blue_square":{"id":"large_blue_square","name":"Blue Square","keywords":["large"],"skins":[{"unified":"1f7e6","native":"🟦"}],"version":12},"large_purple_square":{"id":"large_purple_square","name":"Purple Square","keywords":["large"],"skins":[{"unified":"1f7ea","native":"🟪"}],"version":12},"large_brown_square":{"id":"large_brown_square","name":"Brown Square","keywords":["large"],"skins":[{"unified":"1f7eb","native":"🟫"}],"version":12},"black_large_square":{"id":"black_large_square","name":"Black Large Square","keywords":["shape","icon","button"],"skins":[{"unified":"2b1b","native":"⬛"}],"version":1},"white_large_square":{"id":"white_large_square","name":"White Large Square","keywords":["shape","icon","stone","button"],"skins":[{"unified":"2b1c","native":"⬜"}],"version":1},"black_medium_square":{"id":"black_medium_square","name":"Black Medium Square","keywords":["shape","button","icon"],"skins":[{"unified":"25fc-fe0f","native":"◼️"}],"version":1},"white_medium_square":{"id":"white_medium_square","name":"White Medium Square","keywords":["shape","stone","icon"],"skins":[{"unified":"25fb-fe0f","native":"◻️"}],"version":1},"black_medium_small_square":{"id":"black_medium_small_square","name":"Black Medium Small Square","keywords":["icon","shape","button"],"skins":[{"unified":"25fe","native":"◾"}],"version":1},"white_medium_small_square":{"id":"white_medium_small_square","name":"White Medium Small Square","keywords":["shape","stone","icon","button"],"skins":[{"unified":"25fd","native":"◽"}],"version":1},"black_small_square":{"id":"black_small_square","name":"Black Small Square","keywords":["shape","icon"],"skins":[{"unified":"25aa-fe0f","native":"▪️"}],"version":1},"white_small_square":{"id":"white_small_square","name":"White Small Square","keywords":["shape","icon"],"skins":[{"unified":"25ab-fe0f","native":"▫️"}],"version":1},"large_orange_diamond":{"id":"large_orange_diamond","name":"Large Orange Diamond","keywords":["shape","jewel","gem"],"skins":[{"unified":"1f536","native":"🔶"}],"version":1},"large_blue_diamond":{"id":"large_blue_diamond","name":"Large Blue Diamond","keywords":["shape","jewel","gem"],"skins":[{"unified":"1f537","native":"🔷"}],"version":1},"small_orange_diamond":{"id":"small_orange_diamond","name":"Small Orange Diamond","keywords":["shape","jewel","gem"],"skins":[{"unified":"1f538","native":"🔸"}],"version":1},"small_blue_diamond":{"id":"small_blue_diamond","name":"Small Blue Diamond","keywords":["shape","jewel","gem"],"skins":[{"unified":"1f539","native":"🔹"}],"version":1},"small_red_triangle":{"id":"small_red_triangle","name":"Red Triangle Pointed Up","keywords":["small","shape","direction","top"],"skins":[{"unified":"1f53a","native":"🔺"}],"version":1},"small_red_triangle_down":{"id":"small_red_triangle_down","name":"Red Triangle Pointed Down","keywords":["small","shape","direction","bottom"],"skins":[{"unified":"1f53b","native":"🔻"}],"version":1},"diamond_shape_with_a_dot_inside":{"id":"diamond_shape_with_a_dot_inside","name":"Diamond with a Dot","keywords":["shape","inside","jewel","blue","gem","crystal","fancy"],"skins":[{"unified":"1f4a0","native":"💠"}],"version":1},"radio_button":{"id":"radio_button","name":"Radio Button","keywords":["input","old","music","circle"],"skins":[{"unified":"1f518","native":"🔘"}],"version":1},"white_square_button":{"id":"white_square_button","name":"White Square Button","keywords":["shape","input"],"skins":[{"unified":"1f533","native":"🔳"}],"version":1},"black_square_button":{"id":"black_square_button","name":"Black Square Button","keywords":["shape","input","frame"],"skins":[{"unified":"1f532","native":"🔲"}],"version":1},"checkered_flag":{"id":"checkered_flag","name":"Chequered Flag","keywords":["checkered","contest","finishline","race","gokart"],"skins":[{"unified":"1f3c1","native":"🏁"}],"version":1},"triangular_flag_on_post":{"id":"triangular_flag_on_post","name":"Triangular Flag","keywords":["on","post","mark","milestone","place"],"skins":[{"unified":"1f6a9","native":"🚩"}],"version":1},"crossed_flags":{"id":"crossed_flags","name":"Crossed Flags","keywords":["japanese","nation","country","border"],"skins":[{"unified":"1f38c","native":"🎌"}],"version":1},"waving_black_flag":{"id":"waving_black_flag","name":"Black Flag","keywords":["waving","pirate"],"skins":[{"unified":"1f3f4","native":"🏴"}],"version":1},"waving_white_flag":{"id":"waving_white_flag","name":"White Flag","keywords":["waving","losing","loser","lost","surrender","give","up","fail"],"skins":[{"unified":"1f3f3-fe0f","native":"🏳️"}],"version":1},"rainbow-flag":{"id":"rainbow-flag","name":"Rainbow Flag","keywords":["pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],"skins":[{"unified":"1f3f3-fe0f-200d-1f308","native":"🏳️🌈"}],"version":4},"transgender_flag":{"id":"transgender_flag","name":"Transgender Flag","keywords":["lgbtq"],"skins":[{"unified":"1f3f3-fe0f-200d-26a7-fe0f","native":"🏳️⚧️"}],"version":13},"pirate_flag":{"id":"pirate_flag","name":"Pirate Flag","keywords":["skull","crossbones","banner"],"skins":[{"unified":"1f3f4-200d-2620-fe0f","native":"🏴☠️"}],"version":11},"flag-ac":{"id":"flag-ac","name":"Ascension Island Flag","keywords":["ac"],"skins":[{"unified":"1f1e6-1f1e8","native":"🇦🇨"}],"version":2},"flag-ad":{"id":"flag-ad","name":"Andorra Flag","keywords":["ad","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1e9","native":"🇦🇩"}],"version":2},"flag-ae":{"id":"flag-ae","name":"United Arab Emirates Flag","keywords":["ae","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1ea","native":"🇦🇪"}],"version":2},"flag-af":{"id":"flag-af","name":"Afghanistan Flag","keywords":["af","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1eb","native":"🇦🇫"}],"version":2},"flag-ag":{"id":"flag-ag","name":"Antigua & Barbuda Flag","keywords":["ag","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1ec","native":"🇦🇬"}],"version":2},"flag-ai":{"id":"flag-ai","name":"Anguilla Flag","keywords":["ai","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1ee","native":"🇦🇮"}],"version":2},"flag-al":{"id":"flag-al","name":"Albania Flag","keywords":["al","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1f1","native":"🇦🇱"}],"version":2},"flag-am":{"id":"flag-am","name":"Armenia Flag","keywords":["am","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1f2","native":"🇦🇲"}],"version":2},"flag-ao":{"id":"flag-ao","name":"Angola Flag","keywords":["ao","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1f4","native":"🇦🇴"}],"version":2},"flag-aq":{"id":"flag-aq","name":"Antarctica Flag","keywords":["aq","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1f6","native":"🇦🇶"}],"version":2},"flag-ar":{"id":"flag-ar","name":"Argentina Flag","keywords":["ar","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1f7","native":"🇦🇷"}],"version":2},"flag-as":{"id":"flag-as","name":"American Samoa Flag","keywords":["as","ws","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1f8","native":"🇦🇸"}],"version":2},"flag-at":{"id":"flag-at","name":"Austria Flag","keywords":["at","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1f9","native":"🇦🇹"}],"version":2},"flag-au":{"id":"flag-au","name":"Australia Flag","keywords":["au","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1fa","native":"🇦🇺"}],"version":2},"flag-aw":{"id":"flag-aw","name":"Aruba Flag","keywords":["aw","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1fc","native":"🇦🇼"}],"version":2},"flag-ax":{"id":"flag-ax","name":"Åland Islands Flag","keywords":["ax","aland","Aland","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1fd","native":"🇦🇽"}],"version":2},"flag-az":{"id":"flag-az","name":"Azerbaijan Flag","keywords":["az","nation","country","banner"],"skins":[{"unified":"1f1e6-1f1ff","native":"🇦🇿"}],"version":2},"flag-ba":{"id":"flag-ba","name":"Bosnia & Herzegovina Flag","keywords":["ba","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1e6","native":"🇧🇦"}],"version":2},"flag-bb":{"id":"flag-bb","name":"Barbados Flag","keywords":["bb","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1e7","native":"🇧🇧"}],"version":2},"flag-bd":{"id":"flag-bd","name":"Bangladesh Flag","keywords":["bd","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1e9","native":"🇧🇩"}],"version":2},"flag-be":{"id":"flag-be","name":"Belgium Flag","keywords":["be","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1ea","native":"🇧🇪"}],"version":2},"flag-bf":{"id":"flag-bf","name":"Burkina Faso Flag","keywords":["bf","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1eb","native":"🇧🇫"}],"version":2},"flag-bg":{"id":"flag-bg","name":"Bulgaria Flag","keywords":["bg","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1ec","native":"🇧🇬"}],"version":2},"flag-bh":{"id":"flag-bh","name":"Bahrain Flag","keywords":["bh","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1ed","native":"🇧🇭"}],"version":2},"flag-bi":{"id":"flag-bi","name":"Burundi Flag","keywords":["bi","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1ee","native":"🇧🇮"}],"version":2},"flag-bj":{"id":"flag-bj","name":"Benin Flag","keywords":["bj","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1ef","native":"🇧🇯"}],"version":2},"flag-bl":{"id":"flag-bl","name":"St. Barthélemy Flag","keywords":["bl","st","barthelemy","saint","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1f1","native":"🇧🇱"}],"version":2},"flag-bm":{"id":"flag-bm","name":"Bermuda Flag","keywords":["bm","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1f2","native":"🇧🇲"}],"version":2},"flag-bn":{"id":"flag-bn","name":"Brunei Flag","keywords":["bn","darussalam","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1f3","native":"🇧🇳"}],"version":2},"flag-bo":{"id":"flag-bo","name":"Bolivia Flag","keywords":["bo","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1f4","native":"🇧🇴"}],"version":2},"flag-bq":{"id":"flag-bq","name":"Caribbean Netherlands Flag","keywords":["bq","bonaire","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1f6","native":"🇧🇶"}],"version":2},"flag-br":{"id":"flag-br","name":"Brazil Flag","keywords":["br","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1f7","native":"🇧🇷"}],"version":2},"flag-bs":{"id":"flag-bs","name":"Bahamas Flag","keywords":["bs","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1f8","native":"🇧🇸"}],"version":2},"flag-bt":{"id":"flag-bt","name":"Bhutan Flag","keywords":["bt","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1f9","native":"🇧🇹"}],"version":2},"flag-bv":{"id":"flag-bv","name":"Bouvet Island Flag","keywords":["bv","norway"],"skins":[{"unified":"1f1e7-1f1fb","native":"🇧🇻"}],"version":2},"flag-bw":{"id":"flag-bw","name":"Botswana Flag","keywords":["bw","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1fc","native":"🇧🇼"}],"version":2},"flag-by":{"id":"flag-by","name":"Belarus Flag","keywords":["by","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1fe","native":"🇧🇾"}],"version":2},"flag-bz":{"id":"flag-bz","name":"Belize Flag","keywords":["bz","nation","country","banner"],"skins":[{"unified":"1f1e7-1f1ff","native":"🇧🇿"}],"version":2},"flag-ca":{"id":"flag-ca","name":"Canada Flag","keywords":["ca","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1e6","native":"🇨🇦"}],"version":2},"flag-cc":{"id":"flag-cc","name":"Cocos (keeling) Islands Flag","keywords":["cc","keeling","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1e8","native":"🇨🇨"}],"version":2},"flag-cd":{"id":"flag-cd","name":"Congo - Kinshasa Flag","keywords":["cd","democratic","republic","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1e9","native":"🇨🇩"}],"version":2},"flag-cf":{"id":"flag-cf","name":"Central African Republic Flag","keywords":["cf","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1eb","native":"🇨🇫"}],"version":2},"flag-cg":{"id":"flag-cg","name":"Congo - Brazzaville Flag","keywords":["cg","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1ec","native":"🇨🇬"}],"version":2},"flag-ch":{"id":"flag-ch","name":"Switzerland Flag","keywords":["ch","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1ed","native":"🇨🇭"}],"version":2},"flag-ci":{"id":"flag-ci","name":"Côte D’ivoire Flag","keywords":["ci","cote","d","ivoire","ivory","coast","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1ee","native":"🇨🇮"}],"version":2},"flag-ck":{"id":"flag-ck","name":"Cook Islands Flag","keywords":["ck","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1f0","native":"🇨🇰"}],"version":2},"flag-cl":{"id":"flag-cl","name":"Chile Flag","keywords":["cl","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1f1","native":"🇨🇱"}],"version":2},"flag-cm":{"id":"flag-cm","name":"Cameroon Flag","keywords":["cm","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1f2","native":"🇨🇲"}],"version":2},"cn":{"id":"cn","name":"China Flag","keywords":["cn","chinese","prc","country","nation","banner"],"skins":[{"unified":"1f1e8-1f1f3","native":"🇨🇳"}],"version":1},"flag-co":{"id":"flag-co","name":"Colombia Flag","keywords":["co","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1f4","native":"🇨🇴"}],"version":2},"flag-cp":{"id":"flag-cp","name":"Clipperton Island Flag","keywords":["cp"],"skins":[{"unified":"1f1e8-1f1f5","native":"🇨🇵"}],"version":2},"flag-cr":{"id":"flag-cr","name":"Costa Rica Flag","keywords":["cr","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1f7","native":"🇨🇷"}],"version":2},"flag-cu":{"id":"flag-cu","name":"Cuba Flag","keywords":["cu","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1fa","native":"🇨🇺"}],"version":2},"flag-cv":{"id":"flag-cv","name":"Cape Verde Flag","keywords":["cv","cabo","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1fb","native":"🇨🇻"}],"version":2},"flag-cw":{"id":"flag-cw","name":"Curaçao Flag","keywords":["cw","curacao","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1fc","native":"🇨🇼"}],"version":2},"flag-cx":{"id":"flag-cx","name":"Christmas Island Flag","keywords":["cx","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1fd","native":"🇨🇽"}],"version":2},"flag-cy":{"id":"flag-cy","name":"Cyprus Flag","keywords":["cy","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1fe","native":"🇨🇾"}],"version":2},"flag-cz":{"id":"flag-cz","name":"Czechia Flag","keywords":["cz","nation","country","banner"],"skins":[{"unified":"1f1e8-1f1ff","native":"🇨🇿"}],"version":2},"de":{"id":"de","name":"Germany Flag","keywords":["de","german","nation","country","banner"],"skins":[{"unified":"1f1e9-1f1ea","native":"🇩🇪"}],"version":1},"flag-dg":{"id":"flag-dg","name":"Diego Garcia Flag","keywords":["dg"],"skins":[{"unified":"1f1e9-1f1ec","native":"🇩🇬"}],"version":2},"flag-dj":{"id":"flag-dj","name":"Djibouti Flag","keywords":["dj","nation","country","banner"],"skins":[{"unified":"1f1e9-1f1ef","native":"🇩🇯"}],"version":2},"flag-dk":{"id":"flag-dk","name":"Denmark Flag","keywords":["dk","nation","country","banner"],"skins":[{"unified":"1f1e9-1f1f0","native":"🇩🇰"}],"version":2},"flag-dm":{"id":"flag-dm","name":"Dominica Flag","keywords":["dm","nation","country","banner"],"skins":[{"unified":"1f1e9-1f1f2","native":"🇩🇲"}],"version":2},"flag-do":{"id":"flag-do","name":"Dominican Republic Flag","keywords":["do","nation","country","banner"],"skins":[{"unified":"1f1e9-1f1f4","native":"🇩🇴"}],"version":2},"flag-dz":{"id":"flag-dz","name":"Algeria Flag","keywords":["dz","nation","country","banner"],"skins":[{"unified":"1f1e9-1f1ff","native":"🇩🇿"}],"version":2},"flag-ea":{"id":"flag-ea","name":"Ceuta & Melilla Flag","keywords":["ea"],"skins":[{"unified":"1f1ea-1f1e6","native":"🇪🇦"}],"version":2},"flag-ec":{"id":"flag-ec","name":"Ecuador Flag","keywords":["ec","nation","country","banner"],"skins":[{"unified":"1f1ea-1f1e8","native":"🇪🇨"}],"version":2},"flag-ee":{"id":"flag-ee","name":"Estonia Flag","keywords":["ee","nation","country","banner"],"skins":[{"unified":"1f1ea-1f1ea","native":"🇪🇪"}],"version":2},"flag-eg":{"id":"flag-eg","name":"Egypt Flag","keywords":["eg","nation","country","banner"],"skins":[{"unified":"1f1ea-1f1ec","native":"🇪🇬"}],"version":2},"flag-eh":{"id":"flag-eh","name":"Western Sahara Flag","keywords":["eh","nation","country","banner"],"skins":[{"unified":"1f1ea-1f1ed","native":"🇪🇭"}],"version":2},"flag-er":{"id":"flag-er","name":"Eritrea Flag","keywords":["er","nation","country","banner"],"skins":[{"unified":"1f1ea-1f1f7","native":"🇪🇷"}],"version":2},"es":{"id":"es","name":"Spain Flag","keywords":["es","nation","country","banner"],"skins":[{"unified":"1f1ea-1f1f8","native":"🇪🇸"}],"version":1},"flag-et":{"id":"flag-et","name":"Ethiopia Flag","keywords":["et","nation","country","banner"],"skins":[{"unified":"1f1ea-1f1f9","native":"🇪🇹"}],"version":2},"flag-eu":{"id":"flag-eu","name":"European Union Flag","keywords":["eu","banner"],"skins":[{"unified":"1f1ea-1f1fa","native":"🇪🇺"}],"version":2},"flag-fi":{"id":"flag-fi","name":"Finland Flag","keywords":["fi","nation","country","banner"],"skins":[{"unified":"1f1eb-1f1ee","native":"🇫🇮"}],"version":2},"flag-fj":{"id":"flag-fj","name":"Fiji Flag","keywords":["fj","nation","country","banner"],"skins":[{"unified":"1f1eb-1f1ef","native":"🇫🇯"}],"version":2},"flag-fk":{"id":"flag-fk","name":"Falkland Islands Flag","keywords":["fk","malvinas","nation","country","banner"],"skins":[{"unified":"1f1eb-1f1f0","native":"🇫🇰"}],"version":2},"flag-fm":{"id":"flag-fm","name":"Micronesia Flag","keywords":["fm","federated","states","nation","country","banner"],"skins":[{"unified":"1f1eb-1f1f2","native":"🇫🇲"}],"version":2},"flag-fo":{"id":"flag-fo","name":"Faroe Islands Flag","keywords":["fo","nation","country","banner"],"skins":[{"unified":"1f1eb-1f1f4","native":"🇫🇴"}],"version":2},"fr":{"id":"fr","name":"France Flag","keywords":["fr","banner","nation","french","country"],"skins":[{"unified":"1f1eb-1f1f7","native":"🇫🇷"}],"version":1},"flag-ga":{"id":"flag-ga","name":"Gabon Flag","keywords":["ga","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1e6","native":"🇬🇦"}],"version":2},"gb":{"id":"gb","name":"United Kingdom Flag","keywords":["gb","uk","great","britain","northern","ireland","nation","country","banner","british","UK","english","england","union","jack"],"skins":[{"unified":"1f1ec-1f1e7","native":"🇬🇧"}],"version":1},"flag-gd":{"id":"flag-gd","name":"Grenada Flag","keywords":["gd","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1e9","native":"🇬🇩"}],"version":2},"flag-ge":{"id":"flag-ge","name":"Georgia Flag","keywords":["ge","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1ea","native":"🇬🇪"}],"version":2},"flag-gf":{"id":"flag-gf","name":"French Guiana Flag","keywords":["gf","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1eb","native":"🇬🇫"}],"version":2},"flag-gg":{"id":"flag-gg","name":"Guernsey Flag","keywords":["gg","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1ec","native":"🇬🇬"}],"version":2},"flag-gh":{"id":"flag-gh","name":"Ghana Flag","keywords":["gh","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1ed","native":"🇬🇭"}],"version":2},"flag-gi":{"id":"flag-gi","name":"Gibraltar Flag","keywords":["gi","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1ee","native":"🇬🇮"}],"version":2},"flag-gl":{"id":"flag-gl","name":"Greenland Flag","keywords":["gl","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1f1","native":"🇬🇱"}],"version":2},"flag-gm":{"id":"flag-gm","name":"Gambia Flag","keywords":["gm","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1f2","native":"🇬🇲"}],"version":2},"flag-gn":{"id":"flag-gn","name":"Guinea Flag","keywords":["gn","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1f3","native":"🇬🇳"}],"version":2},"flag-gp":{"id":"flag-gp","name":"Guadeloupe Flag","keywords":["gp","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1f5","native":"🇬🇵"}],"version":2},"flag-gq":{"id":"flag-gq","name":"Equatorial Guinea Flag","keywords":["gq","gn","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1f6","native":"🇬🇶"}],"version":2},"flag-gr":{"id":"flag-gr","name":"Greece Flag","keywords":["gr","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1f7","native":"🇬🇷"}],"version":2},"flag-gs":{"id":"flag-gs","name":"South Georgia & South Sandwich Islands Flag","keywords":["gs","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1f8","native":"🇬🇸"}],"version":2},"flag-gt":{"id":"flag-gt","name":"Guatemala Flag","keywords":["gt","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1f9","native":"🇬🇹"}],"version":2},"flag-gu":{"id":"flag-gu","name":"Guam Flag","keywords":["gu","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1fa","native":"🇬🇺"}],"version":2},"flag-gw":{"id":"flag-gw","name":"Guinea-Bissau Flag","keywords":["gw","guinea","bissau","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1fc","native":"🇬🇼"}],"version":2},"flag-gy":{"id":"flag-gy","name":"Guyana Flag","keywords":["gy","nation","country","banner"],"skins":[{"unified":"1f1ec-1f1fe","native":"🇬🇾"}],"version":2},"flag-hk":{"id":"flag-hk","name":"Hong Kong Sar China Flag","keywords":["hk","nation","country","banner"],"skins":[{"unified":"1f1ed-1f1f0","native":"🇭🇰"}],"version":2},"flag-hm":{"id":"flag-hm","name":"Heard & Mcdonald Islands Flag","keywords":["hm"],"skins":[{"unified":"1f1ed-1f1f2","native":"🇭🇲"}],"version":2},"flag-hn":{"id":"flag-hn","name":"Honduras Flag","keywords":["hn","nation","country","banner"],"skins":[{"unified":"1f1ed-1f1f3","native":"🇭🇳"}],"version":2},"flag-hr":{"id":"flag-hr","name":"Croatia Flag","keywords":["hr","nation","country","banner"],"skins":[{"unified":"1f1ed-1f1f7","native":"🇭🇷"}],"version":2},"flag-ht":{"id":"flag-ht","name":"Haiti Flag","keywords":["ht","nation","country","banner"],"skins":[{"unified":"1f1ed-1f1f9","native":"🇭🇹"}],"version":2},"flag-hu":{"id":"flag-hu","name":"Hungary Flag","keywords":["hu","nation","country","banner"],"skins":[{"unified":"1f1ed-1f1fa","native":"🇭🇺"}],"version":2},"flag-ic":{"id":"flag-ic","name":"Canary Islands Flag","keywords":["ic","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1e8","native":"🇮🇨"}],"version":2},"flag-id":{"id":"flag-id","name":"Indonesia Flag","keywords":["id","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1e9","native":"🇮🇩"}],"version":2},"flag-ie":{"id":"flag-ie","name":"Ireland Flag","keywords":["ie","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1ea","native":"🇮🇪"}],"version":2},"flag-il":{"id":"flag-il","name":"Israel Flag","keywords":["il","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1f1","native":"🇮🇱"}],"version":2},"flag-im":{"id":"flag-im","name":"Isle of Man Flag","keywords":["im","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1f2","native":"🇮🇲"}],"version":2},"flag-in":{"id":"flag-in","name":"India Flag","keywords":["in","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1f3","native":"🇮🇳"}],"version":2},"flag-io":{"id":"flag-io","name":"British Indian Ocean Territory Flag","keywords":["io","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1f4","native":"🇮🇴"}],"version":2},"flag-iq":{"id":"flag-iq","name":"Iraq Flag","keywords":["iq","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1f6","native":"🇮🇶"}],"version":2},"flag-ir":{"id":"flag-ir","name":"Iran Flag","keywords":["ir","islamic","republic","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1f7","native":"🇮🇷"}],"version":2},"flag-is":{"id":"flag-is","name":"Iceland Flag","keywords":["is","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1f8","native":"🇮🇸"}],"version":2},"it":{"id":"it","name":"Italy Flag","keywords":["it","nation","country","banner"],"skins":[{"unified":"1f1ee-1f1f9","native":"🇮🇹"}],"version":1},"flag-je":{"id":"flag-je","name":"Jersey Flag","keywords":["je","nation","country","banner"],"skins":[{"unified":"1f1ef-1f1ea","native":"🇯🇪"}],"version":2},"flag-jm":{"id":"flag-jm","name":"Jamaica Flag","keywords":["jm","nation","country","banner"],"skins":[{"unified":"1f1ef-1f1f2","native":"🇯🇲"}],"version":2},"flag-jo":{"id":"flag-jo","name":"Jordan Flag","keywords":["jo","nation","country","banner"],"skins":[{"unified":"1f1ef-1f1f4","native":"🇯🇴"}],"version":2},"jp":{"id":"jp","name":"Japan Flag","keywords":["jp","japanese","nation","country","banner","ja"],"skins":[{"unified":"1f1ef-1f1f5","native":"🇯🇵"}],"version":1},"flag-ke":{"id":"flag-ke","name":"Kenya Flag","keywords":["ke","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1ea","native":"🇰🇪"}],"version":2},"flag-kg":{"id":"flag-kg","name":"Kyrgyzstan Flag","keywords":["kg","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1ec","native":"🇰🇬"}],"version":2},"flag-kh":{"id":"flag-kh","name":"Cambodia Flag","keywords":["kh","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1ed","native":"🇰🇭"}],"version":2},"flag-ki":{"id":"flag-ki","name":"Kiribati Flag","keywords":["ki","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1ee","native":"🇰🇮"}],"version":2},"flag-km":{"id":"flag-km","name":"Comoros Flag","keywords":["km","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1f2","native":"🇰🇲"}],"version":2},"flag-kn":{"id":"flag-kn","name":"St. Kitts & Nevis Flag","keywords":["kn","st","saint","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1f3","native":"🇰🇳"}],"version":2},"flag-kp":{"id":"flag-kp","name":"North Korea Flag","keywords":["kp","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1f5","native":"🇰🇵"}],"version":2},"kr":{"id":"kr","name":"South Korea Flag","keywords":["kr","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1f7","native":"🇰🇷"}],"version":1},"flag-kw":{"id":"flag-kw","name":"Kuwait Flag","keywords":["kw","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1fc","native":"🇰🇼"}],"version":2},"flag-ky":{"id":"flag-ky","name":"Cayman Islands Flag","keywords":["ky","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1fe","native":"🇰🇾"}],"version":2},"flag-kz":{"id":"flag-kz","name":"Kazakhstan Flag","keywords":["kz","nation","country","banner"],"skins":[{"unified":"1f1f0-1f1ff","native":"🇰🇿"}],"version":2},"flag-la":{"id":"flag-la","name":"Laos Flag","keywords":["la","lao","democratic","republic","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1e6","native":"🇱🇦"}],"version":2},"flag-lb":{"id":"flag-lb","name":"Lebanon Flag","keywords":["lb","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1e7","native":"🇱🇧"}],"version":2},"flag-lc":{"id":"flag-lc","name":"St. Lucia Flag","keywords":["lc","st","saint","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1e8","native":"🇱🇨"}],"version":2},"flag-li":{"id":"flag-li","name":"Liechtenstein Flag","keywords":["li","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1ee","native":"🇱🇮"}],"version":2},"flag-lk":{"id":"flag-lk","name":"Sri Lanka Flag","keywords":["lk","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1f0","native":"🇱🇰"}],"version":2},"flag-lr":{"id":"flag-lr","name":"Liberia Flag","keywords":["lr","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1f7","native":"🇱🇷"}],"version":2},"flag-ls":{"id":"flag-ls","name":"Lesotho Flag","keywords":["ls","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1f8","native":"🇱🇸"}],"version":2},"flag-lt":{"id":"flag-lt","name":"Lithuania Flag","keywords":["lt","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1f9","native":"🇱🇹"}],"version":2},"flag-lu":{"id":"flag-lu","name":"Luxembourg Flag","keywords":["lu","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1fa","native":"🇱🇺"}],"version":2},"flag-lv":{"id":"flag-lv","name":"Latvia Flag","keywords":["lv","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1fb","native":"🇱🇻"}],"version":2},"flag-ly":{"id":"flag-ly","name":"Libya Flag","keywords":["ly","nation","country","banner"],"skins":[{"unified":"1f1f1-1f1fe","native":"🇱🇾"}],"version":2},"flag-ma":{"id":"flag-ma","name":"Morocco Flag","keywords":["ma","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1e6","native":"🇲🇦"}],"version":2},"flag-mc":{"id":"flag-mc","name":"Monaco Flag","keywords":["mc","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1e8","native":"🇲🇨"}],"version":2},"flag-md":{"id":"flag-md","name":"Moldova Flag","keywords":["md","republic","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1e9","native":"🇲🇩"}],"version":2},"flag-me":{"id":"flag-me","name":"Montenegro Flag","keywords":["me","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1ea","native":"🇲🇪"}],"version":2},"flag-mf":{"id":"flag-mf","name":"St. Martin Flag","keywords":["mf","st"],"skins":[{"unified":"1f1f2-1f1eb","native":"🇲🇫"}],"version":2},"flag-mg":{"id":"flag-mg","name":"Madagascar Flag","keywords":["mg","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1ec","native":"🇲🇬"}],"version":2},"flag-mh":{"id":"flag-mh","name":"Marshall Islands Flag","keywords":["mh","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1ed","native":"🇲🇭"}],"version":2},"flag-mk":{"id":"flag-mk","name":"North Macedonia Flag","keywords":["mk","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f0","native":"🇲🇰"}],"version":2},"flag-ml":{"id":"flag-ml","name":"Mali Flag","keywords":["ml","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f1","native":"🇲🇱"}],"version":2},"flag-mm":{"id":"flag-mm","name":"Myanmar (burma) Flag","keywords":["mm","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f2","native":"🇲🇲"}],"version":2},"flag-mn":{"id":"flag-mn","name":"Mongolia Flag","keywords":["mn","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f3","native":"🇲🇳"}],"version":2},"flag-mo":{"id":"flag-mo","name":"Macao Sar China Flag","keywords":["mo","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f4","native":"🇲🇴"}],"version":2},"flag-mp":{"id":"flag-mp","name":"Northern Mariana Islands Flag","keywords":["mp","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f5","native":"🇲🇵"}],"version":2},"flag-mq":{"id":"flag-mq","name":"Martinique Flag","keywords":["mq","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f6","native":"🇲🇶"}],"version":2},"flag-mr":{"id":"flag-mr","name":"Mauritania Flag","keywords":["mr","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f7","native":"🇲🇷"}],"version":2},"flag-ms":{"id":"flag-ms","name":"Montserrat Flag","keywords":["ms","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f8","native":"🇲🇸"}],"version":2},"flag-mt":{"id":"flag-mt","name":"Malta Flag","keywords":["mt","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1f9","native":"🇲🇹"}],"version":2},"flag-mu":{"id":"flag-mu","name":"Mauritius Flag","keywords":["mu","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1fa","native":"🇲🇺"}],"version":2},"flag-mv":{"id":"flag-mv","name":"Maldives Flag","keywords":["mv","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1fb","native":"🇲🇻"}],"version":2},"flag-mw":{"id":"flag-mw","name":"Malawi Flag","keywords":["mw","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1fc","native":"🇲🇼"}],"version":2},"flag-mx":{"id":"flag-mx","name":"Mexico Flag","keywords":["mx","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1fd","native":"🇲🇽"}],"version":2},"flag-my":{"id":"flag-my","name":"Malaysia Flag","keywords":["my","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1fe","native":"🇲🇾"}],"version":2},"flag-mz":{"id":"flag-mz","name":"Mozambique Flag","keywords":["mz","nation","country","banner"],"skins":[{"unified":"1f1f2-1f1ff","native":"🇲🇿"}],"version":2},"flag-na":{"id":"flag-na","name":"Namibia Flag","keywords":["na","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1e6","native":"🇳🇦"}],"version":2},"flag-nc":{"id":"flag-nc","name":"New Caledonia Flag","keywords":["nc","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1e8","native":"🇳🇨"}],"version":2},"flag-ne":{"id":"flag-ne","name":"Niger Flag","keywords":["ne","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1ea","native":"🇳🇪"}],"version":2},"flag-nf":{"id":"flag-nf","name":"Norfolk Island Flag","keywords":["nf","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1eb","native":"🇳🇫"}],"version":2},"flag-ng":{"id":"flag-ng","name":"Nigeria Flag","keywords":["ng","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1ec","native":"🇳🇬"}],"version":2},"flag-ni":{"id":"flag-ni","name":"Nicaragua Flag","keywords":["ni","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1ee","native":"🇳🇮"}],"version":2},"flag-nl":{"id":"flag-nl","name":"Netherlands Flag","keywords":["nl","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1f1","native":"🇳🇱"}],"version":2},"flag-no":{"id":"flag-no","name":"Norway Flag","keywords":["no","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1f4","native":"🇳🇴"}],"version":2},"flag-np":{"id":"flag-np","name":"Nepal Flag","keywords":["np","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1f5","native":"🇳🇵"}],"version":2},"flag-nr":{"id":"flag-nr","name":"Nauru Flag","keywords":["nr","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1f7","native":"🇳🇷"}],"version":2},"flag-nu":{"id":"flag-nu","name":"Niue Flag","keywords":["nu","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1fa","native":"🇳🇺"}],"version":2},"flag-nz":{"id":"flag-nz","name":"New Zealand Flag","keywords":["nz","nation","country","banner"],"skins":[{"unified":"1f1f3-1f1ff","native":"🇳🇿"}],"version":2},"flag-om":{"id":"flag-om","name":"Oman Flag","keywords":["om","symbol","nation","country","banner"],"skins":[{"unified":"1f1f4-1f1f2","native":"🇴🇲"}],"version":2},"flag-pa":{"id":"flag-pa","name":"Panama Flag","keywords":["pa","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1e6","native":"🇵🇦"}],"version":2},"flag-pe":{"id":"flag-pe","name":"Peru Flag","keywords":["pe","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1ea","native":"🇵🇪"}],"version":2},"flag-pf":{"id":"flag-pf","name":"French Polynesia Flag","keywords":["pf","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1eb","native":"🇵🇫"}],"version":2},"flag-pg":{"id":"flag-pg","name":"Papua New Guinea Flag","keywords":["pg","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1ec","native":"🇵🇬"}],"version":2},"flag-ph":{"id":"flag-ph","name":"Philippines Flag","keywords":["ph","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1ed","native":"🇵🇭"}],"version":2},"flag-pk":{"id":"flag-pk","name":"Pakistan Flag","keywords":["pk","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1f0","native":"🇵🇰"}],"version":2},"flag-pl":{"id":"flag-pl","name":"Poland Flag","keywords":["pl","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1f1","native":"🇵🇱"}],"version":2},"flag-pm":{"id":"flag-pm","name":"St. Pierre & Miquelon Flag","keywords":["pm","st","saint","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1f2","native":"🇵🇲"}],"version":2},"flag-pn":{"id":"flag-pn","name":"Pitcairn Islands Flag","keywords":["pn","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1f3","native":"🇵🇳"}],"version":2},"flag-pr":{"id":"flag-pr","name":"Puerto Rico Flag","keywords":["pr","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1f7","native":"🇵🇷"}],"version":2},"flag-ps":{"id":"flag-ps","name":"Palestinian Territories Flag","keywords":["ps","palestine","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1f8","native":"🇵🇸"}],"version":2},"flag-pt":{"id":"flag-pt","name":"Portugal Flag","keywords":["pt","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1f9","native":"🇵🇹"}],"version":2},"flag-pw":{"id":"flag-pw","name":"Palau Flag","keywords":["pw","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1fc","native":"🇵🇼"}],"version":2},"flag-py":{"id":"flag-py","name":"Paraguay Flag","keywords":["py","nation","country","banner"],"skins":[{"unified":"1f1f5-1f1fe","native":"🇵🇾"}],"version":2},"flag-qa":{"id":"flag-qa","name":"Qatar Flag","keywords":["qa","nation","country","banner"],"skins":[{"unified":"1f1f6-1f1e6","native":"🇶🇦"}],"version":2},"flag-re":{"id":"flag-re","name":"Réunion Flag","keywords":["re","reunion","nation","country","banner"],"skins":[{"unified":"1f1f7-1f1ea","native":"🇷🇪"}],"version":2},"flag-ro":{"id":"flag-ro","name":"Romania Flag","keywords":["ro","nation","country","banner"],"skins":[{"unified":"1f1f7-1f1f4","native":"🇷🇴"}],"version":2},"flag-rs":{"id":"flag-rs","name":"Serbia Flag","keywords":["rs","nation","country","banner"],"skins":[{"unified":"1f1f7-1f1f8","native":"🇷🇸"}],"version":2},"ru":{"id":"ru","name":"Russia Flag","keywords":["ru","russian","federation","nation","country","banner"],"skins":[{"unified":"1f1f7-1f1fa","native":"🇷🇺"}],"version":1},"flag-rw":{"id":"flag-rw","name":"Rwanda Flag","keywords":["rw","nation","country","banner"],"skins":[{"unified":"1f1f7-1f1fc","native":"🇷🇼"}],"version":2},"flag-sa":{"id":"flag-sa","name":"Saudi Arabia Flag","keywords":["sa","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1e6","native":"🇸🇦"}],"version":2},"flag-sb":{"id":"flag-sb","name":"Solomon Islands Flag","keywords":["sb","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1e7","native":"🇸🇧"}],"version":2},"flag-sc":{"id":"flag-sc","name":"Seychelles Flag","keywords":["sc","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1e8","native":"🇸🇨"}],"version":2},"flag-sd":{"id":"flag-sd","name":"Sudan Flag","keywords":["sd","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1e9","native":"🇸🇩"}],"version":2},"flag-se":{"id":"flag-se","name":"Sweden Flag","keywords":["se","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1ea","native":"🇸🇪"}],"version":2},"flag-sg":{"id":"flag-sg","name":"Singapore Flag","keywords":["sg","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1ec","native":"🇸🇬"}],"version":2},"flag-sh":{"id":"flag-sh","name":"St. Helena Flag","keywords":["sh","st","saint","ascension","tristan","cunha","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1ed","native":"🇸🇭"}],"version":2},"flag-si":{"id":"flag-si","name":"Slovenia Flag","keywords":["si","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1ee","native":"🇸🇮"}],"version":2},"flag-sj":{"id":"flag-sj","name":"Svalbard & Jan Mayen Flag","keywords":["sj"],"skins":[{"unified":"1f1f8-1f1ef","native":"🇸🇯"}],"version":2},"flag-sk":{"id":"flag-sk","name":"Slovakia Flag","keywords":["sk","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1f0","native":"🇸🇰"}],"version":2},"flag-sl":{"id":"flag-sl","name":"Sierra Leone Flag","keywords":["sl","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1f1","native":"🇸🇱"}],"version":2},"flag-sm":{"id":"flag-sm","name":"San Marino Flag","keywords":["sm","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1f2","native":"🇸🇲"}],"version":2},"flag-sn":{"id":"flag-sn","name":"Senegal Flag","keywords":["sn","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1f3","native":"🇸🇳"}],"version":2},"flag-so":{"id":"flag-so","name":"Somalia Flag","keywords":["so","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1f4","native":"🇸🇴"}],"version":2},"flag-sr":{"id":"flag-sr","name":"Suriname Flag","keywords":["sr","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1f7","native":"🇸🇷"}],"version":2},"flag-ss":{"id":"flag-ss","name":"South Sudan Flag","keywords":["ss","sd","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1f8","native":"🇸🇸"}],"version":2},"flag-st":{"id":"flag-st","name":"São Tomé & Príncipe Flag","keywords":["st","sao","tome","principe","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1f9","native":"🇸🇹"}],"version":2},"flag-sv":{"id":"flag-sv","name":"El Salvador Flag","keywords":["sv","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1fb","native":"🇸🇻"}],"version":2},"flag-sx":{"id":"flag-sx","name":"Sint Maarten Flag","keywords":["sx","dutch","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1fd","native":"🇸🇽"}],"version":2},"flag-sy":{"id":"flag-sy","name":"Syria Flag","keywords":["sy","syrian","arab","republic","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1fe","native":"🇸🇾"}],"version":2},"flag-sz":{"id":"flag-sz","name":"Eswatini Flag","keywords":["sz","nation","country","banner"],"skins":[{"unified":"1f1f8-1f1ff","native":"🇸🇿"}],"version":2},"flag-ta":{"id":"flag-ta","name":"Tristan Da Cunha Flag","keywords":["ta"],"skins":[{"unified":"1f1f9-1f1e6","native":"🇹🇦"}],"version":2},"flag-tc":{"id":"flag-tc","name":"Turks & Caicos Islands Flag","keywords":["tc","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1e8","native":"🇹🇨"}],"version":2},"flag-td":{"id":"flag-td","name":"Chad Flag","keywords":["td","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1e9","native":"🇹🇩"}],"version":2},"flag-tf":{"id":"flag-tf","name":"French Southern Territories Flag","keywords":["tf","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1eb","native":"🇹🇫"}],"version":2},"flag-tg":{"id":"flag-tg","name":"Togo Flag","keywords":["tg","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1ec","native":"🇹🇬"}],"version":2},"flag-th":{"id":"flag-th","name":"Thailand Flag","keywords":["th","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1ed","native":"🇹🇭"}],"version":2},"flag-tj":{"id":"flag-tj","name":"Tajikistan Flag","keywords":["tj","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1ef","native":"🇹🇯"}],"version":2},"flag-tk":{"id":"flag-tk","name":"Tokelau Flag","keywords":["tk","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1f0","native":"🇹🇰"}],"version":2},"flag-tl":{"id":"flag-tl","name":"Timor-Leste Flag","keywords":["tl","timor","leste","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1f1","native":"🇹🇱"}],"version":2},"flag-tm":{"id":"flag-tm","name":"Turkmenistan Flag","keywords":["tm","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1f2","native":"🇹🇲"}],"version":2},"flag-tn":{"id":"flag-tn","name":"Tunisia Flag","keywords":["tn","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1f3","native":"🇹🇳"}],"version":2},"flag-to":{"id":"flag-to","name":"Tonga Flag","keywords":["to","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1f4","native":"🇹🇴"}],"version":2},"flag-tr":{"id":"flag-tr","name":"Turkey Flag","keywords":["tr","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1f7","native":"🇹🇷"}],"version":2},"flag-tt":{"id":"flag-tt","name":"Trinidad & Tobago Flag","keywords":["tt","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1f9","native":"🇹🇹"}],"version":2},"flag-tv":{"id":"flag-tv","name":"Tuvalu Flag","keywords":["tv","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1fb","native":"🇹🇻"}],"version":2},"flag-tw":{"id":"flag-tw","name":"Taiwan Flag","keywords":["tw","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1fc","native":"🇹🇼"}],"version":2},"flag-tz":{"id":"flag-tz","name":"Tanzania Flag","keywords":["tz","united","republic","nation","country","banner"],"skins":[{"unified":"1f1f9-1f1ff","native":"🇹🇿"}],"version":2},"flag-ua":{"id":"flag-ua","name":"Ukraine Flag","keywords":["ua","nation","country","banner"],"skins":[{"unified":"1f1fa-1f1e6","native":"🇺🇦"}],"version":2},"flag-ug":{"id":"flag-ug","name":"Uganda Flag","keywords":["ug","nation","country","banner"],"skins":[{"unified":"1f1fa-1f1ec","native":"🇺🇬"}],"version":2},"flag-um":{"id":"flag-um","name":"U.s. Outlying Islands Flag","keywords":["um","u","s"],"skins":[{"unified":"1f1fa-1f1f2","native":"🇺🇲"}],"version":2},"flag-un":{"id":"flag-un","name":"United Nations Flag","keywords":["un","banner"],"skins":[{"unified":"1f1fa-1f1f3","native":"🇺🇳"}],"version":4},"us":{"id":"us","name":"United States Flag","keywords":["us","america","nation","country","banner"],"skins":[{"unified":"1f1fa-1f1f8","native":"🇺🇸"}],"version":1},"flag-uy":{"id":"flag-uy","name":"Uruguay Flag","keywords":["uy","nation","country","banner"],"skins":[{"unified":"1f1fa-1f1fe","native":"🇺🇾"}],"version":2},"flag-uz":{"id":"flag-uz","name":"Uzbekistan Flag","keywords":["uz","nation","country","banner"],"skins":[{"unified":"1f1fa-1f1ff","native":"🇺🇿"}],"version":2},"flag-va":{"id":"flag-va","name":"Vatican City Flag","keywords":["va","nation","country","banner"],"skins":[{"unified":"1f1fb-1f1e6","native":"🇻🇦"}],"version":2},"flag-vc":{"id":"flag-vc","name":"St. Vincent & Grenadines Flag","keywords":["vc","st","saint","nation","country","banner"],"skins":[{"unified":"1f1fb-1f1e8","native":"🇻🇨"}],"version":2},"flag-ve":{"id":"flag-ve","name":"Venezuela Flag","keywords":["ve","bolivarian","republic","nation","country","banner"],"skins":[{"unified":"1f1fb-1f1ea","native":"🇻🇪"}],"version":2},"flag-vg":{"id":"flag-vg","name":"British Virgin Islands Flag","keywords":["vg","bvi","nation","country","banner"],"skins":[{"unified":"1f1fb-1f1ec","native":"🇻🇬"}],"version":2},"flag-vi":{"id":"flag-vi","name":"U.s. Virgin Islands Flag","keywords":["vi","u","s","us","nation","country","banner"],"skins":[{"unified":"1f1fb-1f1ee","native":"🇻🇮"}],"version":2},"flag-vn":{"id":"flag-vn","name":"Vietnam Flag","keywords":["vn","viet","nam","nation","country","banner"],"skins":[{"unified":"1f1fb-1f1f3","native":"🇻🇳"}],"version":2},"flag-vu":{"id":"flag-vu","name":"Vanuatu Flag","keywords":["vu","nation","country","banner"],"skins":[{"unified":"1f1fb-1f1fa","native":"🇻🇺"}],"version":2},"flag-wf":{"id":"flag-wf","name":"Wallis & Futuna Flag","keywords":["wf","nation","country","banner"],"skins":[{"unified":"1f1fc-1f1eb","native":"🇼🇫"}],"version":2},"flag-ws":{"id":"flag-ws","name":"Samoa Flag","keywords":["ws","nation","country","banner"],"skins":[{"unified":"1f1fc-1f1f8","native":"🇼🇸"}],"version":2},"flag-xk":{"id":"flag-xk","name":"Kosovo Flag","keywords":["xk","nation","country","banner"],"skins":[{"unified":"1f1fd-1f1f0","native":"🇽🇰"}],"version":2},"flag-ye":{"id":"flag-ye","name":"Yemen Flag","keywords":["ye","nation","country","banner"],"skins":[{"unified":"1f1fe-1f1ea","native":"🇾🇪"}],"version":2},"flag-yt":{"id":"flag-yt","name":"Mayotte Flag","keywords":["yt","nation","country","banner"],"skins":[{"unified":"1f1fe-1f1f9","native":"🇾🇹"}],"version":2},"flag-za":{"id":"flag-za","name":"South Africa Flag","keywords":["za","nation","country","banner"],"skins":[{"unified":"1f1ff-1f1e6","native":"🇿🇦"}],"version":2},"flag-zm":{"id":"flag-zm","name":"Zambia Flag","keywords":["zm","nation","country","banner"],"skins":[{"unified":"1f1ff-1f1f2","native":"🇿🇲"}],"version":2},"flag-zw":{"id":"flag-zw","name":"Zimbabwe Flag","keywords":["zw","nation","country","banner"],"skins":[{"unified":"1f1ff-1f1fc","native":"🇿🇼"}],"version":2},"flag-england":{"id":"flag-england","name":"England Flag","keywords":["english"],"skins":[{"unified":"1f3f4-e0067-e0062-e0065-e006e-e0067-e007f","native":"🏴"}],"version":5},"flag-scotland":{"id":"flag-scotland","name":"Scotland Flag","keywords":["scottish"],"skins":[{"unified":"1f3f4-e0067-e0062-e0073-e0063-e0074-e007f","native":"🏴"}],"version":5},"flag-wales":{"id":"flag-wales","name":"Wales Flag","keywords":["welsh"],"skins":[{"unified":"1f3f4-e0067-e0062-e0077-e006c-e0073-e007f","native":"🏴"}],"version":5}},"aliases":{"satisfied":"laughing","grinning_face_with_star_eyes":"star-struck","grinning_face_with_one_large_and_one_small_eye":"zany_face","smiling_face_with_smiling_eyes_and_hand_covering_mouth":"face_with_hand_over_mouth","face_with_finger_covering_closed_lips":"shushing_face","face_with_one_eyebrow_raised":"face_with_raised_eyebrow","face_with_open_mouth_vomiting":"face_vomiting","shocked_face_with_exploding_head":"exploding_head","serious_face_with_symbols_covering_mouth":"face_with_symbols_on_mouth","poop":"hankey","shit":"hankey","collision":"boom","raised_hand":"hand","hand_with_index_and_middle_fingers_crossed":"crossed_fingers","sign_of_the_horns":"the_horns","reversed_hand_with_middle_finger_extended":"middle_finger","thumbsup":"+1","thumbsdown":"-1","punch":"facepunch","mother_christmas":"mrs_claus","running":"runner","man-with-bunny-ears-partying":"men-with-bunny-ears-partying","woman-with-bunny-ears-partying":"women-with-bunny-ears-partying","women_holding_hands":"two_women_holding_hands","woman_and_man_holding_hands":"man_and_woman_holding_hands","couple":"man_and_woman_holding_hands","men_holding_hands":"two_men_holding_hands","paw_prints":"feet","flipper":"dolphin","honeybee":"bee","lady_beetle":"ladybug","cooking":"fried_egg","knife":"hocho","red_car":"car","sailboat":"boat","waxing_gibbous_moon":"moon","sun_small_cloud":"mostly_sunny","sun_behind_cloud":"barely_sunny","sun_behind_rain_cloud":"partly_sunny_rain","lightning_cloud":"lightning","tornado_cloud":"tornado","tshirt":"shirt","shoe":"mans_shoe","telephone":"phone","lantern":"izakaya_lantern","open_book":"book","envelope":"email","pencil":"memo","heavy_exclamation_mark":"exclamation","staff_of_aesculapius":"medical_symbol","flag-cn":"cn","flag-de":"de","flag-es":"es","flag-fr":"fr","uk":"gb","flag-gb":"gb","flag-it":"it","flag-jp":"jp","flag-kr":"kr","flag-ru":"ru","flag-us":"us"}}
\ No newline at end of file
diff --git a/src/plugins/Emojis/data/filterEmojiData.ts b/src/plugins/Emojis/data/filterEmojiData.ts
new file mode 100644
index 000000000..540471f5e
--- /dev/null
+++ b/src/plugins/Emojis/data/filterEmojiData.ts
@@ -0,0 +1,31 @@
+import type { EmojiData } from './types';
+
+type FilterEmojiDataOptions = {
+ exceptEmojis?: string[];
+};
+
+/**
+ * Returns a dataset with the excluded emoji removed, pruning any category left empty.
+ * Returns the SAME reference when nothing is excluded, so callers memoize cheaply and
+ * the picker renders identically to the unfiltered dataset.
+ */
+export const filterEmojiData = (
+ data: EmojiData,
+ { exceptEmojis = [] }: FilterEmojiDataOptions,
+): EmojiData => {
+ if (!exceptEmojis.length) return data;
+
+ const excluded = new Set(exceptEmojis);
+ const emojis: EmojiData['emojis'] = {};
+ for (const id of Object.keys(data.emojis)) {
+ if (!excluded.has(id)) emojis[id] = data.emojis[id];
+ }
+ const categories = data.categories
+ .map((category) => ({
+ ...category,
+ emojis: category.emojis.filter((id) => emojis[id]),
+ }))
+ .filter((category) => category.emojis.length > 0);
+
+ return { ...data, categories, emojis };
+};
diff --git a/src/plugins/Emojis/data/index.ts b/src/plugins/Emojis/data/index.ts
new file mode 100644
index 000000000..d31c9443f
--- /dev/null
+++ b/src/plugins/Emojis/data/index.ts
@@ -0,0 +1,24 @@
+import { memoizeAsyncWithReset } from '../memoizeAsyncWithReset';
+import type { EmojiData } from './types';
+
+export type {
+ EmojiData,
+ EmojiDataCategory,
+ EmojiDataEmoji,
+ EmojiDataSkin,
+} from './types';
+
+/**
+ * Lazily loads the vendored emoji dataset. The JSON is imported dynamically so
+ * bundlers emit it as a separate async chunk — it is fetched only when the emoji
+ * picker or search actually runs, and never enters the main `stream-chat-react`
+ * bundle. The result is memoized, so repeated calls share a single load; a failed
+ * load (offline, stale chunk after a deploy) is not cached, so a later call retries.
+ */
+export const loadEmojiData = memoizeAsyncWithReset(() =>
+ import('./emoji-data.json').then(
+ (mod) =>
+ ((mod as unknown as { default?: EmojiData }).default ??
+ mod) as unknown as EmojiData,
+ ),
+);
diff --git a/src/plugins/Emojis/data/types.ts b/src/plugins/Emojis/data/types.ts
new file mode 100644
index 000000000..f4f4d2d3b
--- /dev/null
+++ b/src/plugins/Emojis/data/types.ts
@@ -0,0 +1,28 @@
+// Shape of the vendored emoji dataset (a snapshot of `@emoji-mart/data`'s native
+// set). Kept structurally identical to the upstream data so that `mapEmojiMartData`
+// and any consumer relying on the emoji-mart data shape keep working unchanged.
+
+export type EmojiDataSkin = {
+ native: string;
+ unified: string;
+};
+
+export type EmojiDataEmoji = {
+ id: string;
+ keywords: string[];
+ name: string;
+ skins: EmojiDataSkin[];
+ version: number;
+ emoticons?: string[];
+};
+
+export type EmojiDataCategory = {
+ emojis: string[];
+ id: string;
+};
+
+export type EmojiData = {
+ aliases: Record;
+ categories: EmojiDataCategory[];
+ emojis: Record;
+};
diff --git a/src/plugins/Emojis/hooks/__tests__/gridNavigation.test.ts b/src/plugins/Emojis/hooks/__tests__/gridNavigation.test.ts
new file mode 100644
index 000000000..95672be90
--- /dev/null
+++ b/src/plugins/Emojis/hooks/__tests__/gridNavigation.test.ts
@@ -0,0 +1,126 @@
+import { navigateGrid } from '../gridNavigation';
+
+// A "grid" is a vertical stack of sections (categories); each section is laid out as a
+// `columns`-wide grid filled in reading order. navigateGrid is pure: given the section
+// lengths, the active (section, index), a key, and the column count, it returns the
+// target position (or null to stay put at a grid edge).
+
+describe('navigateGrid — single section (search view)', () => {
+ const single = [7]; // rows (cols=3): [0,1,2] [3,4,5] [6]
+
+ it('moves right/left within a row', () => {
+ expect(navigateGrid(single, { index: 0, section: 0 }, 'ArrowRight', 3)).toEqual({
+ index: 1,
+ section: 0,
+ });
+ expect(navigateGrid(single, { index: 1, section: 0 }, 'ArrowLeft', 3)).toEqual({
+ index: 0,
+ section: 0,
+ });
+ });
+
+ it('clamps (null) at the last cell going right and the first going left', () => {
+ expect(navigateGrid(single, { index: 6, section: 0 }, 'ArrowRight', 3)).toBeNull();
+ expect(navigateGrid(single, { index: 0, section: 0 }, 'ArrowLeft', 3)).toBeNull();
+ });
+
+ it('moves down/up by one row, same column', () => {
+ expect(navigateGrid(single, { index: 1, section: 0 }, 'ArrowDown', 3)).toEqual({
+ index: 4,
+ section: 0,
+ });
+ expect(navigateGrid(single, { index: 4, section: 0 }, 'ArrowUp', 3)).toEqual({
+ index: 1,
+ section: 0,
+ });
+ });
+
+ it('down into a partial last row clamps to that row’s last cell', () => {
+ // index 5 (row 1, col 2) down: row 2 has only index 6 → clamp to 6.
+ expect(navigateGrid(single, { index: 5, section: 0 }, 'ArrowDown', 3)).toEqual({
+ index: 6,
+ section: 0,
+ });
+ });
+
+ it('clamps (null) going down from the last row and up from the first', () => {
+ expect(navigateGrid(single, { index: 6, section: 0 }, 'ArrowDown', 3)).toBeNull();
+ expect(navigateGrid(single, { index: 2, section: 0 }, 'ArrowUp', 3)).toBeNull();
+ });
+
+ it('Home/End jump to the first/last cell of the whole grid', () => {
+ expect(navigateGrid(single, { index: 5, section: 0 }, 'Home', 3)).toEqual({
+ index: 0,
+ section: 0,
+ });
+ expect(navigateGrid(single, { index: 0, section: 0 }, 'End', 3)).toEqual({
+ index: 6,
+ section: 0,
+ });
+ });
+});
+
+describe('navigateGrid — multiple sections (category view)', () => {
+ const multi = [5, 6]; // section 0 rows (cols=3): [0,1,2] [3,4]; section 1: [0,1,2] [3,4,5]
+
+ it('crosses to the next section going right off a section’s last cell', () => {
+ expect(navigateGrid(multi, { index: 4, section: 0 }, 'ArrowRight', 3)).toEqual({
+ index: 0,
+ section: 1,
+ });
+ });
+
+ it('crosses to the previous section going left off a section’s first cell', () => {
+ expect(navigateGrid(multi, { index: 0, section: 1 }, 'ArrowLeft', 3)).toEqual({
+ index: 4,
+ section: 0,
+ });
+ });
+
+ it('crosses down into the next section preserving the column', () => {
+ expect(navigateGrid(multi, { index: 3, section: 0 }, 'ArrowDown', 3)).toEqual({
+ index: 0,
+ section: 1,
+ });
+ expect(navigateGrid(multi, { index: 4, section: 0 }, 'ArrowDown', 3)).toEqual({
+ index: 1,
+ section: 1,
+ });
+ });
+
+ it('crosses up into the previous section’s last row, clamping the column', () => {
+ expect(navigateGrid(multi, { index: 1, section: 1 }, 'ArrowUp', 3)).toEqual({
+ index: 4,
+ section: 0,
+ });
+ // Column 2 has no cell in section 0's last row ([3,4]) → clamp to its last cell.
+ expect(navigateGrid(multi, { index: 2, section: 1 }, 'ArrowUp', 3)).toEqual({
+ index: 4,
+ section: 0,
+ });
+ });
+
+ it('clamps (null) going right off the very last cell of the last section', () => {
+ expect(navigateGrid(multi, { index: 5, section: 1 }, 'ArrowRight', 3)).toBeNull();
+ });
+
+ it('End jumps to the last cell of the last section', () => {
+ expect(navigateGrid(multi, { index: 0, section: 0 }, 'End', 3)).toEqual({
+ index: 5,
+ section: 1,
+ });
+ });
+});
+
+// Column count is a parameter, so a non-default `perLine` navigates by that many cells
+// per row — the hook measures columns from layout at runtime and passes them here, which
+// is why the perLine option needs no keyboard-nav change.
+describe('navigateGrid — honors the column count (perLine parity)', () => {
+ it('ArrowDown moves by `columns` cells within a section', () => {
+ // 14 cells at 7 columns: row 0 = [0..6], row 1 = [7..13]; down from 0 → 7.
+ expect(navigateGrid([14], { index: 0, section: 0 }, 'ArrowDown', 7)).toEqual({
+ index: 7,
+ section: 0,
+ });
+ });
+});
diff --git a/src/plugins/Emojis/hooks/__tests__/useDebouncedValue.test.ts b/src/plugins/Emojis/hooks/__tests__/useDebouncedValue.test.ts
new file mode 100644
index 000000000..8ea4b443a
--- /dev/null
+++ b/src/plugins/Emojis/hooks/__tests__/useDebouncedValue.test.ts
@@ -0,0 +1,39 @@
+import { act, renderHook } from '@testing-library/react';
+import { useDebouncedValue } from '../useDebouncedValue';
+
+describe('useDebouncedValue', () => {
+ beforeEach(() => vi.useFakeTimers());
+ afterEach(() => vi.useRealTimers());
+
+ it('returns the initial value immediately', () => {
+ const { result } = renderHook(() => useDebouncedValue('a', 100));
+ expect(result.current).toBe('a');
+ });
+
+ it('updates to the latest value only after the delay elapses', () => {
+ const { rerender, result } = renderHook(({ v }) => useDebouncedValue(v, 100), {
+ initialProps: { v: 'a' },
+ });
+
+ rerender({ v: 'b' });
+ expect(result.current).toBe('a'); // not yet
+
+ act(() => vi.advanceTimersByTime(100));
+ expect(result.current).toBe('b');
+ });
+
+ it('collapses rapid changes, emitting only the final value', () => {
+ const { rerender, result } = renderHook(({ v }) => useDebouncedValue(v, 100), {
+ initialProps: { v: 'a' },
+ });
+
+ rerender({ v: 'ab' });
+ act(() => vi.advanceTimersByTime(50));
+ rerender({ v: 'abc' });
+ act(() => vi.advanceTimersByTime(50)); // only 50ms since 'abc' → still stale
+ expect(result.current).toBe('a');
+
+ act(() => vi.advanceTimersByTime(50)); // now 100ms since 'abc'
+ expect(result.current).toBe('abc'); // intermediate 'ab' was skipped
+ });
+});
diff --git a/src/plugins/Emojis/hooks/__tests__/useEmojiPickerState.test.ts b/src/plugins/Emojis/hooks/__tests__/useEmojiPickerState.test.ts
new file mode 100644
index 000000000..1ef4c4689
--- /dev/null
+++ b/src/plugins/Emojis/hooks/__tests__/useEmojiPickerState.test.ts
@@ -0,0 +1,37 @@
+import { act, renderHook, waitFor } from '@testing-library/react';
+
+const { loadState } = vi.hoisted(() => ({ loadState: { attempts: 0 } }));
+
+// Reject the first dataset load, then succeed — the offline / stale-chunk scenario the
+// picker must recover from without a full page reload.
+vi.mock('../../data', () => ({
+ loadEmojiData: vi.fn(() => {
+ loadState.attempts += 1;
+ return loadState.attempts === 1
+ ? Promise.reject(new Error('chunk load failed'))
+ : Promise.resolve({ aliases: {}, categories: [], emojis: {} });
+ }),
+}));
+
+import { useEmojiPickerState } from '../useEmojiPickerState';
+
+describe('useEmojiPickerState', () => {
+ beforeEach(() => {
+ loadState.attempts = 0;
+ });
+
+ it('surfaces an error when the dataset fails to load, then recovers on retry', async () => {
+ const { result } = renderHook(() => useEmojiPickerState());
+
+ await waitFor(() => expect(result.current.error).toBe(true));
+ expect(result.current.data).toBeNull();
+
+ act(() => {
+ result.current.retry();
+ });
+
+ await waitFor(() => expect(result.current.data).not.toBeNull());
+ expect(result.current.error).toBe(false);
+ expect(loadState.attempts).toBe(2);
+ });
+});
diff --git a/src/plugins/Emojis/hooks/__tests__/useFrequentlyUsedEmoji.test.ts b/src/plugins/Emojis/hooks/__tests__/useFrequentlyUsedEmoji.test.ts
new file mode 100644
index 000000000..2ab949e0a
--- /dev/null
+++ b/src/plugins/Emojis/hooks/__tests__/useFrequentlyUsedEmoji.test.ts
@@ -0,0 +1,49 @@
+import { act, renderHook } from '@testing-library/react';
+import { useFrequentlyUsedEmoji } from '../useFrequentlyUsedEmoji';
+
+describe('useFrequentlyUsedEmoji', () => {
+ it('tracks recents most-recent-first and de-duplicates (uncontrolled)', () => {
+ const { result } = renderHook(() => useFrequentlyUsedEmoji({}));
+ act(() => result.current.recordUse('a'));
+ act(() => result.current.recordUse('b'));
+ act(() => result.current.recordUse('a'));
+ expect(result.current.frequentlyUsedIds).toEqual(['a', 'b']);
+ });
+
+ it('notifies via onFrequentlyUsedChange and stays controlled', () => {
+ const onFrequentlyUsedChange = vi.fn();
+ const { rerender, result } = renderHook(
+ ({ frequentlyUsedEmoji }) =>
+ useFrequentlyUsedEmoji({ frequentlyUsedEmoji, onFrequentlyUsedChange }),
+ { initialProps: { frequentlyUsedEmoji: ['x'] } },
+ );
+ act(() => result.current.recordUse('y'));
+ expect(onFrequentlyUsedChange).toHaveBeenCalledWith(['y', 'x']);
+ expect(result.current.frequentlyUsedIds).toEqual(['x']); // controlled: reflects prop only
+ rerender({ frequentlyUsedEmoji: ['y', 'x'] });
+ expect(result.current.frequentlyUsedIds).toEqual(['y', 'x']);
+ });
+
+ it('keeps both when two emoji are recorded before a re-render (uncontrolled)', () => {
+ const { result } = renderHook(() => useFrequentlyUsedEmoji({}));
+ // Two selects in the same tick close over the same list — the second must still
+ // build on the first, not overwrite it.
+ act(() => {
+ result.current.recordUse('a');
+ result.current.recordUse('b');
+ });
+ expect(result.current.frequentlyUsedIds).toEqual(['b', 'a']);
+ });
+
+ it('accumulates both when two emoji are recorded before a re-render (controlled)', () => {
+ const onFrequentlyUsedChange = vi.fn();
+ const { result } = renderHook(() =>
+ useFrequentlyUsedEmoji({ frequentlyUsedEmoji: [], onFrequentlyUsedChange }),
+ );
+ act(() => {
+ result.current.recordUse('a');
+ result.current.recordUse('b');
+ });
+ expect(onFrequentlyUsedChange).toHaveBeenLastCalledWith(['b', 'a']);
+ });
+});
diff --git a/src/plugins/Emojis/hooks/__tests__/useGridKeyboardNav.test.tsx b/src/plugins/Emojis/hooks/__tests__/useGridKeyboardNav.test.tsx
new file mode 100644
index 000000000..5ae64e7dc
--- /dev/null
+++ b/src/plugins/Emojis/hooks/__tests__/useGridKeyboardNav.test.tsx
@@ -0,0 +1,124 @@
+import { useRef, useState } from 'react';
+import { fireEvent, render, screen, waitFor } from '@testing-library/react';
+import { useGridKeyboardNav } from '../useGridKeyboardNav';
+
+// jsdom doesn't implement scrollIntoView; the hook calls it after focusing a cell.
+beforeAll(() => {
+ Element.prototype.scrollIntoView = () => undefined;
+});
+
+type Category = { emojis: { id: string }[]; id: string };
+
+/**
+ * Mimics the virtualized grid: only `initialMounted` categories are in the DOM, and
+ * asking to scroll to a category "mounts" it (as Virtuoso would). This lets us prove
+ * navigation can cross into a category that virtualization has not yet rendered.
+ */
+const Harness = ({
+ categories,
+ initialMounted,
+}: {
+ categories: Category[];
+ initialMounted: string[];
+}) => {
+ const ref = useRef(null);
+ const [mounted, setMounted] = useState(initialMounted);
+ const scrollToCategory = (id: string) =>
+ setMounted((current) => (current.includes(id) ? current : [...current, id]));
+ const { onKeyDown } = useGridKeyboardNav(ref, { categories, scrollToCategory });
+
+ return (
+
+ {categories
+ .filter((category) => mounted.includes(category.id))
+ .map((category) => (
+
+ {category.emojis.map(({ id }) => (
+
+ {id}
+
+ ))}
+
+ ))}
+
+ );
+};
+
+const categories: Category[] = [
+ { emojis: [{ id: 'a1' }, { id: 'a2' }, { id: 'a3' }], id: 'a' },
+ { emojis: [{ id: 'b1' }, { id: 'b2' }, { id: 'b3' }], id: 'b' },
+];
+
+describe('useGridKeyboardNav across virtualization boundaries', () => {
+ it('ArrowRight past the last mounted cell mounts the next category and focuses its first cell', async () => {
+ render( );
+ // The next category isn't mounted yet (virtualization).
+ expect(screen.queryByText('b1')).not.toBeInTheDocument();
+
+ screen.getByText('a3').focus();
+ fireEvent.keyDown(screen.getByText('a3'), { key: 'ArrowRight' });
+
+ await waitFor(() => expect(screen.getByText('b1')).toHaveFocus());
+ });
+
+ it('ArrowLeft before the first mounted cell mounts the previous category and focuses its last cell', async () => {
+ render( );
+ expect(screen.queryByText('a3')).not.toBeInTheDocument();
+
+ screen.getByText('b1').focus();
+ fireEvent.keyDown(screen.getByText('b1'), { key: 'ArrowLeft' });
+
+ await waitFor(() => expect(screen.getByText('a3')).toHaveFocus());
+ });
+
+ it('ArrowRight still moves within the mounted set without scrolling', () => {
+ render( );
+
+ screen.getByText('a1').focus();
+ fireEvent.keyDown(screen.getByText('a1'), { key: 'ArrowRight' });
+
+ expect(screen.getByText('a2')).toHaveFocus();
+ });
+
+ it('does not try to cross categories in the search view (flat results, no category sections)', () => {
+ const scrollToCategory = vi.fn();
+ const SearchHarness = () => {
+ const ref = useRef(null);
+ const { onKeyDown } = useGridKeyboardNav(ref, { categories, scrollToCategory });
+ // Search results render as a flat grid with no [data-category-id] ancestor.
+ return (
+
+ {['r1', 'r2'].map((id) => (
+
+ {id}
+
+ ))}
+
+ );
+ };
+ render( );
+
+ // ArrowRight at the last result clamps (no category to scroll to)…
+ screen.getByText('r2').focus();
+ fireEvent.keyDown(screen.getByText('r2'), { key: 'ArrowRight' });
+ expect(screen.getByText('r2')).toHaveFocus();
+
+ // …and Home goes to the first result rather than scrolling to a category.
+ fireEvent.keyDown(screen.getByText('r2'), { key: 'Home' });
+ expect(screen.getByText('r1')).toHaveFocus();
+
+ expect(scrollToCategory).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/plugins/Emojis/hooks/__tests__/useSkinTone.test.ts b/src/plugins/Emojis/hooks/__tests__/useSkinTone.test.ts
new file mode 100644
index 000000000..adc4f510e
--- /dev/null
+++ b/src/plugins/Emojis/hooks/__tests__/useSkinTone.test.ts
@@ -0,0 +1,32 @@
+import { act, renderHook } from '@testing-library/react';
+import { useSkinTone } from '../useSkinTone';
+
+describe('useSkinTone', () => {
+ it('is uncontrolled from defaultSkinTone and updates internally', () => {
+ const { result } = renderHook(() => useSkinTone({ defaultSkinTone: 2 }));
+ expect(result.current[0]).toBe(2);
+ act(() => result.current[1](4));
+ expect(result.current[0]).toBe(4);
+ });
+
+ it('clamps out-of-range values to 0..5', () => {
+ const { result } = renderHook(() => useSkinTone({ defaultSkinTone: 99 }));
+ expect(result.current[0]).toBe(5);
+ act(() => result.current[1](-3));
+ expect(result.current[0]).toBe(0);
+ });
+
+ it('is controlled when skinTone is provided and does not self-update', () => {
+ const onSkinToneChange = vi.fn();
+ const { rerender, result } = renderHook(
+ ({ skinTone }) => useSkinTone({ onSkinToneChange, skinTone }),
+ { initialProps: { skinTone: 1 } },
+ );
+ expect(result.current[0]).toBe(1);
+ act(() => result.current[1](3));
+ expect(onSkinToneChange).toHaveBeenCalledWith(3);
+ expect(result.current[0]).toBe(1); // stays until the controlled prop changes
+ rerender({ skinTone: 3 });
+ expect(result.current[0]).toBe(3);
+ });
+});
diff --git a/src/plugins/Emojis/hooks/gridNavigation.ts b/src/plugins/Emojis/hooks/gridNavigation.ts
new file mode 100644
index 000000000..b079b2c3b
--- /dev/null
+++ b/src/plugins/Emojis/hooks/gridNavigation.ts
@@ -0,0 +1,81 @@
+export type GridPosition = { index: number; section: number };
+
+/**
+ * Pure keyboard navigation over a sectioned grid: the emoji picker is a vertical stack
+ * of sections (categories), each laid out as a `columns`-wide grid filled in reading
+ * order. Given the section lengths, the active `(section, index)`, the pressed key, and
+ * the current column count, it returns the target position — or `null` to stay put at a
+ * grid edge.
+ *
+ * Kept free of the DOM so the (otherwise layout-dependent, untestable) navigation logic
+ * can be unit-tested exhaustively. The hook maps the DOM position in/out and measures
+ * `columns` from layout.
+ */
+export const navigateGrid = (
+ sectionLengths: number[],
+ pos: GridPosition,
+ key: string,
+ columns: number,
+): GridPosition | null => {
+ const cols = Math.max(1, columns);
+ const len = sectionLengths[pos.section] ?? 0;
+ if (len === 0) return null;
+
+ const col = pos.index % cols;
+ const row = Math.floor(pos.index / cols);
+ const lastRow = Math.floor((len - 1) / cols);
+
+ switch (key) {
+ case 'Home':
+ return { index: 0, section: 0 };
+
+ case 'End': {
+ const last = sectionLengths.length - 1;
+ return { index: Math.max(0, (sectionLengths[last] ?? 0) - 1), section: last };
+ }
+
+ case 'ArrowRight':
+ if (pos.index < len - 1) return { index: pos.index + 1, section: pos.section };
+ if (pos.section < sectionLengths.length - 1) {
+ return { index: 0, section: pos.section + 1 };
+ }
+ return null;
+
+ case 'ArrowLeft':
+ if (pos.index > 0) return { index: pos.index - 1, section: pos.section };
+ if (pos.section > 0) {
+ return {
+ index: Math.max(0, (sectionLengths[pos.section - 1] ?? 0) - 1),
+ section: pos.section - 1,
+ };
+ }
+ return null;
+
+ case 'ArrowDown':
+ if (row < lastRow) {
+ return { index: Math.min(pos.index + cols, len - 1), section: pos.section };
+ }
+ if (pos.section < sectionLengths.length - 1) {
+ const nextLen = sectionLengths[pos.section + 1] ?? 0;
+ if (nextLen === 0) return null;
+ return { index: Math.min(col, nextLen - 1), section: pos.section + 1 };
+ }
+ return null;
+
+ case 'ArrowUp':
+ if (row > 0) return { index: pos.index - cols, section: pos.section };
+ if (pos.section > 0) {
+ const prevLen = sectionLengths[pos.section - 1] ?? 0;
+ if (prevLen === 0) return null;
+ const prevLastRow = Math.floor((prevLen - 1) / cols);
+ return {
+ index: Math.min(prevLastRow * cols + col, prevLen - 1),
+ section: pos.section - 1,
+ };
+ }
+ return null;
+
+ default:
+ return null;
+ }
+};
diff --git a/src/plugins/Emojis/hooks/useDebouncedValue.ts b/src/plugins/Emojis/hooks/useDebouncedValue.ts
new file mode 100644
index 000000000..0ff16ee63
--- /dev/null
+++ b/src/plugins/Emojis/hooks/useDebouncedValue.ts
@@ -0,0 +1,17 @@
+import { useEffect, useState } from 'react';
+
+/**
+ * Returns `value` debounced by `delayMs`: the result only catches up to the latest value
+ * once `delayMs` has elapsed without a further change. Version-safe across React 17–19
+ * (unlike `useDeferredValue`, which is React 18+).
+ */
+export const useDebouncedValue = (value: T, delayMs: number): T => {
+ const [debounced, setDebounced] = useState(value);
+
+ useEffect(() => {
+ const id = setTimeout(() => setDebounced(value), delayMs);
+ return () => clearTimeout(id);
+ }, [value, delayMs]);
+
+ return debounced;
+};
diff --git a/src/plugins/Emojis/hooks/useEmojiPickerState.ts b/src/plugins/Emojis/hooks/useEmojiPickerState.ts
new file mode 100644
index 000000000..4ecfc2572
--- /dev/null
+++ b/src/plugins/Emojis/hooks/useEmojiPickerState.ts
@@ -0,0 +1,36 @@
+import { useCallback, useEffect, useState } from 'react';
+import { type EmojiData, loadEmojiData } from '../data';
+
+/**
+ * Loads the vendored emoji dataset lazily (via the code-split dynamic import) and
+ * exposes it once resolved.
+ *
+ * `data` is `null` while loading. If the load fails (offline, or a stale chunk after a
+ * deploy) `error` becomes `true`; `retry()` re-attempts it. Because `loadEmojiData`
+ * drops its memo on failure, the retry actually re-imports rather than replaying the
+ * rejected promise — so the picker can recover without a full page reload.
+ */
+export const useEmojiPickerState = () => {
+ const [data, setData] = useState(null);
+ const [error, setError] = useState(false);
+ const [attempt, setAttempt] = useState(0);
+
+ useEffect(() => {
+ let active = true;
+ setError(false);
+ loadEmojiData()
+ .then((loaded) => {
+ if (active) setData(loaded);
+ })
+ .catch(() => {
+ if (active) setError(true);
+ });
+ return () => {
+ active = false;
+ };
+ }, [attempt]);
+
+ const retry = useCallback(() => setAttempt((current) => current + 1), []);
+
+ return { data, error, retry };
+};
diff --git a/src/plugins/Emojis/hooks/useFrequentlyUsedEmoji.ts b/src/plugins/Emojis/hooks/useFrequentlyUsedEmoji.ts
new file mode 100644
index 000000000..7efb681b2
--- /dev/null
+++ b/src/plugins/Emojis/hooks/useFrequentlyUsedEmoji.ts
@@ -0,0 +1,46 @@
+import { useCallback, useRef, useState } from 'react';
+
+export type UseFrequentlyUsedEmojiParams = {
+ /** Controlled ordered list of recently used emoji ids (most recent first). */
+ frequentlyUsedEmoji?: string[];
+ /** Called with the updated ordered list whenever an emoji is used. */
+ onFrequentlyUsedChange?: (emojiIds: string[]) => void;
+};
+
+const MAX_FREQUENTLY_USED = 24;
+
+/**
+ * Tracks recently used emoji as an ordered, most-recent-first list. Controlled via
+ * `frequentlyUsedEmoji`/`onFrequentlyUsedChange`; otherwise kept ephemerally in
+ * memory for the current mount (reset on reload). The SDK never persists — see the
+ * vite example for a localStorage-backed integrator pattern.
+ */
+export const useFrequentlyUsedEmoji = ({
+ frequentlyUsedEmoji,
+ onFrequentlyUsedChange,
+}: UseFrequentlyUsedEmojiParams) => {
+ const [internal, setInternal] = useState([]);
+ const isControlled = Array.isArray(frequentlyUsedEmoji);
+ const frequentlyUsedIds = isControlled ? frequentlyUsedEmoji : internal;
+
+ // Mirror the current list into a ref so several recordUse calls fired before a
+ // re-render each build on the previous result rather than a stale closure/prop
+ // (otherwise the second synchronous select would drop the first).
+ const latestRef = useRef(frequentlyUsedIds);
+ latestRef.current = frequentlyUsedIds;
+
+ const recordUse = useCallback(
+ (emojiId: string) => {
+ const next = [
+ emojiId,
+ ...latestRef.current.filter((existing) => existing !== emojiId),
+ ].slice(0, MAX_FREQUENTLY_USED);
+ latestRef.current = next;
+ if (!isControlled) setInternal(next);
+ onFrequentlyUsedChange?.(next);
+ },
+ [isControlled, onFrequentlyUsedChange],
+ );
+
+ return { frequentlyUsedIds, recordUse };
+};
diff --git a/src/plugins/Emojis/hooks/useGridKeyboardNav.ts b/src/plugins/Emojis/hooks/useGridKeyboardNav.ts
new file mode 100644
index 000000000..33977b2d4
--- /dev/null
+++ b/src/plugins/Emojis/hooks/useGridKeyboardNav.ts
@@ -0,0 +1,189 @@
+import { type KeyboardEvent, useCallback, useEffect, useRef } from 'react';
+import { navigateGrid } from './gridNavigation';
+
+type GridRef = { readonly current: HTMLElement | null };
+
+export type GridKeyboardNavOptions = {
+ /**
+ * Ordered categories with their emoji ids. Navigation runs over this model (not live
+ * DOM geometry), so it can target a cell in a category that virtualization has not
+ * mounted yet — and stays correct regardless of layout.
+ */
+ categories?: readonly { emojis: readonly { id: string }[]; id: string }[];
+ /**
+ * Scrolls a category into view so virtualization mounts it (e.g. Virtuoso's
+ * `scrollToIndex`). Navigation focuses the target cell once that category appears.
+ */
+ scrollToCategory?: (categoryId: string) => void;
+};
+
+const EMOJI_SELECTOR = '.str-chat__emoji-picker__emoji';
+const CATEGORY_SELECTOR = '[data-category-id]';
+const NAV_KEYS = ['ArrowRight', 'ArrowLeft', 'ArrowDown', 'ArrowUp', 'Home', 'End'];
+// Stop waiting for an offscreen category to mount after this long (avoids a dangling
+// observer if a scroll never mounts the target).
+const MOUNT_TIMEOUT_MS = 1000;
+
+const cellsIn = (root: Element | null) =>
+ root ? Array.from(root.querySelectorAll(EMOJI_SELECTOR)) : [];
+
+// Cells are laid out row-major, so the first row is every cell sharing the first cell's
+// offsetTop — its size is the current column count. Uses offsetTop (no forced reflow)
+// and is read once per keypress.
+const measureColumns = (cells: HTMLButtonElement[]) => {
+ if (cells.length <= 1) return Math.max(1, cells.length);
+ const top = cells[0].offsetTop;
+ return Math.max(1, cells.filter((cell) => cell.offsetTop === top).length);
+};
+
+/**
+ * Roving-tabindex keyboard navigation for the emoji grid. Navigation is computed by the
+ * pure `navigateGrid` over the known category model (see gridNavigation.ts) — only the
+ * current column count is read from layout — then the resolved cell is focused by id.
+ *
+ * Because the grid is virtualized, a move can target a category that is not currently
+ * mounted; navigation then asks `scrollToCategory` to mount it and focuses the cell as
+ * soon as it appears, so keyboard users can traverse the whole set. In the search view
+ * (no categories) it navigates the flat, fully-mounted result list the same way.
+ */
+export const useGridKeyboardNav = (
+ gridRef: GridRef,
+ { categories = [], scrollToCategory }: GridKeyboardNavOptions = {},
+) => {
+ const getButtons = useCallback(() => cellsIn(gridRef.current), [gridRef]);
+
+ // The single tab-reachable ("roving") cell. Tracked in a ref so moving focus only
+ // flips two cells' tabIndex instead of sweeping every mounted cell.
+ const rovingRef = useRef(null);
+
+ const focusCell = useCallback((cell: HTMLButtonElement | null | undefined) => {
+ if (!cell) return;
+ if (rovingRef.current && rovingRef.current !== cell) {
+ rovingRef.current.tabIndex = -1;
+ }
+ cell.tabIndex = 0;
+ rovingRef.current = cell;
+ cell.focus();
+ cell.scrollIntoView({ block: 'nearest' });
+ }, []);
+
+ // Keep one tab-reachable cell as virtualization mounts/unmounts. Cheap: only touches
+ // the DOM when the roving cell has detached (e.g. scrolled out and unmounted).
+ useEffect(() => {
+ if (rovingRef.current && gridRef.current?.contains(rovingRef.current)) return;
+ const first = getButtons()[0];
+ if (first) {
+ first.tabIndex = 0;
+ rovingRef.current = first;
+ }
+ });
+
+ const focusFirst = useCallback(
+ () => focusCell(getButtons()[0]),
+ [focusCell, getButtons],
+ );
+
+ // Teardown for a pending "focus once the category mounts" watch. Replaced whenever a
+ // new focus-by-id starts; invoked on a superseding keypress and on unmount.
+ const cancelPending = useRef<() => void>(() => undefined);
+ useEffect(() => () => cancelPending.current(), []);
+
+ // Focus an emoji by id within a specific category (ids repeat across the "frequent"
+ // section and their home category, so the lookup must be category-scoped). If that
+ // category isn't mounted, scroll it into view and focus once it appears.
+ const focusEmojiInCategory = useCallback(
+ (categoryId: string, emojiId: string) => {
+ const find = () => {
+ const section = gridRef.current?.querySelector(
+ `${CATEGORY_SELECTOR}[data-category-id="${categoryId}"]`,
+ );
+ return (
+ section?.querySelector(
+ `${EMOJI_SELECTOR}[data-emoji-id="${emojiId}"]`,
+ ) ?? null
+ );
+ };
+
+ cancelPending.current();
+
+ const mounted = find();
+ if (mounted) {
+ focusCell(mounted);
+ return;
+ }
+
+ scrollToCategory?.(categoryId);
+ const grid = gridRef.current;
+ if (!grid) return;
+
+ const observer = new MutationObserver(() => {
+ const cell = find();
+ if (cell) {
+ cancelPending.current();
+ focusCell(cell);
+ }
+ });
+ observer.observe(grid, { childList: true, subtree: true });
+ const timeout = setTimeout(() => cancelPending.current(), MOUNT_TIMEOUT_MS);
+ cancelPending.current = () => {
+ observer.disconnect();
+ clearTimeout(timeout);
+ cancelPending.current = () => undefined;
+ };
+ },
+ [focusCell, gridRef, scrollToCategory],
+ );
+
+ const onKeyDown = useCallback(
+ (event: KeyboardEvent) => {
+ if (!NAV_KEYS.includes(event.key)) return;
+ const buttons = getButtons();
+ const activeIndex = buttons.findIndex(
+ (button) => button === document.activeElement,
+ );
+ if (activeIndex === -1) return;
+ event.preventDefault();
+ // A fresh keypress supersedes any in-flight wait for an offscreen category.
+ cancelPending.current();
+
+ const active = buttons[activeIndex];
+ const sectionEl = active.closest(CATEGORY_SELECTOR);
+ const categoryId = sectionEl?.getAttribute('data-category-id');
+ const sectionIndex = categories.findIndex((entry) => entry.id === categoryId);
+
+ if (sectionIndex >= 0) {
+ // Category (virtualized) view — navigate the known model.
+ const emojiId = active.getAttribute('data-emoji-id');
+ const indexInSection = categories[sectionIndex].emojis.findIndex(
+ (emoji) => emoji.id === emojiId,
+ );
+ if (indexInSection === -1) return;
+
+ const target = navigateGrid(
+ categories.map((category) => category.emojis.length),
+ { index: indexInSection, section: sectionIndex },
+ event.key,
+ measureColumns(cellsIn(sectionEl)),
+ );
+ if (!target) return; // grid edge — stay put
+
+ const targetCategory = categories[target.section];
+ const targetEmoji = targetCategory.emojis[target.index];
+ if (targetEmoji) focusEmojiInCategory(targetCategory.id, targetEmoji.id);
+ return;
+ }
+
+ // Search (non-virtualized) view — navigate the flat, fully-mounted result list.
+ const target = navigateGrid(
+ [buttons.length],
+ { index: activeIndex, section: 0 },
+ event.key,
+ measureColumns(buttons),
+ );
+ if (target) focusCell(buttons[target.index]);
+ },
+ [categories, focusCell, focusEmojiInCategory, getButtons],
+ );
+
+ return { focusFirst, onKeyDown };
+};
diff --git a/src/plugins/Emojis/hooks/useSkinTone.ts b/src/plugins/Emojis/hooks/useSkinTone.ts
new file mode 100644
index 000000000..b06b2c7e2
--- /dev/null
+++ b/src/plugins/Emojis/hooks/useSkinTone.ts
@@ -0,0 +1,39 @@
+import { useCallback, useState } from 'react';
+import { MAX_SKIN_TONE_INDEX } from '../components/skinTones';
+
+export type UseSkinToneParams = {
+ /** Uncontrolled initial skin tone index (0 = default, 1–5 = light → dark). */
+ defaultSkinTone?: number;
+ /** Called with the new skin tone index whenever it changes. */
+ onSkinToneChange?: (skinTone: number) => void;
+ /** Controlled skin tone index. When provided, the picker does not hold its own. */
+ skinTone?: number;
+};
+
+const clamp = (value: number) =>
+ Math.min(MAX_SKIN_TONE_INDEX, Math.max(0, Math.floor(value)));
+
+/**
+ * Controlled-or-uncontrolled skin tone selection. The SDK never persists the value
+ * — integrators own persistence by controlling `skinTone`/`onSkinToneChange`.
+ */
+export const useSkinTone = ({
+ defaultSkinTone,
+ onSkinToneChange,
+ skinTone,
+}: UseSkinToneParams) => {
+ const [internal, setInternal] = useState(() => clamp(defaultSkinTone ?? 0));
+ const isControlled = typeof skinTone === 'number';
+ const value = clamp(isControlled ? skinTone : internal);
+
+ const setSkinTone = useCallback(
+ (next: number) => {
+ const clamped = clamp(next);
+ if (!isControlled) setInternal(clamped);
+ onSkinToneChange?.(clamped);
+ },
+ [isControlled, onSkinToneChange],
+ );
+
+ return [value, setSkinTone] as const;
+};
diff --git a/src/plugins/Emojis/index.ts b/src/plugins/Emojis/index.ts
index 17d0119d3..97d4effda 100644
--- a/src/plugins/Emojis/index.ts
+++ b/src/plugins/Emojis/index.ts
@@ -1,2 +1,12 @@
+export * from './compat';
+export * from './components';
+export {
+ type EmojiPickerContextValue,
+ useEmojiPickerContext,
+} from './context/EmojiPickerContext';
+export * from './data';
export * from './EmojiPicker';
export * from './middleware';
+export * from './reactions';
+export * from './search';
+export * from './StreamEmojiPicker';
diff --git a/src/plugins/Emojis/memoizeAsyncWithReset.ts b/src/plugins/Emojis/memoizeAsyncWithReset.ts
new file mode 100644
index 000000000..72721b44f
--- /dev/null
+++ b/src/plugins/Emojis/memoizeAsyncWithReset.ts
@@ -0,0 +1,19 @@
+/**
+ * Memoizes an async factory, sharing one in-flight/resolved promise across callers —
+ * but drops the memo if the promise rejects, so a later call retries instead of
+ * replaying the failure forever. Used for the lazily code-split emoji dataset (and the
+ * search index derived from it): a transient chunk-load failure (offline, stale deploy)
+ * must not permanently disable the picker or poison the shared search index.
+ */
+export const memoizeAsyncWithReset = (factory: () => Promise) => {
+ let promise: Promise | null = null;
+ return (): Promise => {
+ if (!promise) {
+ promise = factory().catch((error) => {
+ promise = null;
+ throw error;
+ });
+ }
+ return promise;
+ };
+};
diff --git a/src/plugins/Emojis/middleware/__tests__/textComposerEmojiMiddleware.test.ts b/src/plugins/Emojis/middleware/__tests__/textComposerEmojiMiddleware.test.ts
new file mode 100644
index 000000000..db9027819
--- /dev/null
+++ b/src/plugins/Emojis/middleware/__tests__/textComposerEmojiMiddleware.test.ts
@@ -0,0 +1,102 @@
+import { createTextComposerEmojiMiddleware } from '../textComposerEmojiMiddleware';
+
+// Minimal onChange harness: capture whatever state the handler completes/nexts with.
+const runOnChange = async (
+ middleware: ReturnType,
+
+ state: any,
+) => {
+ let output: any;
+
+ const complete = (next: any) => {
+ output = next;
+ return { state: next, status: 'complete' };
+ };
+ const forward = vi.fn(() => ({ status: 'forward' }));
+
+ const next = (nextState: any) => {
+ output = nextState;
+ return { state: nextState, status: 'next' };
+ };
+ await middleware.handlers.onChange({
+ complete,
+ forward,
+ next,
+ state,
+ } as any);
+ return { forward, output };
+};
+
+describe('createTextComposerEmojiMiddleware', () => {
+ it('returns a middleware with the expected id and handlers when called with no arguments', () => {
+ const middleware = createTextComposerEmojiMiddleware();
+ expect(middleware.id).toBe('stream-io/emoji-middleware');
+ expect(typeof middleware.handlers.onChange).toBe('function');
+ expect(typeof middleware.handlers.onSuggestionItemSelect).toBe('function');
+ });
+
+ it('drives ":" shortcode autocomplete from the built-in index (no emoji-mart)', async () => {
+ const middleware = createTextComposerEmojiMiddleware();
+ const { output } = await runOnChange(middleware, {
+ selection: { end: 4, start: 4 },
+ suggestions: undefined,
+ text: ':smi',
+ });
+
+ expect(output?.suggestions?.trigger).toBe(':');
+ expect(output?.suggestions?.query).toBe('smi');
+
+ const { items } = await output.suggestions.searchSource.query('smi');
+ expect(items.length).toBeGreaterThan(0);
+ // e.g. "smile" / "smiley" — proves the default search index is wired in
+ expect(items.some((item: { id: string }) => item.id.startsWith('smi'))).toBe(true);
+ });
+
+ it('forwards when there is no selection', async () => {
+ const middleware = createTextComposerEmojiMiddleware();
+ const { forward } = await runOnChange(middleware, {
+ selection: null,
+ suggestions: undefined,
+ text: '',
+ });
+ expect(forward).toHaveBeenCalled();
+ });
+
+ it('accepts a custom EmojiSearchIndex override', async () => {
+ const search = vi.fn().mockResolvedValue([
+ {
+ emoticons: [],
+ id: 'custom',
+ name: 'Custom',
+ native: '🦄',
+ skins: [{ native: '🦄' }],
+ },
+ ]);
+ const middleware = createTextComposerEmojiMiddleware({ search });
+ const { output } = await runOnChange(middleware, {
+ selection: { end: 4, start: 4 },
+ suggestions: undefined,
+ text: ':uni',
+ });
+ const { items } = await output.suggestions.searchSource.query('uni');
+ expect(search).toHaveBeenCalled();
+ expect(items[0]?.id).toBe('custom');
+ });
+
+ it('does not leak options between calls (shared defaults are not mutated)', async () => {
+ // A call that overrides options must not change the defaults a later no-arg call
+ // sees. Previously `mergeWith(DEFAULT_OPTIONS, options)` mutated the shared constant.
+ createTextComposerEmojiMiddleware(undefined, { minChars: 3, trigger: ';' });
+
+ const withDefaults = createTextComposerEmojiMiddleware();
+ const { output } = await runOnChange(withDefaults, {
+ selection: { end: 4, start: 4 },
+ suggestions: undefined,
+ text: ':smi',
+ });
+
+ // Still the default ':' trigger — not the ';' leaked from the earlier call.
+ expect(output?.suggestions?.trigger).toBe(':');
+ expect(output?.suggestions?.query).toBe('smi');
+ });
+});
diff --git a/src/plugins/Emojis/middleware/textComposerEmojiMiddleware.ts b/src/plugins/Emojis/middleware/textComposerEmojiMiddleware.ts
index 2a8ce8c00..36367d1c0 100644
--- a/src/plugins/Emojis/middleware/textComposerEmojiMiddleware.ts
+++ b/src/plugins/Emojis/middleware/textComposerEmojiMiddleware.ts
@@ -1,4 +1,3 @@
-import mergeWith from 'lodash.mergewith';
import type {
Middleware,
SearchSourceOptions,
@@ -18,6 +17,7 @@ import type {
EmojiSearchIndex,
EmojiSearchIndexResult,
} from '../../../components/MessageComposer';
+import { defaultEmojiSearchIndex } from '../search';
export type EmojiSuggestion =
TextComposerSuggestion;
@@ -78,27 +78,30 @@ export type EmojiMiddleware;
/**
- * TextComposer middleware for mentions
+ * TextComposer middleware providing `:shortcode` emoji autocomplete and
+ * emoticon-to-emoji replacement (e.g. `:)` → 🙂).
+ *
* Usage:
*
- * const textComposer = new TextComposer(options);
+ * // uses the SDK's built-in emoji search index (no `emoji-mart` required)
+ * textComposer.middlewareExecutor.insert({
+ * middleware: [createTextComposerEmojiMiddleware()],
+ * });
*
- * textComposer.use(new createTextComposerEmojiMiddleware(emojiSearchIndex, {
- * minChars: 2
- * }));
+ * // or provide a custom EmojiSearchIndex / options
+ * createTextComposerEmojiMiddleware(customEmojiSearchIndex, { minChars: 2 });
*
- * @param emojiSearchIndex
- * @param {{
- * minChars: number;
- * trigger: string;
- * }} options
+ * @param emojiSearchIndex Defaults to the SDK's built-in `defaultEmojiSearchIndex`.
+ * @param options `minChars` and `trigger` overrides.
* @returns
*/
export const createTextComposerEmojiMiddleware = (
- emojiSearchIndex: EmojiSearchIndex,
+ emojiSearchIndex: EmojiSearchIndex = defaultEmojiSearchIndex,
options?: Partial,
): EmojiMiddleware => {
- const finalOptions = mergeWith(DEFAULT_OPTIONS, options ?? {});
+ // Spread into a fresh object — never mutate the shared module-level DEFAULT_OPTIONS
+ // (options are flat, so a shallow merge is exact).
+ const finalOptions = { ...DEFAULT_OPTIONS, ...options };
const emojiSearchSource = new EmojiSearchSource(emojiSearchIndex);
emojiSearchSource.activate();
diff --git a/src/plugins/Emojis/reactions.ts b/src/plugins/Emojis/reactions.ts
new file mode 100644
index 000000000..dcf659c1a
--- /dev/null
+++ b/src/plugins/Emojis/reactions.ts
@@ -0,0 +1,24 @@
+import { mapEmojiMartData } from '../../components/Reactions/reactionOptions';
+import { loadEmojiData } from './data';
+import { memoizeAsyncWithReset } from './memoizeAsyncWithReset';
+
+/**
+ * Loads the full set of "extended" reaction options — every vendored emoji, keyed by
+ * unicode — for use as `reactionOptions.extended`. This restores reacting with (almost)
+ * any emoji via the reaction selector's "+" button, which previously came from feeding
+ * the whole `@emoji-mart/data` object into `mapEmojiMartData`.
+ *
+ * Both halves of that feature read `reactionOptions.extended`: the selector only shows
+ * "+" when it is non-empty, and `useProcessReactions` renders a reaction only when its
+ * type is a known option — so without this map an arbitrary-emoji reaction can be sent
+ * but not displayed.
+ *
+ * The dataset is fetched through the same lazily code-split dynamic import the picker
+ * uses (and the result is memoized), so importing this loader costs nothing until it is
+ * actually called and the ~340 KB JSON never lands in an app's initial bundle.
+ * Integrators call it once — e.g. in an effect — and merge the result into their
+ * reaction options; see the emoji migration notes in `AI.md`.
+ */
+export const loadDefaultExtendedReactionOptions = memoizeAsyncWithReset(async () =>
+ mapEmojiMartData(await loadEmojiData()),
+);
diff --git a/src/plugins/Emojis/search/EmojiSearchIndex.ts b/src/plugins/Emojis/search/EmojiSearchIndex.ts
new file mode 100644
index 000000000..ee9382a56
--- /dev/null
+++ b/src/plugins/Emojis/search/EmojiSearchIndex.ts
@@ -0,0 +1,37 @@
+import type {
+ EmojiSearchIndex,
+ EmojiSearchIndexResult,
+} from '../../../components/MessageComposer';
+import { loadEmojiData } from '../data';
+import { memoizeAsyncWithReset } from '../memoizeAsyncWithReset';
+import { buildEmojiSearchData, type SearchableEmoji } from './buildEmojiSearchData';
+import { runSearch } from './search';
+
+// Memoized, but dropped on failure so a transient dataset-load error does not
+// permanently poison the shared search index used by the composer middleware.
+const getIndex = memoizeAsyncWithReset(() =>
+ loadEmojiData().then(buildEmojiSearchData),
+);
+
+const toResult = (emoji: SearchableEmoji): EmojiSearchIndexResult => ({
+ emoticons: emoji.emoticons,
+ id: emoji.id,
+ name: emoji.name,
+ native: emoji.native,
+ skins: emoji.skins,
+});
+
+/**
+ * The built-in, `emoji-mart`-free implementation of the {@link EmojiSearchIndex}
+ * interface consumed by `createTextComposerEmojiMiddleware` and the emoji picker.
+ * It self-initializes: the vendored dataset is loaded and the search index built
+ * lazily on first `search()` call, then memoized. An empty query resolves to `[]`
+ * (functionally equivalent to emoji-mart's `null`, which the middleware coerces).
+ */
+export const defaultEmojiSearchIndex: EmojiSearchIndex = {
+ search: async (query: string) => {
+ if (!query || !query.trim()) return [];
+ const results = runSearch(await getIndex(), query);
+ return results ? results.map(toResult) : [];
+ },
+};
diff --git a/src/plugins/Emojis/search/__tests__/EmojiSearchIndex.test.ts b/src/plugins/Emojis/search/__tests__/EmojiSearchIndex.test.ts
new file mode 100644
index 000000000..b7be9f36a
--- /dev/null
+++ b/src/plugins/Emojis/search/__tests__/EmojiSearchIndex.test.ts
@@ -0,0 +1,34 @@
+import { defaultEmojiSearchIndex } from '../EmojiSearchIndex';
+
+describe('defaultEmojiSearchIndex', () => {
+ it('satisfies the EmojiSearchIndex interface (async search)', () => {
+ expect(typeof defaultEmojiSearchIndex.search).toBe('function');
+ });
+
+ it('resolves to [] for an empty query', async () => {
+ await expect(defaultEmojiSearchIndex.search('')).resolves.toEqual([]);
+ await expect(defaultEmojiSearchIndex.search(' ')).resolves.toEqual([]);
+ });
+
+ it('lazily builds the index and returns EmojiSearchIndexResult-shaped items', async () => {
+ const results = (await defaultEmojiSearchIndex.search('fire')) ?? [];
+ expect(results.length).toBeGreaterThan(0);
+ const [first] = results;
+ expect(first).toEqual(
+ expect.objectContaining({
+ id: 'fire',
+ name: 'Fire',
+ native: '🔥',
+ }),
+ );
+ expect(Array.isArray(first.skins)).toBe(true);
+ expect(first.skins[0]).toHaveProperty('native');
+ });
+
+ it('reuses the memoized index across calls', async () => {
+ const first = (await defaultEmojiSearchIndex.search('smile')) ?? [];
+ const second = (await defaultEmojiSearchIndex.search('smile')) ?? [];
+ expect(second.map((emoji) => emoji.id)).toEqual(first.map((emoji) => emoji.id));
+ expect(first[0]?.id).toBe('smile');
+ });
+});
diff --git a/src/plugins/Emojis/search/__tests__/buildEmojiSearchData.test.ts b/src/plugins/Emojis/search/__tests__/buildEmojiSearchData.test.ts
new file mode 100644
index 000000000..3a3c286c8
--- /dev/null
+++ b/src/plugins/Emojis/search/__tests__/buildEmojiSearchData.test.ts
@@ -0,0 +1,35 @@
+import { buildEmojiSearchData } from '../buildEmojiSearchData';
+import type { EmojiData } from '../../data/types';
+
+const makeData = (): EmojiData =>
+ ({
+ aliases: {},
+ categories: [],
+ emojis: {
+ smile: {
+ id: 'smile',
+ keywords: ['happy'],
+ name: 'Smile',
+ skins: [{ native: '😄', unified: '1f604' }],
+ version: 1,
+ },
+ },
+ }) as unknown as EmojiData;
+
+describe('buildEmojiSearchData', () => {
+ it('memoizes by data object so the panel and middleware share a single build', () => {
+ const data = makeData();
+ expect(buildEmojiSearchData(data)).toBe(buildEmojiSearchData(data));
+ });
+
+ it('builds a distinct index for a different data object', () => {
+ expect(buildEmojiSearchData(makeData())).not.toBe(buildEmojiSearchData(makeData()));
+ });
+
+ it('produces a comma-anchored haystack and resolves the native glyph', () => {
+ const [entry] = buildEmojiSearchData(makeData());
+ expect(entry.id).toBe('smile');
+ expect(entry.search).toContain(',smile');
+ expect(entry.native).toBe('😄');
+ });
+});
diff --git a/src/plugins/Emojis/search/__tests__/search.test.ts b/src/plugins/Emojis/search/__tests__/search.test.ts
new file mode 100644
index 000000000..7d89df922
--- /dev/null
+++ b/src/plugins/Emojis/search/__tests__/search.test.ts
@@ -0,0 +1,108 @@
+import emojiData from '../../data/emoji-data.json';
+import type { EmojiData } from '../../data/types';
+import { buildEmojiSearchData, type SearchableEmoji } from '../buildEmojiSearchData';
+import { runSearch } from '../search';
+
+const index = buildEmojiSearchData(emojiData as unknown as EmojiData);
+const ids = (results: SearchableEmoji[] | null) =>
+ (results ?? []).map((emoji) => emoji.id);
+
+describe('runSearch (against the vendored dataset)', () => {
+ it('returns null for an empty or whitespace-only query', () => {
+ expect(runSearch(index, '')).toBeNull();
+ expect(runSearch(index, ' ')).toBeNull();
+ });
+
+ it('ranks an exact id match first', () => {
+ expect(ids(runSearch(index, 'fire'))[0]).toBe('fire');
+ expect(ids(runSearch(index, 'smile'))[0]).toBe('smile');
+ });
+
+ it('matches keywords by comma-anchored token prefix', () => {
+ const thumbs = ids(runSearch(index, 'thumb'));
+ expect(thumbs).toContain('+1'); // "Thumbs Up" via the "thumbsup" keyword
+ expect(thumbs).toContain('-1'); // "Thumbs Down" via the "thumbsdown" keyword
+ });
+
+ it('matches (lowercased) emoticons', () => {
+ const results = runSearch(index, ':)') ?? [];
+ expect(results.length).toBeGreaterThan(0);
+ expect(results.some((emoji) => emoji.emoticons?.includes(':)'))).toBe(true);
+ });
+
+ it('applies AND semantics across multiple words', () => {
+ const results = runSearch(index, 'red heart') ?? [];
+ expect(results.map((emoji) => emoji.id)).toContain('heart'); // "Red Heart"
+ // Every result matched BOTH words as comma-anchored tokens — mirroring runSearch's
+ // own `indexOf(",word")`, not a loose substring that a match like "tired" would pass.
+ expect(
+ results.every(
+ (emoji) => emoji.search.includes(',red') && emoji.search.includes(',heart'),
+ ),
+ ).toBe(true);
+ });
+
+ it('resolves the native character on each result', () => {
+ const [first] = runSearch(index, 'fire') ?? [];
+ expect(first.native).toBe('🔥');
+ });
+
+ it('respects the maxResults cap', () => {
+ const capped = runSearch(index, 'face', { maxResults: 5 }) ?? [];
+ expect(capped.length).toBeLessThanOrEqual(5);
+ expect(capped.length).toBeGreaterThan(0);
+ });
+});
+
+describe('runSearch (ranking details, synthetic data)', () => {
+ const tiny = buildEmojiSearchData({
+ aliases: {},
+ categories: [],
+ emojis: {
+ aaa: {
+ id: 'aaa',
+ keywords: [],
+ name: 'First',
+ skins: [{ native: '①', unified: '' }],
+ version: 1,
+ },
+ bbb: {
+ id: 'bbb',
+ keywords: ['aaa'],
+ name: 'Second',
+ skins: [{ native: '②', unified: '' }],
+ version: 1,
+ },
+ // Equal-length names (and ids) so the shared "tie" keyword lands at the same
+ // haystack offset in both — giving an actual score tie that the id.localeCompare
+ // tie-break must resolve (otherwise score alone would decide the order).
+ ccc: {
+ id: 'ccc',
+ keywords: ['tie'],
+ name: 'Cat',
+ skins: [{ native: '③', unified: '' }],
+ version: 1,
+ },
+ ddd: {
+ id: 'ddd',
+ keywords: ['tie'],
+ name: 'Dog',
+ skins: [{ native: '④', unified: '' }],
+ version: 1,
+ },
+ },
+ } as EmojiData);
+
+ it('returns a single match unsorted when fewer than two results', () => {
+ expect(runSearch(tiny, 'first')?.map((emoji) => emoji.id)).toEqual(['aaa']);
+ });
+
+ it('scores an exact id match as 0 so it ranks before keyword matches', () => {
+ // "aaa" is the id of emoji aaa (score 0) and a keyword of emoji bbb (score > 0)
+ expect(runSearch(tiny, 'aaa')?.map((emoji) => emoji.id)).toEqual(['aaa', 'bbb']);
+ });
+
+ it('breaks score ties with id.localeCompare', () => {
+ expect(runSearch(tiny, 'tie')?.map((emoji) => emoji.id)).toEqual(['ccc', 'ddd']);
+ });
+});
diff --git a/src/plugins/Emojis/search/buildEmojiSearchData.ts b/src/plugins/Emojis/search/buildEmojiSearchData.ts
new file mode 100644
index 000000000..bba983b23
--- /dev/null
+++ b/src/plugins/Emojis/search/buildEmojiSearchData.ts
@@ -0,0 +1,70 @@
+import type { EmojiData, EmojiDataEmoji, EmojiDataSkin } from '../data';
+
+export type SearchableEmoji = {
+ id: string;
+ name: string;
+ native: string;
+ /** Comma-prefixed, lowercased haystack — mirrors emoji-mart's `emoji.search`. */
+ search: string;
+ skins: EmojiDataSkin[];
+ emoticons?: string[];
+};
+
+// Mirrors emoji-mart's SearchIndex haystack construction (module.js): id (not
+// tokenized), name (tokenized on /[-|_|\s]+/), keywords and emoticons (not
+// tokenized) — all lowercased and comma-joined — followed by each skin's native.
+const buildHaystack = (emoji: EmojiDataEmoji): string => {
+ const fields: Array<[string | string[] | undefined, boolean]> = [
+ [emoji.id, false],
+ [emoji.name, true],
+ [emoji.keywords, false],
+ [emoji.emoticons, false],
+ ];
+
+ const tokens = fields
+ .map(([strings, split]) => {
+ if (!strings) return [];
+ return (Array.isArray(strings) ? strings : [strings])
+ .map((string) =>
+ (split ? string.split(/[-|_|\s]+/) : [string]).map((part) =>
+ part.toLowerCase(),
+ ),
+ )
+ .flat();
+ })
+ .flat()
+ .filter((token) => token && token.trim());
+
+ let haystack = `,${tokens.join(',')}`;
+ for (const skin of emoji.skins) {
+ if (skin?.native) haystack += `,${skin.native}`;
+ }
+ return haystack;
+};
+
+// Cache the built index per data object. The dataset is loaded once (a memoized dynamic
+// import), so the picker panel and the composer middleware pass the same object here and
+// share a single ~1,900-entry build instead of computing it twice.
+const cache = new WeakMap();
+
+/**
+ * Transforms the vendored emoji dataset into a flat, search-ready index (memoized by the
+ * data object). Pure and side-effect free — the produced `search` haystack matches
+ * emoji-mart's format so that ranking parity with `emoji-mart`'s `SearchIndex` is
+ * preserved.
+ */
+export const buildEmojiSearchData = (data: EmojiData): SearchableEmoji[] => {
+ const cached = cache.get(data);
+ if (cached) return cached;
+
+ const built = Object.values(data.emojis).map((emoji) => ({
+ emoticons: emoji.emoticons,
+ id: emoji.id,
+ name: emoji.name,
+ native: emoji.skins[0]?.native ?? '',
+ search: buildHaystack(emoji),
+ skins: emoji.skins,
+ }));
+ cache.set(data, built);
+ return built;
+};
diff --git a/src/plugins/Emojis/search/index.ts b/src/plugins/Emojis/search/index.ts
new file mode 100644
index 000000000..e59a35752
--- /dev/null
+++ b/src/plugins/Emojis/search/index.ts
@@ -0,0 +1,3 @@
+export * from './buildEmojiSearchData';
+export * from './EmojiSearchIndex';
+export * from './search';
diff --git a/src/plugins/Emojis/search/search.ts b/src/plugins/Emojis/search/search.ts
new file mode 100644
index 000000000..11be95dd4
--- /dev/null
+++ b/src/plugins/Emojis/search/search.ts
@@ -0,0 +1,61 @@
+import type { SearchableEmoji } from './buildEmojiSearchData';
+
+export type RunSearchOptions = {
+ maxResults?: number;
+};
+
+/**
+ * Ranked emoji search replicating emoji-mart's `SearchIndex.search` (module.js):
+ * lowercase the query, turn the first `word-` into `word ` (space), split on
+ * whitespace/`|`/`,`, dedupe, then AND-intersect the pool across words — scoring
+ * each emoji by the position of `,` in its haystack. Lower score (earlier
+ * match) ranks first; an exact id match scores 0; ties break by `id.localeCompare`.
+ *
+ * Returns `null` for an empty query (parity with emoji-mart), an empty array when
+ * the query yields no usable words, otherwise the ranked matches capped at
+ * `maxResults` (default 90).
+ */
+export const runSearch = (
+ index: SearchableEmoji[],
+ value: string,
+ { maxResults = 90 }: RunSearchOptions = {},
+): SearchableEmoji[] | null => {
+ if (!value || !value.trim().length) return null;
+
+ const words = value
+ .toLowerCase()
+ .replace(/(\w)-/, '$1 ')
+ .split(/[\s|,]+/)
+ .filter((word, position, all) => word.trim() && all.indexOf(word) === position);
+
+ if (!words.length) return [];
+
+ let pool = index;
+ let results: SearchableEmoji[] = [];
+ let scores: Record = {};
+
+ for (const word of words) {
+ if (!pool.length) break;
+ results = [];
+ scores = {};
+ for (const emoji of pool) {
+ if (!emoji.search) continue;
+ const score = emoji.search.indexOf(`,${word}`);
+ if (score === -1) continue;
+ results.push(emoji);
+ scores[emoji.id] = (scores[emoji.id] ?? 0) + (emoji.id === word ? 0 : score + 1);
+ }
+ pool = results;
+ }
+
+ if (results.length < 2) return results;
+
+ results.sort((a, b) => {
+ const aScore = scores[a.id];
+ const bScore = scores[b.id];
+ if (aScore === bScore) return a.id.localeCompare(b.id);
+ return aScore - bScore;
+ });
+
+ return results.length > maxResults ? results.slice(0, maxResults) : results;
+};
diff --git a/src/plugins/Emojis/styling/EmojiPicker.scss b/src/plugins/Emojis/styling/EmojiPicker.scss
index 2bd0aadea..bebc52556 100644
--- a/src/plugins/Emojis/styling/EmojiPicker.scss
+++ b/src/plugins/Emojis/styling/EmojiPicker.scss
@@ -1,11 +1,368 @@
-$emoji-picker-border-radius: 10px;
+@use '../../../styling/utils';
+@use '../../../styling/light' as light;
-.str-chat__message-textarea-emoji-picker-container {
- border-radius: $emoji-picker-border-radius;
- box-shadow: var(--str-chat__box-shadow-3);
- overflow: hidden;
+$emoji-picker-border-radius: 12px;
- em-emoji-picker {
- --border-radius: #{$emoji-picker-border-radius};
+.str-chat {
+ .str-chat__message-textarea-emoji-picker-container {
+ border-radius: $emoji-picker-border-radius;
+ box-shadow: var(--str-chat__box-shadow-3);
+ overflow: hidden;
}
+
+ .str-chat__emoji-picker {
+ // Component tokens — resolved from semantic tokens. With `theme='auto'` these
+ // inherit the ancestor `.str-chat__theme-*`; with a forced `theme` the semantic
+ // tokens are re-asserted on the panel below so the override wins regardless of
+ // the ancestor theme.
+ --str-chat__emoji-picker-background-color: var(
+ --str-chat__background-core-surface-card
+ );
+ --str-chat__emoji-picker-text-color: var(--str-chat__text-primary);
+ --str-chat__emoji-picker-secondary-text-color: var(--str-chat__text-secondary);
+ --str-chat__emoji-picker-hover-background-color: var(
+ --str-chat__background-utility-hover
+ );
+ --str-chat__emoji-picker-selected-background-color: var(
+ --str-chat__background-utility-selected
+ );
+ --str-chat__emoji-picker-border-color: var(--str-chat__border-core-on-surface);
+ // Gentle hairline for the search/footer dividers (the default on-surface border is
+ // intentionally strong and reads as too heavy here).
+ --str-chat__emoji-picker-separator-color: var(--str-chat__border-core-subtle);
+ // A soft grey fill for the search field (the app background token is white).
+ --str-chat__emoji-picker-search-background-color: var(
+ --str-chat__background-utility-hover
+ );
+ --str-chat__emoji-picker-active-indicator-color: var(--str-chat__accent-primary);
+ --str-chat__emoji-picker-width: 22.5rem;
+ --str-chat__emoji-picker-height: 27.5rem;
+ --str-chat__emoji-picker-emoji-size: 1.5rem;
+
+ display: flex;
+ flex-direction: column;
+ inline-size: var(--str-chat__emoji-picker-width);
+ max-inline-size: 100%;
+ block-size: var(--str-chat__emoji-picker-height);
+ background-color: var(--str-chat__emoji-picker-background-color);
+ color: var(--str-chat__emoji-picker-text-color);
+ font: var(--str-chat__font-body-default);
+
+ // The whole row is styled as one filled search field, with the icon inside it.
+ &__search {
+ display: flex;
+ align-items: center;
+ gap: var(--str-chat__spacing-xs);
+ margin: var(--str-chat__spacing-xs) var(--str-chat__spacing-sm)
+ var(--str-chat__spacing-sm);
+ // No inline padding: the icon's inset already comes from the flex `gap` after
+ // the visually-hidden label (the first flex child). Adding padding here would
+ // stack on top of that gap and push the icon deeper into the field.
+ min-block-size: 2rem;
+ border-radius: var(--str-chat__radius-8);
+ background-color: var(--str-chat__emoji-picker-search-background-color);
+
+ &:focus-within {
+ @include utils.focusable;
+ }
+
+ .str-chat__icon {
+ flex: none;
+ inline-size: 1rem;
+ block-size: 1rem;
+ color: var(--str-chat__emoji-picker-secondary-text-color);
+ }
+ }
+
+ &__search-input {
+ flex: 1 1 auto;
+ min-inline-size: 0;
+ border: none;
+ background: transparent;
+ color: inherit;
+ font: inherit;
+ font-size: 0.875rem;
+ line-height: 1.5;
+
+ // The filled field shows focus via `:focus-within`, so the input itself doesn't.
+ &:focus,
+ &:focus-visible {
+ outline: none;
+ }
+
+ &::placeholder {
+ color: var(--str-chat__emoji-picker-secondary-text-color);
+ }
+ }
+
+ &__search-clear {
+ flex: none;
+ }
+
+ &__empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: var(--str-chat__spacing-xs);
+ min-block-size: 12rem;
+ padding: var(--str-chat__spacing-md);
+ color: var(--str-chat__emoji-picker-secondary-text-color);
+ text-align: center;
+ }
+
+ &__empty-emoji {
+ font-size: 2rem;
+ line-height: 1;
+ }
+
+ &__category-nav {
+ display: flex;
+ align-items: stretch;
+ gap: var(--str-chat__spacing-xxs);
+ padding: var(--str-chat__spacing-xs) var(--str-chat__spacing-sm) 0;
+ }
+
+ &__category-nav-button {
+ @include utils.button-reset;
+ cursor: pointer;
+ position: relative;
+ display: flex;
+ flex: 1 1 auto;
+ align-items: center;
+ justify-content: center;
+ padding-block: var(--str-chat__spacing-xs);
+ font-size: 1.125rem;
+ line-height: 1;
+ // Muted tabs; the active one is emphasized with an underline bar (like
+ // emoji-mart) rather than a filled background.
+ opacity: 0.55;
+
+ &:hover {
+ opacity: 0.85;
+ }
+
+ &:focus-visible {
+ @include utils.focusable;
+ }
+
+ &--active {
+ opacity: 1;
+
+ &::after {
+ content: '';
+ position: absolute;
+ inset-inline: 15%;
+ inset-block-end: 0;
+ block-size: 2px;
+ border-radius: 2px 2px 0 0;
+ background-color: var(--str-chat__emoji-picker-active-indicator-color);
+ }
+ }
+ }
+
+ &__body {
+ flex: 1 1 auto;
+ min-block-size: 0;
+ border-block-start: 1px solid var(--str-chat__emoji-picker-separator-color);
+ }
+
+ &__grid-container {
+ @include utils.scrollable-y;
+ block-size: 100%;
+ padding-inline: var(--str-chat__spacing-xs);
+ }
+
+ &__category {
+ padding-inline: var(--str-chat__spacing-xs);
+
+ &-label {
+ position: sticky;
+ inset-block-start: 0;
+ z-index: 1;
+ padding-block: var(--str-chat__spacing-xs) var(--str-chat__spacing-xxs);
+ background-color: var(--str-chat__emoji-picker-background-color);
+ color: var(--str-chat__emoji-picker-secondary-text-color);
+ font-size: 0.8125rem;
+ font-weight: 500;
+ }
+
+ &-emojis {
+ display: grid;
+ // Fixed column count driven by the `perLine` option (default 9); cells share the
+ // row evenly with a real gap so the grid breathes rather than packing tight.
+ grid-template-columns: repeat(
+ var(--str-chat__emoji-picker-per-line, 9),
+ minmax(0, 1fr)
+ );
+ gap: var(--str-chat__spacing-xs);
+ padding-block-end: var(--str-chat__spacing-xs);
+ }
+
+ // Pin the "frequently used" section to a single row. The panel caps its ids to
+ // FREQUENTLY_USED_LIMIT (see frequentlyUsed.ts) and these fixed columns match the
+ // default grid width, so it fills one aligned row and never wraps to a second as
+ // more emoji are used. (Uses the literal child class, not `&-emojis`, so the
+ // combinator doesn't re-expand the whole parent chain.)
+ &[data-category-id='frequent'] > .str-chat__emoji-picker__category-emojis {
+ grid-template-columns: repeat(
+ var(--str-chat__emoji-picker-per-line, 9),
+ minmax(0, 1fr)
+ );
+ }
+ }
+
+ &__emoji {
+ @include utils.button-reset;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ aspect-ratio: 1 / 1;
+ inline-size: 100%;
+ border-radius: var(--str-chat__radius-4);
+ font-size: var(--str-chat__emoji-picker-emoji-size);
+ line-height: 1;
+
+ &:hover {
+ background-color: var(--str-chat__emoji-picker-hover-background-color);
+ }
+
+ &:focus-visible {
+ @include utils.focusable;
+ }
+ }
+
+ &__footer {
+ display: flex;
+ align-items: center;
+ gap: var(--str-chat__spacing-sm);
+ min-block-size: 2.75rem;
+ padding: var(--str-chat__spacing-xs) var(--str-chat__spacing-sm);
+ border-block-start: 1px solid var(--str-chat__emoji-picker-separator-color);
+ }
+
+ &__preview {
+ display: flex;
+ flex: 1 1 auto;
+ align-items: center;
+ gap: var(--str-chat__spacing-sm);
+ min-inline-size: 0;
+
+ &-emoji {
+ flex: none;
+ font-size: 1.5rem;
+ line-height: 1;
+ }
+
+ // Name (prominent) stacked over the `:shortcode:` (muted), both truncated.
+ &-text {
+ display: flex;
+ flex-direction: column;
+ min-inline-size: 0;
+ line-height: 1.2;
+ }
+
+ &-name {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ font-size: 0.875rem;
+ }
+
+ &-shortcode {
+ overflow: hidden;
+ color: var(--str-chat__emoji-picker-secondary-text-color);
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ font-size: 0.8125rem;
+ }
+ }
+
+ &__skin-tones {
+ display: flex;
+ flex: none;
+ align-items: center;
+ gap: var(--str-chat__spacing-xxs);
+ }
+
+ &__skin-tone-toggle,
+ &__skin-tone {
+ @include utils.button-reset;
+ cursor: pointer;
+ display: flex;
+ flex: none;
+ align-items: center;
+ justify-content: center;
+ padding: var(--str-chat__spacing-xxs);
+ border-radius: var(--str-chat__radius-4);
+ font-size: 1.25rem;
+ line-height: 1;
+
+ &:hover {
+ background-color: var(--str-chat__emoji-picker-hover-background-color);
+ }
+
+ &:focus-visible {
+ @include utils.focusable;
+ }
+ }
+
+ &__skin-tone--active {
+ background-color: var(--str-chat__emoji-picker-selected-background-color);
+ }
+
+ &__loading {
+ flex: 1 1 auto;
+ min-block-size: 12rem;
+ }
+
+ &__error {
+ display: flex;
+ flex: 1 1 auto;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: var(--str-chat__spacing-sm);
+ min-block-size: 12rem;
+ padding: var(--str-chat__spacing-md);
+ color: var(--str-chat__emoji-picker-secondary-text-color);
+ text-align: center;
+ }
+
+ &__error-retry {
+ @include utils.button-reset;
+ cursor: pointer;
+ padding: var(--str-chat__spacing-xs) var(--str-chat__spacing-md);
+ border: 1px solid var(--str-chat__emoji-picker-border-color);
+ border-radius: var(--str-chat__radius-8);
+ color: var(--str-chat__emoji-picker-text-color);
+ font: inherit;
+
+ &:hover {
+ background-color: var(--str-chat__emoji-picker-hover-background-color);
+ }
+
+ &:focus-visible {
+ @include utils.focusable;
+ }
+ }
+ }
+}
+
+// Forced light theme (`pickerProps.theme='light'`).
+//
+// The SDK's global theme rules (variable-tokens.scss) treat light as the `.str-chat`
+// default and apply dark via `.str-chat__theme-dark`; there is no rule that asserts
+// light values for a `.str-chat__theme-light` class. So a picker forced to light while
+// nested in a `.str-chat__theme-dark` ancestor would inherit the ancestor's dark tokens.
+// Re-assert the full light set on the forced-light panel so it wins over any inherited
+// theme — mirroring how variable-tokens.scss emits `light.variables` for the
+// `.str-chat__theme-dark .str-chat__theme-inverse` ("light inside dark") case.
+//
+// `theme='dark'` needs no equivalent block: the panel carries `.str-chat__theme-dark`,
+// which the global rule (always loaded via index.css) already matches. `theme='auto'`
+// intentionally inherits the ancestor theme.
+.str-chat__emoji-picker.str-chat__theme-light {
+ @include light.variables;
}
diff --git a/src/styling/_emoji-replacement.scss b/src/styling/_emoji-replacement.scss
index 5d6170dfb..1c34a7b56 100644
--- a/src/styling/_emoji-replacement.scss
+++ b/src/styling/_emoji-replacement.scss
@@ -21,7 +21,8 @@ $emoji-flag-unicode-range: U+1F1E6-1F1FF;
.str-chat__message-textarea,
.str-chat__message-text-inner *,
.str-chat__emoji-item--entity,
- .emoji-mart-emoji-native * {
+ .str-chat__emoji-picker__emoji,
+ .str-chat__emoji-picker__preview-emoji {
font-family: ReplaceFlagEmojiPNG, var(--str-chat__font-family), sans-serif;
font-display: swap;
}
@@ -33,7 +34,8 @@ $emoji-flag-unicode-range: U+1F1E6-1F1FF;
.str-chat__message-textarea,
.str-chat__message-text-inner *,
.str-chat__emoji-item--entity,
- .emoji-mart-emoji-native * {
+ .str-chat__emoji-picker__emoji,
+ .str-chat__emoji-picker__preview-emoji {
font-family: ReplaceFlagEmojiSVG, var(--str-chat__font-family), sans-serif;
font-display: swap;
}
diff --git a/yarn.lock b/yarn.lock
index 5197cd485..dbceada6f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -614,7 +614,7 @@ __metadata:
languageName: node
linkType: hard
-"@emoji-mart/data@npm:^1.2.1":
+"@emoji-mart/data@npm:1.2.1, @emoji-mart/data@npm:^1.2.1":
version: 1.2.1
resolution: "@emoji-mart/data@npm:1.2.1"
checksum: 10c0/6784b97bf49a0d3ff110d8447bbd3b0449fcbc497294be3d1c3a6cb1609308776895c7520200be604cbecaa5e172c76927e47f34419c72ba8a76fd4e5a53674b
@@ -2072,11 +2072,9 @@ __metadata:
version: 0.0.0-use.local
resolution: "@stream-io/stream-chat-react-tutorial@workspace:examples/tutorial"
dependencies:
- "@emoji-mart/data": "npm:^1.2.1"
"@types/react": "npm:^19.2.15"
"@types/react-dom": "npm:^19.2.3"
"@vitejs/plugin-react": "npm:^6.0.3"
- emoji-mart: "npm:^5.6.0"
react: "npm:^19.2.6"
react-dom: "npm:^19.2.6"
stream-chat: "npm:^9.49.0"
@@ -2092,6 +2090,7 @@ __metadata:
dependencies:
"@babel/core": "npm:^7.29.0"
"@emoji-mart/data": "npm:^1.2.1"
+ "@emoji-mart/react": "npm:^1.1.1"
"@playwright/test": "npm:^1.60.0"
"@types/react": "npm:^19.2.15"
"@types/react-dom": "npm:^19.2.3"
@@ -10041,7 +10040,7 @@ __metadata:
"@breezystack/lamejs": "npm:^1.2.7"
"@commitlint/cli": "npm:^21.0.1"
"@commitlint/config-conventional": "npm:^21.0.1"
- "@emoji-mart/data": "npm:^1.2.1"
+ "@emoji-mart/data": "npm:1.2.1"
"@emoji-mart/react": "npm:^1.1.1"
"@eslint/js": "npm:^9.39.4"
"@floating-ui/react": "npm:^0.27.19"