Anchor the reaction picker above the message bubble#153
Merged
Conversation
The reaction picker rendered detached from its message — centered, off in a corner, or overlapping the bubble — in the default NSTableView timeline renderer. The bubble frame was captured in the SwiftUI "timeline" coordinate space, which can't resolve inside the table's per-row NSHostingView cells, so the frame was meaningless across that boundary. Capture the bubble frame in global (window) coordinates, which is consistent across both the table and LazyVStack renderers and survives the NSHostingView boundary. ReactionPickerOverlay converts it to its own local space by subtracting its global origin, then pins the capsule's bottom edge a small gap above the bubble's top via deterministic padding (no capsule-size measurement to lag a frame). The capsule's trailing edge aligns to the bubble's trailing edge. MessageView is the single source of the bubble frame: it streams updates so the picker tracks the bubble across layout changes (e.g. window resize) and reports the same frame up to the row for the context-menu present — avoiding a second, whole-row stream that previously fought it and slid the picker onto the avatar gutter during width changes. Fixes subpop#147. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
For short incoming messages, the reaction picker capsule was anchored to the bubble's trailing edge, causing it to extend leftward behind the room list sidebar. Now incoming messages anchor the capsule to the bubble's leading edge so it extends rightward into the visible timeline area. Outgoing messages retain trailing-edge alignment. Assisted-By: OpenCode (claude-opus-4-6)
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.
Fixes #147 — the reaction picker rendered fixed near the center, off in a corner, or overlapping/under the compose bar instead of attached to its message.
Cause
The default timeline renderer is NSTableView-backed, with each row in its own
NSHostingView. The picker was positioned from a bubble frame captured in the SwiftUI"timeline"coordinate space, but a named coordinate space can't resolve across that per-cell hosting boundary — so the frame was meaningless and the picker landed wherever.Fix
NSHostingViewboundary.ReactionPickerOverlayconverts it into its own local space by subtracting its global origin.MessageViewstreams its precise bubble frame so the picker tracks the message across layout changes (e.g. window resize), and reports the same frame up to the row for the context-menu present. This removes a second, whole-row geometry stream that previously fought it and slid the picker onto the avatar gutter when the window narrowed.Testing