|
| 1 | +## Summary |
| 2 | + |
| 3 | +Adds support for image-based custom emoji categories, frequently used emojis, and unified cross-type search — all as opt-in props on `<EmojiPicker.Root>`. |
| 4 | + |
| 5 | +## New Props |
| 6 | + |
| 7 | +| Prop | Type | Default | Description | |
| 8 | +| ----------------- | -------------------- | ------------------- | ----------- | |
| 9 | +| `custom` | `CustomCategory[]` | — | Image-based emoji categories appended after standard categories. | |
| 10 | +| `frequently` | `EmojiPickerEmoji[]` | — | Emojis shown in a "Frequently Used" category at the top. Hidden during search. | |
| 11 | +| `frequentlyLabel` | `string` | `"Frequently Used"` | Label for the frequently used category header. | |
| 12 | +| `unifiedSearch` | `boolean` | `false` | When `true`, all search results are merged into one ranked list. | |
| 13 | +| `searchLabel` | `string` | `""` | Category header label when `unifiedSearch` is active. | |
| 14 | + |
| 15 | +## New Types |
| 16 | + |
| 17 | +```ts |
| 18 | +type CustomEmoji = { id: string; label: string; url: string; tags?: string[]; }; |
| 19 | +type CustomCategory = { id: string; label: string; emojis: CustomEmoji[]; }; |
| 20 | +``` |
| 21 | + |
| 22 | +Both are exported from the package. `EmojiPickerRootProps` is augmented via intersection (not mutation) so the public type includes all new props. |
| 23 | + |
| 24 | +## New Exports |
| 25 | + |
| 26 | +- `CustomEmoji` — type for individual custom emoji |
| 27 | +- `CustomCategory` — type for a custom emoji category |
| 28 | + |
| 29 | +## Architecture |
| 30 | + |
| 31 | +All new code lives in dedicated files: |
| 32 | + |
| 33 | +- **`src/custom-emoji-types.ts`** — new types and `CustomEmojiRootProps` interface |
| 34 | +- **`src/data/custom-emoji.ts`** — `buildFrequentlyUsedRows`, `buildCustomCategoryRows`, `buildUnifiedSearchRows`, `scoreEmoji` (internal) |
| 35 | +- **`src/utils/emoji-identity.ts`** — `isSameEmoji` for comparing native and custom emojis |
| 36 | + |
| 37 | +Upstream files (`src/types.ts`, `src/data/emoji-picker.ts`, `src/components/emoji-picker.tsx`, `src/store.ts`) are touched minimally — each change is a delegation call or an optional-param addition at a single call site. |
| 38 | + |
| 39 | +### Search Scoring |
| 40 | + |
| 41 | +Custom emoji search mirrors the upstream `searchEmojis` scoring (+10 label match, +1 per tag match). `scoreEmoji` is extracted as a shared helper to reduce duplication within our own code. |
| 42 | + |
| 43 | +### Unified Search |
| 44 | + |
| 45 | +When `unifiedSearch` is enabled, `buildUnifiedSearchRows` merges native and custom emoji results into a single score-ranked list instead of displaying them in separate categories. |
| 46 | + |
| 47 | +### Type Widening |
| 48 | + |
| 49 | +`EmojiPickerEmoji` is widened to `{ emoji?: string; label: string; url?: string; id?: string }` to accommodate both native and custom emojis without casts. The upstream `EmojiPickerRootProps` export is shadowed in `src/index.ts` by an augmented version that includes `CustomEmojiRootProps`. |
| 50 | + |
| 51 | +## Bug Fixes |
| 52 | + |
| 53 | +- `sameEmojiPickerEmoji` in `store.ts`: fixed two bugs where custom emojis (with `emoji: undefined`) would always compare as equal, suppressing `useActiveEmoji()` updates. Now guards for `undefined` first and compares custom emojis by `id`. |
| 54 | + |
| 55 | +## Tests |
| 56 | + |
| 57 | +New test files: |
| 58 | +- `src/data/__tests__/custom-emoji.test.ts` — 15 tests for `scoreEmoji`, `buildFrequentlyUsedRows`, `buildCustomCategoryRows`, `buildUnifiedSearchRows` |
| 59 | +- `src/utils/__tests__/emoji-identity.test.ts` — 4 tests for `isSameEmoji` |
| 60 | + |
| 61 | +Extended: |
| 62 | +- `src/data/__tests__/emoji-picker.test.ts` — 9 new tests for custom categories, frequently used, and unified search |
| 63 | + |
| 64 | +## Docs |
| 65 | + |
| 66 | +See `CUSTOM-EMOJIS.md` for full usage documentation including examples, prop reference, and type definitions. |
0 commit comments