Home: the emoji button opens the picker for the message box; the + picker opens without a delay
Merged
TE
17d ago+235+235+012345678901234567890123456789-17-17-01234567890123456789
Problem
In the cmux-next Home chat (the Chief's iMessage-style view):
- Emoji button. Clicks often did nothing, or the chosen emoji never reached the message box. It only worked when the box already had the keyboard. The button focused the box and called
orderFrontCharacterPalettein the same click. AppKit moves the key window's text input context to a new first responder only after that event, so the picker opened for the previous responder (the transcript or the pane). - "+" (add attachment) button. The sheet came up slowly. Each click built a new
NSOpenPaneland opened it from aTask, one run-loop turn later. On macOS 27.0.1, in a bare app,NSOpenPanel()takes about 130 ms of main-thread time (about 400 ms for the first one in a process), andbeginSheetModaladds about 270 ms. That is 0.7 s or more before the sheet appears.
Change
ChatController+Emoji.swift: the button makes the box first responder (and makes its window key), then asks for the picker one turn later, once the box's input context is current. A box that already has the keyboard opens the picker at once. The picker call goes throughopenEmojiPaletteso tests can count it.HomeAttachmentPanel.swift: one open panel is made while Home is idle (aDemandTimerdeadline, after a second with no input, at most 10 checks) and reused. The click opens it as a sheet in its own turn. A second click while the sheet is open does nothing.
Verification
- Commit 1 adds
EmojiButtonTestswithout the fix. On the fleet it fails as intended:Expectation failed: (opened.count โ 1) == 0, meaning the picker was opened in the click's own turn. - With the fix, on the fleet (Xcode 26.6,
package-test-lane.sh suite, run on the pre-rebase SHAs; the rebase onto the current base was clean):EmojiButtonTestsandDropFocusTestspass inPackages/Shared/CmuxMessagesLab.HomeComposerInlineImageTestspass inPackages/macOS/CmuxNext, so the "+" change compiles.
scripts/cmux-next/check-concurrency.shreports nothing in the changed files.- Review round (commit 4,
43e669f):- The emoji button keeps the draft's caret (the tapback menu's emoji item shares the path).
- It still asks for the picker when the field cannot take the keyboard.
- It waits for
didBecomeKeywhile the app is still activating. - The attach panel has no process-wide
showingflag, so a torn-down sheet can't disable "+" and a second window gets its own panel. - The warm-up counts input only while cmux is in front.
- Fleet on
43e669f:EmojiButtonTests(3 tests, including the new caret test),DropFocusTestsandHomeComposerInlineImageTestspass.
- Not done: dogfood in a tagged build. The panel timings come from a standalone bench, not from inside the app.
No user-facing strings changed, so no localization audit was needed.
๐ค Generated with Claude Code