Skip to content

Emoji icon state

Keep picker state local to React while the application owns selection persistence and catalog policy.

Pure data operations

The pure core does not own React state. resolveEmojiIcon returns the selected record or null when the ID is missing, disabled, or the requested variantId is unknown. An explicit variant ID takes precedence over tone; without one, a matching tone is used when present, otherwise the base item is returned. Store the resolved variantId when a selection must retain its exact source variant.

recordEmojiIconUsage(records, id, now?) returns a new list with an incremented count and timestamp; it does not write storage. getFrequentEmojiIcons(catalog, records, limit?) sorts by count, recency, then catalog order and skips missing/disabled items. The caller chooses persistence, timestamp source, and whether history is appropriate.

React picker state

useEmojiIconPicker(options) adds independent per-instance React state for value, query, category, tone, and open. Each can be controlled with its value prop and corresponding on…Change, or initialized with default…. Uncontrolled defaults do not update after mount. closeOnSelect defaults to true; inline, disabled, and virtualized default to false; status defaults to ready.

onValueChange(value, item) reports the selection and its resolved item. It emits null when cleared; a missing or disabled selection is ignored. When controlled, the callback reports a request and the caller must pass the next value back. Query, category, tone, and open callbacks follow the same controlled-state pattern. Closing clears query, category, and active highlight. Changing tone updates an existing exact-variant selection through the resolver; if selection cannot resolve, it remains unchanged.

The following hook controls the selected value while leaving query, category, tone, and open state with the picker. Call picker.select to request a selection; onValueChange stores it and the next render supplies it back.

use-reaction-picker.tsx

useEmojiIconPickerContext() is exported from @ghost-ui/core/components/emoji-icon-picker; it reads state inside the styled component's EmojiIconPicker.Root and throws outside it. @ghost-ui/core/emoji-icon-picker-react provides the standalone state and loading hooks without importing the styled view. For view parts and layout, see Emoji Icon Picker.

Async catalog resolution

useEmojiIconCatalog(resolver, key?) calls a synchronous or async resolver with an AbortSignal, returning status, optional catalog/error, and reload. It aborts prior work on unmount or when resolver, key, or reload attempt changes; aborted results are ignored. During reload it retains the previous catalog while status is loading or error. A rejected resolver sets error; the hook does not retry, validate network payloads, or select a fallback. Keep the resolver stable with useCallback and implement response validation, caching, and recovery in the caller.

use-catalog.tsx

readItems is the application's response validator: return validated records or throw. Keep that function stable too. Its exception becomes the hook's error state; a TypeScript assertion on JSON would not perform this validation.

Selection and persistence

The styled view separates hover and keyboard highlight from the selected value. Those are presentation states, not persisted choices. The caller owns application state, storage, history, endpoint access, localization, and any pending/error feedback. A successful callback does not indicate server acceptance. See data contracts for stable IDs and API reference for operation signatures.

Loading into a view

For a remote/locale catalog, pass the hook's resolved catalog and status into EmojiIconPicker.Root. Show error/retry feedback from the loader and decide whether retained data can still be selected during a refresh. The hook retains the prior catalog after failure; that is not a successful load of the new locale. Keep the resolver stable and key it by every input that changes membership, such as workspace and locale.

Encode query parameters rather than concatenating arbitrary locale strings. Validate JSON at the network boundary before building the catalog; the catalog validates its required identity/content contract, not your complete server schema. Do not put storage, access policy or automatic downloads inside a render callback.

Troubleshooting

A saved selection can resolve to null after its source record is removed or disabled; keep a caller-owned fallback label and let the user choose again. A missing icon can be an unsupported provider/style combination rather than an empty query. A hook/context error can mean that a custom part uses a separately bundled context: import the styled context hook from the same component subpath as Root. If localized search finds nothing, verify the source labels/keywords and selected category before changing the engine.