Skip to content

Add emoji picker with Autocomplete grid - #83538

Open
adamsilverstein wants to merge 453 commits into
trunkfrom
try/notes-emoji-picker-autocomplete-grid
Open

adamsilverstein wants to merge 453 commits into
trunkfrom
try/notes-emoji-picker-autocomplete-grid

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

An alternate take on #78176, so the two approaches can be compared side by side. Standalone against trunk: includes the changes from #76767 (previously stacked on it).

Fixes #75144

To keep this one reviewable, the filters for customizing the emoji set, exclusions, and labels moved to a stacked follow-up, #84043.

This round addresses the feedback from @mirka and @fcoveram. The picker now follows the documented Autocomplete patterns without patching the component's behavior, and the rough edges we hit are collected below under "Autocomplete notes" to pass back.

Claude reworked the picker and wrote up the changes:

What?

Rebuilds the Notes full emoji picker from #78176 on the Design System Autocomplete primitive from @wordpress/ui, in its grid mode (inline, always open), instead of the Composite grid plus SearchControl from @wordpress/components.

Why?

Addresses @fcoveram's keyboard feedback on #78176: getting from the search field to the grid took several Tab presses. With Autocomplete the search field is a combobox that drives the grid through aria-activedescendant, which is the macOS behavior from the review:

  • focus stays in the search field
  • the arrow keys move a highlight through the grid, crossing category boundaries
  • Enter picks the highlighted emoji
  • after typing, the top result is highlighted, so type + Enter picks it
  • one Tab reaches the skin-tone button

How?

  • Every reaction, including the five quick ones, is stored as its Emojibase hex key (2764, 1f680), and reaction_summary is keyed the same way. The server accepts a valid hex key and nothing else.
  • If the Emojibase data cannot load, the picker shows "Couldn't load emojis." instead of falling back to the quick reactions.
  • Composed like the documented async items story (https://wordpress.github.io/gutenberg/?path=/docs/design-system-components-form-primitives-autocomplete--docs#async-items): the results go to Autocomplete.Root through items, and Autocomplete.Status and Autocomplete.Empty handle the loading state, the result count, and the empty state. The list stays mounted.
  • filter={ null } instead of mode="none", so aria-autocomplete stays accurate. Filtering is still ours (curated labels, Emojibase labels and tags): items holds the already-filtered results, as category groups while browsing and a flat list while searching.
  • The speak() count announcements, the item-press guard on onValueChange, and the scroll reset on each query are gone. The component's own behavior applies: Status announces, and autoHighlight scrolls the top hit into view.
  • Autocomplete.Group / GroupLabel / Row / Item render grid, rowgroup (labelled by the heading), row, and gridcell.
  • The input is the Design System Input with a search icon prefix and an Autocomplete.Clear suffix.
  • Spacing per @fcoveram's review: gap-sm between the search field and the skin-tone toggle, no extra space below each row or around the list, and group labels keep the Autocomplete inline padding.
  • The popover no longer jumps when it opens or collapses when a search has no results (@mirka's video). The grid's width is held on the list and on the loading state, so the popover keeps one size throughout.

Autocomplete notes

@mirka asked to hear about styling difficulties with the current Autocomplete. These are the places where the picker still has to add its own styles, plus a couple of behaviors worth documenting. None of them patch the component; they are listed here so they can go back into Autocomplete or its docs if that makes sense.

  1. Inline mode has no width when empty. With inline, nothing gives the list an intrinsic width, so when Empty shows (or while loading) the container collapses to the padding and a surrounding popover resizes and repositions. Popup has width variants; inline has nothing comparable. The picker sets min-inline-size on the List.
  2. Sticky group labels. Long grouped lists read better with the heading pinned while its section scrolls. GroupLabel has no background, so making it sticky means adding position: sticky, a z-index, and a background that matches whatever surface it sits on (here the @wordpress/components popover's $white, which is not a token).
  3. Item styles assume a list row. Item brings margin-inline, asymmetric inline padding for a leading icon, left alignment, and a size-md min height. A grid cell wants a centered square with no padding, so the picker overrides justify-content, height, padding, and font-size. The Grid story does the same with inline styles, so a cell size or variant for grid mode might be worth having.
  4. Row layout is left to the consumer. Row has no layout styles, so the column template and gap are the picker's. Probably intended, but a line in the docs (or a columns option) would help the next grid.
  5. Inline scroll container. The List styles are built for Popup's grid areas (scrollable / footer, and Empty uses grid-area: main). Inline, the consumer brings its own scroll container, so scrollbar-gutter and the scroll-padding that keeps a highlighted cell clear of a sticky heading are ours. Documenting ListBody as the inline scroll container might cover this.
  6. Status updates on every keystroke. The count re-renders in the polite live region per keystroke. The previous version debounced it by 500ms, like the block inserter, so screen readers hear the settled count. Not tested with a screen reader yet; a debounce option or docs guidance could help.
  7. Pressing an item writes its value into the input. onValueChange fires with reason item-press and the item's string value. Harmless here, since picking closes the popover (in testing the field kept the query until it unmounted), but a picker that stays open would need to filter on reason. Worth a note in the docs.
  8. Performance with ~1,900 items. All 1,919 cells mount; rows use content-visibility: auto. In headless Chromium on a Mac: open 165-190ms, first keystroke ~40ms, later keystrokes under 20ms, clearing the search ~55ms. No virtualization needed at this size; it was not tried with grid.

Comparison with #78176

Measured before this round, in headless Chromium against the same wp-env, same Emojibase data (1,919 gridcells), dataset already cached, median of 7 opens, two runs each. Open time is from the click to the painted grid.

#78176 (Composite) This PR (Autocomplete grid)
Search field to grid Several Tabs, then roving tabindex Arrow keys from the field, focus stays in the field
Enter on a search result Tab into the grid first Picks the highlighted (top) result
Crosses categories with arrows Yes Yes
Input semantics searchbox + separate grid combobox with aria-haspopup="grid", aria-controls, aria-activedescendant
Open, median 329-344ms 210-274ms
Longest task on open 245-262ms 78-112ms
Type one letter ("h") ~124ms 67-76ms
Clear the search 95-98ms 105-121ms

Timings move by a few tens of ms between runs, so read them as "not slower" more than as a precise speedup. The numbers after switching to items are in note 8 above; they were taken with a different harness, so they are not directly comparable to the table.

Risks and open questions

  • The search field is a combobox, not a searchbox. Screen reader testing would be good, especially VoiceOver's reading of the active cell and the Status count.
  • Escape closes the whole picker on the first press, even with a query typed.
  • Group headings use the Design System label style (per @mirka) rather than Heading/md from the design spec.

Testing Instructions

Test in WordPress Playground

  1. Enable Notes, add a note to a block, and click the "Add reaction" button on it. The popover should open at its final size and position, without a jump (easiest to see with scrollbars set to "Always" in macOS settings).
  2. Without leaving the search field, press ArrowDown, then move around with the arrow keys; the highlight should cross from "Frequently used" into "Smileys & Emotion" and beyond.
  3. Press Enter; the highlighted emoji is added as a reaction.
  4. Reopen the picker and type "heart"; the top result is highlighted. Press Enter to add it.
  5. Type a query with no matches, eg. "zzzq". "No emoji found." shows and the popover keeps its width.
  6. Tab from the search field; focus moves to the skin-tone button.

Tested: the collab sidebar unit tests (204 pass), and the full block-notes.spec.js e2e spec in Chromium, Firefox, and WebKit (81 pass). The empty-state e2e test now also checks the popover width; it fails without the width fix (the popover shrank by ~140px).

Screenshots

Captured with classic (always visible) scrollbars.

Open Arrow key highlight Search No results
Picker open Highlight moved with the arrow keys Search for heart, top result highlighted No emoji found, popover keeps its width

Screencast

Opening the picker, arrow keys across categories, searching, the empty state, and picking with Enter (keys shown bottom left):

pr83538-autocomplete-screencast-v3.mp4

AI Use

Code and description came out of a few rounds of back and forth with 🤖 Claude Code. I will review and test.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Jx9yDR5xxMRczChFCjzBNu

adamsilverstein and others added 30 commits June 30, 2026 13:07
Both bits only existed to support the full emoji picker, which is now a
follow-up PR. Without the `+` trigger, no caller ever passes a hex
codepoint key into the reaction storage, so the encode/decode pair and
the HEX_KEY_RE fallback in getEmojiBySlug/getLabelBySlug never fire.
The `.editor-collab-sidebar-panel__more-reaction-button` rule styled
that trigger and has no remaining consumer.
Four near-identical tests (no parent, parent is a regular comment,
content not in the emoji list, anonymous user) all built the same POST
request and asserted a specific WP_Error. Replace them with a single
parameterized test_cannot_create_reaction_with_invalid_input plus a
named-key data provider, so the matrix of error cases is readable at a
glance and each new case is one row instead of a new method.

Net -23 lines; the duplicate-reaction and "can stack different reactions"
tests stay separate because their request shape differs.
Five emojis fit in a single ~176px-wide row that drops below the smiley
trigger without clipping. This matches the dominant pattern for emoji
reactions (Facebook/Slack/GitHub/Linear/Notion) so the affordance reads
as reactions instead of a generic dropdown menu.

Composite gets orientation="horizontal" so ArrowLeft/ArrowRight drive
the keyboard nav. The e2e test that exercises arrow keys is updated to
match.
Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com>
Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com>
Apply review feedback: drop the bespoke 28px-with-!important sizing on
the curated add-reaction button in favor of the standard Button "small"
size with iconSize=20. Removes redundant flex/centering CSS the Button
component already handles.
A resolved note thread shouldn't accept new reactions — they're for
in-progress conversations. Disable the curated reaction picker toggle
when the note's status is "approved" and keep it accessible so screen
readers still announce the control's disabled state.
Replace per-render array.find() calls in ReactionDisplay with a Map
keyed by slug, memoized against the emoji list. O(1) lookup keeps
the render cheap if the curated set grows (full picker landing later
via the stacked PR).
Per review feedback, the smiley face shouldn't be promoted to the
public icons API while the reactions feature is still settling. Move
the SVG back inline in reaction-display.js (using SVG/Path from
@wordpress/primitives so it stays cross-platform) and remove the
smiley entry from @wordpress/icons' manifest and library.
Require edit_post capability to create a note or reaction, mirroring
core's note guard, so the check no longer depends on a status field
being present in the request. Also validate that a reaction's parent
note belongs to the same post the reaction targets.

Addresses review feedback on PR #76767.
The prepare_links override repointed a note's _links.children from its
replies (type=note) to reactions (type=reaction), breaking core's
reply-embedding contract for clients relying on _embed. Reactions reach
the client through the reaction_summary field and an on-hover fetch, so
the override served nothing. Remove it and inherit core's behavior.

Addresses review feedback on PR #76767.
The reaction picker fetched the curated emoji list via OPTIONS
/wp/v2/comments, reading it from a reaction_emojis schema default.
OPTIONS is for discovering allowed operations, not data retrieval, and
the curated set is a fixed five-emoji row. Use the hardcoded
REACTION_EMOJIS list directly, drop the useReactionEmojis hook and the
client request, and remove the read-only reaction_emojis schema
property. The gutenberg_note_reaction_emojis filter still drives
server-side validation.

Addresses review feedback on PR #76767.
…plugin class

The reaction controller extended Gutenberg_REST_Comment_Controller_6_9,
but that plugin class was deleted when the minimum WordPress version was
bumped to 6.9 (notes graduated to core). Loading the plugin therefore
fataled with 'Class not found', which cascaded into every PHP, Playwright
and performance CI job.

Extend the core WP_REST_Comments_Controller directly, add a local
check_post_type_supports_notes() (core declares it private, so it cannot
be reused from a subclass), and drop the now-dead remove_action() for the
deleted 6.9 registration function.
Replace the .editor-collab-sidebar-panel__reaction-button CSS-class
locators with getByRole( 'button', { name: /<emoji>/ } ), following the
Playwright guidance to prefer user-facing attributes over CSS selectors.
The reaction pill's accessible label always contains the emoji name, so
the regex match is stable across the count and tooltip label variants.
Addresses review feedback from @manzoorwanijk.
The numbered-step comments were removed from the build script because
they get unwieldy when steps are inserted between existing ones. Drop the
lone leftover marker. Addresses review feedback from @manzoorwanijk.
Core's check_read_permission() only excludes the 'note' comment type from
the public read path, where an approved comment on a readable post is
world-readable. Reactions are an internal comment type too, so a direct
GET /wp/v2/comments/{reaction_id} fell through to that public path and
exposed reaction rows - including the reacting user's identity - to any
reader of a published post. The collection endpoint already blocks
non-editors from querying type=note|reaction, but the single-item-by-ID
path did not.

Override check_read_permission() to give reactions the same restriction
core gives notes: never public, readable only by the reacting user or a
user who can edit the comment. This also closes the direct-ID read path
flagged for internal types. Add coverage asserting logged-out and
subscriber reads are denied while the author and an editor are allowed.

Addresses review feedback from @scruffian.
The comment-count query filter bailed entirely whenever the query already
contained the note-only exclusion (comment_type != 'note'), which core and
older revisions of the filter inject. In that case the 'reaction' type was
never excluded, so reactions inflated the post comment count.

Iterate the internal comment types and append an exclusion clause for each
one not already present, instead of skipping when any exclusion exists.
This guarantees reactions are excluded too and keeps the filter idempotent
across multiple runs.

Addresses review feedback from @scruffian.
Store the validated reaction slug as the comment content instead of the
raw request value, so input like '<b>heart</b>' is persisted as 'heart'
and stays consistent for reaction grouping and counts.

Also reject hex-codepoint slugs that are not assignable Unicode code
points (above U+10FFFF or in the UTF-16 surrogate range), which the
shape-only regex previously accepted.

Addresses CodeRabbit review (M2, m6).
The cached tooltip user-name list was only cleared when toggling an
existing reaction pill. Adding the same slug through the picker updated
the count but left a stale tooltip. Thread noteId into AddReactionButton
and clear the cache entry on the picker path too.

Addresses CodeRabbit review (m8).
Wrap the reaction-emoji filter test in try/finally so a failed assertion
cannot leak the gutenberg_note_reaction_emojis filter into later tests.

Replace the flaky cumulative toHaveCount( 2 ) snackbar assertion in the
re-add e2e with per-add checks: assert and dismiss the first success
snackbar, then assert the re-add surfaces its own, instead of requiring
both auto-dismissing snackbars to be present simultaneously.

Addresses CodeRabbit review (m9, m10).
The pre-insert uniqueness check for reactions is not atomic: two
near-simultaneous requests for the same user, note, and emoji can both
pass the check and insert an approved row, since reactions deliberately
bypass core's wp_allow_comment() duplicate detection.

After a successful reaction insert, re-query the user's approved
reactions for the note and, when more than one matches the slug, keep the
earliest (lowest comment ID) and delete the rest. Every concurrent
request applies the same deterministic rule, so they all converge on the
same surviving row; a request whose own row lost the race repoints its
response to the survivor.

Add a test that injects a competing reaction via rest_pre_insert_comment
(after the pre-insert check, before the insert) and asserts a single row
survives and the response references it.

Addresses CodeRabbit review (M3).
…dditional-comment-type' into add-notes-emoji-reactions-full-picker

# Conflicts:
#	lib/compat/wordpress-7.1/block-comments.php
#	lib/compat/wordpress-7.1/class-gutenberg-rest-comment-controller-7-1.php
#	lib/load.php
#	package-lock.json
#	packages/editor/src/components/collab-sidebar/hooks.js
#	packages/editor/src/components/collab-sidebar/note.js
#	packages/editor/src/components/collab-sidebar/reaction-display.js
#	packages/editor/src/components/collab-sidebar/reaction-emoji-picker.js
#	packages/editor/src/components/collab-sidebar/style.scss
#	phpunit/experimental/class-wp-rest-comments-controller-gutenberg-test.php
#	test/e2e/specs/editor/various/block-notes.spec.js
Dismissing the 'Reaction added.' snackbar moves focus and selection
away from the note thread, which collapses the thread and unmounts
the reaction pill. The subsequent click on the pill then timed out
because the button was no longer rendered. Re-select the thread
after dismissing the snackbar so the pill is visible again, matching
how a user would remove a reaction from a collapsed thread.
Cover the client-side reaction components that previously had no unit
coverage: pill rendering (counts, pressed state, label pluralization,
unknown-slug fallback), toggle callback wiring, focus hand-off to the
parent thread when removing the last reaction, GitHub-style tooltip
name formatting with lazy loading and error fallback, the curated
picker's listbox semantics, slug-based selection, and the disabled
state of the add-reaction button.
The comment-count query filter rewrites wp_update_comment_count_now()'s
SQL to exclude internal comment types, but had no test pinning that
behavior. Recount a post holding a regular comment, a note, and a
reaction, and assert only the regular comment is counted.
…dditional-comment-type' into add-notes-emoji-reactions-try-addditional-comment-type
Use _x() with an 'emoji reaction' context so translators know
bare names like Heart or Eyes refer to emoji in the reaction
picker, not other UI concepts.
adamsilverstein and others added 3 commits October 7, 2026 16:34
…er-autocomplete-grid

# Conflicts:
#	packages/editor/CHANGELOG.md
Reviewers on the matching core change prefer not to define what counts
as an "internal" comment type before a custom comment types API exists,
since reactions may later apply to public comments too. Drop the
gutenberg_get_internal_comment_types() helper and its filter, and list
'note' and 'reaction' at each call site, as on #76767.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01THCU4aj11hnJP5ZbUegTRh
Format the count for the user's locale in both the pill and its
accessible label, as on #76767.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01THCU4aj11hnJP5ZbUegTRh
@dmsnell

dmsnell commented Oct 7, 2026

Copy link
Copy Markdown
Member

technically possible to invoke the native picker directly from the web platform. Still, I'll research that further to make sure. I know in the past this wasn't as straightforward as it sounds.

it happens automatically for text input fields. I’m not sure if it’s possible outside of that, or if there’s a reasonable way to auto-invoke it. it was just a crazy “have we tried this?” question.

on everything else, it all makes sense. I would love to avoid shipping all the data, even lazily, because that could also end up introducing a lot of lag when adding the first reaction, but this is I think an inherently unfortunate scenario.

if we perform search on the server, that might reduce latency but increase server load, as it would be served dynamically instead of a large static bundle. however, that might also make it more feasible for people to add their own WPmoji the way Slack does, and the grid could be simplified to a simple OL or TABLE of text cells or BUTTONs

my comments are meant to be helpful outside questions, not demands. you are welcome to ignore me.

adamsilverstein and others added 2 commits October 7, 2026 16:56
The picker now outlines the emoji the user already reacted with, and
names them as such, so picking one again reads as a toggle. On a
resolved thread the add-reaction trigger was shown disabled on some
notes and hidden until hover on others; hide it entirely, as on #76767.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01THCU4aj11hnJP5ZbUegTRh
The typecheck rejected the picker's trigger element, whose props were
typed as unknown, and the grouped-or-flat items union, which matches
neither of Base UI's Autocomplete.Root overloads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01THCU4aj11hnJP5ZbUegTRh
@adamsilverstein

Copy link
Copy Markdown
Member Author

technically possible to invoke the native picker directly from the web platform. Still, I'll research that further to make sure. I know in the past this wasn't as straightforward as it sounds.

it happens automatically for text input fields. I’m not sure if it’s possible outside of that, or if there’s a reasonable way to auto-invoke it. it was just a crazy “have we tried this?” question.

I'm not sure average users knpw about the native pickers or how to invoke them. I only know how to use them on the mac because a key on my keyboard is mapped to the picker 😀 and still I rarely if ever use the native picker. Still, I will investigate if the idea is possible.

on everything else, it all makes sense. I would love to avoid shipping all the data, even lazily, because that could also end up introducing a lot of lag when adding the first reaction, but this is I think an inherently unfortunate scenario.

We can host the data on .org and load it from there if shipping with wp is a concern, I believe a previous review from @t-hamano brought this up, although I can't find the conversation at the moment.

if we perform search on the server, that might reduce latency but increase server load, as it would be served dynamically instead of a large static bundle. however, that might also make it more feasible for people to add their own WPmoji the way Slack does, and the grid could be simplified to a simple OL or TABLE of text cells or BUTTONs

I'm working on extensibility of the emoji set in a follow up:

my comments are meant to be helpful outside questions, not demands. you are welcome to ignore me.

Thanks! I'm going to pay attention to you even if I don't always agree 😄 (colon smile colon)

@adamsilverstein

Copy link
Copy Markdown
Member Author

Merged trunk and brought over the recent review fixes from #76767.

Claude ported these, summary below:

  • The internal comment types helper and its filter are gone, with 'note' and 'reaction' listed at each call site (a251c4b).
  • Reaction counts use the user's locale in both the pill and its label (f6a32e2).
  • The add-reaction trigger is hidden on resolved threads instead of shown disabled, and the picker outlines the emoji you already reacted with, announced as "heart, your reaction" (7e95aeb).
  • Fixed two type errors in emoji-picker.tsx that were failing the typecheck (74c7340).

@westonruter

Copy link
Copy Markdown
Member

I'm not sure average users knpw about the native pickers or how to invoke them. I only know how to use them on the mac because a key on my keyboard is mapped to the picker 😀 and still I rarely if ever use the native picker. Still, I will investigate if the idea is possible.

Do we need to allow any emoji? The linked issue says:

Use a curated subset of common emoji reactions (similar to GitHub/Slack approach):

  • Suggested set: 👍 👎 ❤️ 🎉 😄 😕 👀 🚀

It would be cool (even 🆒 or 😎) if any emoji could be selected. But this seems excessive maybe, and is shying away from decisions not options. A simple picker of the fixed set would greatly simplify this. Maybe it could be extensible so a plugin could add a full emoji picker for sites that want it.

(Maybe this has already been discussed. I haven't kept up with this closely.)

@Mamaduka

Mamaduka commented Oct 7, 2026

Copy link
Copy Markdown
Member

@westonruter, the PR with the curated list of reactions is in progress here: #76767.

@adamsilverstein

Copy link
Copy Markdown
Member Author

and is shying away from decisions not options

I've decided to give you the choice of any emoji!

Just kidding! Looks like there is more consensus on the curated list of emoji PR so we will start with that. I had always planned the full picker as a potential follow up and it was a good exploration of using the autocomplete grid. Hopefully we can revisit this in the future, I'm fairly sure people will want the full set of emoji once they start using them.

…er-autocomplete-grid

# Conflicts:
#	packages/editor/CHANGELOG.md
#	packages/editor/src/components/collab-sidebar/README.md
#	packages/editor/src/components/collab-sidebar/hooks.js
Move the Autocomplete.Trigger changelog entry back under Unreleased,
since the 0.24.0 release stranded it under a published heading.

Claude-Session: https://claude.ai/code/session_01RmMwj4CN9cF8b1Sx58Pvik
The changelog validator requires Unreleased subsections in a fixed
order, and the trunk merge put Enhancements first.

Claude-Session: https://claude.ai/code/session_01RmMwj4CN9cF8b1Sx58Pvik
The picker set no status while searching, so screen reader users heard
nothing as results changed. The async Autocomplete pattern this follows
puts a visually hidden result count in `Status`; do the same for search
results, leaving the empty state to `Autocomplete.Empty`.

Claude-Session: https://claude.ai/code/session_01RmMwj4CN9cF8b1Sx58Pvik
adamsilverstein added a commit that referenced this pull request Oct 12, 2026
…icker-name-footer

Bring in the emoji search result count announcement from #83538.

Claude-Session: https://claude.ai/code/session_01RmMwj4CN9cF8b1Sx58Pvik
adamsilverstein added a commit that referenced this pull request Oct 12, 2026
…eaction-filters

Bring in the emoji search result count announcement from #83538.

Claude-Session: https://claude.ai/code/session_01RmMwj4CN9cF8b1Sx58Pvik
adamsilverstein added a commit that referenced this pull request Oct 12, 2026
The picker test merged in from #83538 mocks `useEmojibaseConfig` with
only `baseUrl`, but this branch adds `labelOverrides` to the config, so
the mock no longer type checks.

Claude-Session: https://claude.ai/code/session_01RmMwj4CN9cF8b1Sx58Pvik
adamsilverstein and others added 5 commits October 20, 2026 11:58
#76767 landed on trunk with Mamaduka's reactions refactor (NoteReactions
and useNoteReactions replace ReactionDisplay, AddReactionButton and
useReaction), so this keeps trunk's structure and moves the picker onto it:

- NoteReactions opens EmojiPicker instead of the curated Menu, and pills
  name non-curated emoji through Emojibase.
- reaction-emojis keeps trunk's label/sentenceLabel entries and regains the
  hex key helpers the picker needs.
- The comment controller accepts any valid emoji hex key again instead of
  the five curated keys, with PHPUnit cases for both.
- Picker styles, e2e tests and changelog entries move onto trunk's
  versions; changelog entries go under Unreleased.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01335F6jiRhAVVxJxKHsLxgW
…er-autocomplete-grid

# Conflicts:
#	packages/editor/src/components/collab-sidebar/reactions/note-reactions.tsx
Trunk now requires use-recommended-components suppressions to sit on a single import specifier, and new tool scripts to be TypeScript, so scope the skin tone picker's Menu suppression and rename the emojibase copy script to .mts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvpAdxaahosj8kTQtm3NXW
Trunk now publishes @wordpress/block-editor type declarations, so the directive is unused and fails the typecheck.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvpAdxaahosj8kTQtm3NXW
Reverts c153d3a. Filtering is synchronous, so a live count announces on every keystroke; mirka asked for it to be removed in review and Autocomplete.Empty already covers no results. The test now guards against the count coming back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvpAdxaahosj8kTQtm3NXW
@jasmussen

Copy link
Copy Markdown
Contributor

I just wanted to reiterate something I suggested in the past, I can dig up my old comment if you like. Two things:

  • I would like us to omit thumbs-down from the suggested set, at least in these early days. The decision to include "dislike" features I find to be a pattern of negativity in web-apps that implicitly encourages such behaviour by being included as a default option. It's a personal opinion, and a strong one, but not a blocking one: when you feel like downvoting, write an explanatory comment instead, it's better discourse. And the thumbs-down can land one day when we open up the full emoji set.
  • If we include faces and bodies, let's prioritise the addition of skintone-pickers in a followup release.

@jeffpaul

Copy link
Copy Markdown
Member

Fully agree with @jasmussen on indexing towards positive sentiment reactions here! 👍🏼 (thumbs up emoji used very purposely here)

@adamsilverstein

Copy link
Copy Markdown
Member Author

I want to bring back a suggestion from the past which maybe deserves more consideration: instead of immediately opening the full emoji search experience, we could start with a limited subset that ends in a (+) (plus/more) button that brings up the full picker. the initial list could be dynamic gaining items you select from the full picker automatically like the current favorites section.

Discussed here: #78176 (comment) and if you expand the thread there is some discussion on the approach.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Notes Phase 3 of the Gutenberg roadmap around block commenting Needs Design Needs design efforts. [Package] Editor /packages/editor [Package] UI /packages/ui [Type] Feature New feature to highlight in changelogs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add emoji reactions as a first class comment type