Repository navigation
React with the web's quick reactions in a bubble, and the phone's own emoji picker for the rest - #118
Merged
Merged
Conversation
simonhamp
force-pushed
the
feat/emoji-picker
branch
from
October 28, 2026 18:35
603edba to
acf77e6
Compare
The reactions sheet keeps the web's three quick reactions and swaps its fixed grid of sixteen for a More reactions button, as the web has. It opens <native:emoji-picker> from NativePHP/mobile-ui: the emoji keyboard on iOS, Jetpack's EmojiPickerView in a sheet on Android. The sheet makes way for it. A picked emoji goes through toggleReaction like a quick one. devnull only takes the emoji in the web's shortcode set, fully qualified and without skin tones, so ReactionEmoji maps what the picker hands over onto that list (a copy of the web's emoji-shortcodes.json): a skin tone comes off and the variation selector follows devnull's. One devnull doesn't know at all, such as 🐦🔥, isn't sent: a toast says so and the picker stays up for another. openEmojiPicker() is public so the coming long-press menu can open the picker for any message. From the pinned sheet, picking or closing goes back to the pinned messages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Simon didn't want a sheet for a handful of reactions. React now opens a bubble pointing at it, above unless there's no room, with the web's quick reactions and More for the emoji picker. It's <native:popover> from NativePHP/mobile-ui. The message's options stay up while it shows, and reacting puts both away. React in the pinned sheet opens the same bubble over the sheet. The shared bottom sheet now only holds the pinned messages, so $sheet, ReactionsSheet, PinnedSheet and $sheetMessageId are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simonhamp
force-pushed
the
feat/emoji-picker
branch
from
October 28, 2026 18:58
acf77e6 to
3dfde9b
Compare
simonhamp
marked this pull request as ready for review
October 28, 2026 19:28
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
React no longer opens a sheet. It opens a bubble pointing at the React button, above it unless there's no room there, with the web's quick reactions and a More button. More opens the phone's own emoji picker: the emoji keyboard on iOS, with its search, recents and skin tones, and Jetpack's emoji picker in a sheet on Android. A picked emoji, from the bubble or the picker, toggles through
toggleReaction(), and the bubble and the message's options go away.It needs two mobile-ui PRs: NativePHP/mobile-ui#184 (
<native:popover>, the bubble) and NativePHP/mobile-ui#180 (<native:emoji-picker>), documented in NativePHP/nativephp.com#586. I tested through an absolute path repo that isn't committed, socomposer.jsonand the lock still point at mobile-uidev-main, and this can't merge until those do. Until then the tests check fails with "Unknown native element type", because CI installs mobile-ui without them. The suite passes locally with the path repo (1,456 tests). It's rebased onto main now that #102 is merged.The bubble
partials/quick-reactionsand laid over the React button, in the thread's actions row and in the pinned sheet's row. Only the message whose React was pressed renders one.$sheet,ReactionsSheet,PinnedSheetand$sheetMessageIdare gone.Emoji devnull won't take
devnull only takes the 1,870 emoji in the web's
resources/js/lib/emoji-shortcodes.json, in their fully-qualified form, with no skin tones, and nothing newer than Unicode 15.0 (CreateApiMessageReactionRequestchecksRule::in(EmojiShortcodes::emoji())). The phone's picker hands over more than that.App\Devnull\ReactionEmojimaps it onto devnull's list using a copy of that JSON:No two emoji in the list collide once tones and U+FE0F are stripped, so the mapping is unambiguous. The copied JSON needs refreshing whenever the web's changes.
A small API change would let people keep their skin tones: accept a listed emoji followed by tone modifiers (the same stripping, server side) in both reaction requests, and store it as sent. Updating the shortcode list to Unicode 16 would cover the newer emoji. Both are calls for the web side, so I haven't made them. The app works as it is without either.
For the long-press menu
openReactions(int $id)opens the bubble on any message's React, andopenEmojiPicker(int $id)opens the picker straight away. Both are public.Testing
Native::test()covers the bubble (where it sits, what's in it, a tap outside, reacting from it), the bubble over the pinned sheet, opening the picker from More, reacting with the emoji picked, taking back one picked again, the mapping cases above, refusing and keeping the picker up, closing without a pick, and going back to the pinned sheet. On an iOS 26.2 simulator and an Android 15 emulator against a local devnull onproductionI also checked by hand: the bubble opening above, flipping below for a message right under the top bar, a tap outside, reacting from it, the bubble over the pinned sheet, More, the skin-tone mapping, refusing 🐦🔥, and Done or a tap outside closing the picker.Screenshots
reactions (what React opens)
picker (More; new, so no before)
Recordings of React, the bubble, More and a pick: iOS (finds 🎉 with the keyboard's search), Android.
The before shots were taken on #102's branch before its last commits, which changed how a message is dragged open. The picker shots are from before the bubble, when More was in the sheet; the picker itself hasn't changed.
🤖 Generated with Claude Code