Notes: Add full emoji picker behind a + button (stacked on #76767)#78176
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Adds the "+" More-emojis trigger as a sibling of the curated smiley trigger. Tapping it opens a lazy-loaded native picker built from SearchControl + Composite over Emojibase data served same-origin from the plugin (28 locales, fetched per-session on first open). Picks fold into the curated slug when they match (e.g. ❤ → `heart`) and store as a normalized hex-codepoint key otherwise (e.g. `1f44d` for 👍), so visually-equivalent presentations don't fragment the reaction_summary aggregation. The hex encode/decode pair and the HEX_KEY_RE fallback in getEmojiBySlug/getLabelBySlug come along for the ride, since they only ever fire when this picker is enabled. Stacked on the basic-reactions baseline so picker library and bundling choices can be reviewed independently, per t-hamano in #76767.
e05a3b0 to
6aa1aec
Compare
|
Size Change: +4.2 kB (+0.05%) Total Size: 7.83 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Carrying over from @swissspidy's review comment on the original PR, which now lives in this stacked PR:
Worth deciding before merge. Current setup bundles ~7 MB across 28 locales into the plugin's A few options:
@swissspidy what do you think? |
… into add-notes-emoji-reactions-full-picker Resolve conflicts from the base branch's reaction picker refactors: - reaction-emoji-picker.js: adopt the base branch's memoized buildEmojiBySlugMap for curated lookups while keeping the full picker's hex-codepoint helpers (emojiToHexKey/hexKeyToEmoji/ emojiToStorageKey). Drop the now-unused getEmojiBySlug/getLabelBySlug. - reaction-display.js: combine both sides' imports (inline smiley icon + plus icon, useMemo + lazy/Suspense) and decode hex-key slugs in the display fallback so full-picker reactions render as emoji rather than raw codepoints. - block-notes.spec.js: keep the horizontal-listbox keyboard-navigation comment that matches the merged Composite orientation.
Summary
Stacked on top of #76767 — review that PR first (curated 5-emoji reactions baseline). This PR adds the full searchable emoji picker behind a
+button next to the smiley trigger.Splitting this off per @t-hamano's request: library selection and bundling strategy still need wider discussion, so it shouldn't block the basic-reactions foundation.
Two-trigger picker UX
Each note now has two adjacent triggers:
Both buttons are independent siblings; the curated picker doesn't nest the full picker, so popovers never conflict.
Native picker built from WordPress primitives
Earlier iterations used Frimousse, an MIT-licensed React picker. @t-hamano flagged that Frimousse's UI strings come from Emojibase's
.pofiles — not on GlotPress, no coverage for many WordPress locales. Replaced with a native picker built fromSearchControlover aCompositegrid grouped by Emojibase category, with sticky headers andcontent-visibility: autoper row so all ~1949 emojis render quickly. All chrome strings (Search emoji,Loading…,No emoji found., skin tone label) route through__()and translate via the WordPress translation pipeline.packages/editor/src/components/collab-sidebar/emoji-picker.js:resolveEmojibaseLocale()maps a BCP-47 / WordPress locale (pt-BR,fr_FR,zh-TW) to the closest of Emojibase's 28 locales, falling back toen.useEmojibaseData(baseUrl, locale)fetchesdata.json+messages.jsononce per locale, with module-level cache and abort-on-unmount.<EmojiPicker>renders the grid with full keyboard nav viaComposite(same primitives WPDS uses).Storage normalization
Picks from the full picker are stored as a lowercase hex-codepoint sequence joined by
-, e.g.1f44dfor 👍 or1f468-200d-1f4bbfor 👨💻. Variation selector U+FE0F is stripped so visually-equivalent presentations collapse —2764-fe0f(❤️) folds into the curatedheartslug. The hex helpers (emojiToHexKey,hexKeyToEmoji,emojiToStorageKey) extendreaction-emoji-picker.jsand remain compatible with the curated slug storage from the base PR.Bundle-size strategy: lazy load + same-origin data
Two layers keep the editor bundle lean:
React.lazyinreaction-display.js. The picker code only ships when the user first opens the+popover in a session — for editors who never use the full picker, the picker module never loads at all.bin/copy-emojibase-data.mjs) copies per-localedata.json+messages.jsonfromnode_modules/emojibase-data/intobuild/emojibase-data/<locale>/after the main build runs (28 locales, ~7 MB on disk). PHP exposes the directory URL to JS viawindow.gutenbergEmojibaseUrl(set withwp_add_inline_script). Per-session network cost stays at one locale (~85 KB gzipped), only fetched when the user opens the + picker for the first time.For npm consumers of
@wordpress/editoroutside the plugin:emojibase-datais a Gutenberg root devDependency, not a runtime dep of the package. The+button hides itself whenwindow.gutenbergEmojibaseUrlis unset, so npm consumers must opt in by self-hosting the data and setting the global — there's no fallthrough to a third-party CDN.Per-locale label overrides
gutenberg_emoji_picker_label_overridesPHP filter lets sites override Emojibase emoji labels for any locale (e.g. when curated labels in the base PR differ from Emojibase's choice for the same code point). The overrides are exposed to JS via an inline script.Screencast
react.with.emoji.picker.mp4
Test plan
heartreactionzzzznoresults— verify empty-state messagenpm run test:e2e -- test/e2e/specs/editor/various/block-notes.spec.js(full-picker-specific tests)npm run test:unit packages/editor/src/components/collab-sidebar/test/emoji-picker.jsnpm run test:unit:php:base -- --filter=Emoji_Picker_Data