fix(tooltip): render popover-hosted tooltips above their parent - #78
Merged
Merged
Conversation
A tooltip on a button inside a MoonPopover never appears. Every settings popup is built from glyph buttons whose meaning lives in the tooltip, so those controls read as unlabeled squares. GPUI sorts every deferred draw into one global ascending order by priority and paints in that order, regardless of nesting. The managed tooltip overlay deferred at priority 2 while a MoonPopover defers at 30_000, so the popover always painted over the tooltip. A tooltip is the topmost transient surface in any interface, so it now defers above every other band unconditionally rather than opting in per host. The bands themselves move into one module, src/layer.rs, which is the only place they are numbered: LAYER_OVERLAY (1), LAYER_MOON_POPOVER (30_000), LAYER_MOON_POPOVER_MENU (31_000) and LAYER_TOOLTIP (100_000). Every call site that carried a bare literal now names its band. Only the tooltip's value changes behaviour; the one other renumber, the popover-hosted select menu from 30_001 to 31_000, widens the gap without changing any ordering, and the existing test there asserts the relation rather than the number. src/time/date_picker.rs keeps its bare literal 2: that file is a Mirror component with a zero donor-drift budget, so any byte change there fails the donor-mirror guardrail. The gallery's popover gains a tooltip-bearing button so the behaviour has somewhere to be seen. Two tests pin the result: a band-relation test over the constants, and a headless scene-quad probe asserting the tooltip paints above its hosting popover in both themes.
kirillDevPro
added a commit
to Moonbot-Tech/MoonTerminal
that referenced
this pull request
Sep 20, 2026
MoonUI 1767a249 raises the managed tooltip overlay above the popover and dropdown band, so a tooltip on a button inside a MoonPopover is visible again (Moonbot-Tech/MoonUI#78, this repo's #628). Hand-edited: the 23 MoonUI revision lines only, proven by `cargo fetch --locked` returning 0. `cargo update -p` was not used — it re-resolves unrelated dependency edges.
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.
What & why
A tooltip on a button inside a
MoonPopovernever appears, so every settings popup built fromglyph buttons shows unlabeled squares. Fixes Moonbot-Tech/MoonTerminal#628.
GPUI sorts all deferred draws into one global ascending order by
priorityand paints inthat order, regardless of nesting (
moon-gpui/src/window.rs,deferred_draw_traversal_order).The managed tooltip overlay deferred at
2; aMoonPopoverdefers at30_000; the popover won.This takes the principled fix rather than a "tooltip inside a popover" special case: a tooltip is
the topmost transient surface, so it now outranks every other deferred band unconditionally.
The bands move into one module that is the only place they are numbered:
LAYER_OVERLAYLAYER_MOON_POPOVERLAYER_MOON_POPOVER_MENULAYER_TOOLTIPOnly the tooltip's value changes behaviour. Every other call site keeps the number it already
had; the single other renumber (the popover-hosted select menu, 30_001 -> 31_000) only widens the
gap, and the existing test there asserts the ordering relation rather than the literal. This also
removes the crate's only piece of arithmetic on a priority (
MOON_POPOVER_PRIORITY + 1).src/time/date_picker.rs:512deliberately keeps its bare literal2— that file is aMirrorcomponent with a zero donor-drift budget, so any byte change fails
cargo xtask component-mirror.docs/component-mirror-baseline.jsonis regenerated because four donor-tracked files changedbytes. The diff moves only
local_hash/hash/bytes; everydonor_changed_fileslist isbyte-identical, i.e. no new drift was introduced or absorbed. Same pattern as #64.
Note for downstream consumers
The tooltip moved from the bottom of the global deferred stack to the top.
Popover::deferred_priorityand
Select::menu_priorityare publicusizesetters, and the sort is global — so a custom overlaybuilt with a hand-picked priority in
3..99_999used to paint above tooltips and now paints belowthem. That is the intended effect, but it is a behaviour change for anyone who relied on the old
order.
How to verify
powershell -ExecutionPolicy Bypass -File tools\run-component-guardrails.ps1— fmt, gallerycheck, component and gallery tests, component audit, API and donor-mirror checks.
now renders above the popover. On
masterit is invisible.geometry probe asserting the tooltip's deferred draw paints after its hosting popover's.
Follow-ups this change surfaced but deliberately does not fix
All four are pre-existing and out of scope for a paint-order fix; they are one theme, not four
tickets. The band is absolute, not relative to the host, so any child overlay that defers low is
invisible inside any higher-band parent.
MoonSelectsolved this ad hoc with an opt-inin_popover(); this change solves it structurally for tooltips. The rest are unsolved:MoonDatePicker's calendar (time/date_picker.rs:512) defers at2, so a date pickerinside a
MoonPopoverhas an invisible calendar — issue #628's exact symptom. Blocked here bythe Mirror drift budget; needs a donor-side change or a component-class decision.
MoonDropdownsubmenus (moon/dropdown/popup.rs:891) defer at the base band whilemoon/dropdown/trigger.rs:654puts every dropdown's own surface at30_000, so a submenupaints under its own parent menu. No test pins submenu draw order anywhere.
MoonComboboxhas no equivalent ofin_popover()at all, so nesting one in a popoverwould hide its list with no API to reach for. Latent — no such composition exists today.
on_hover(false)and
on_mouse_downon the trigger itself; no popover-dismiss, Escape or focus-loss path clearsit. Dismissing a popover by Escape while hovering leaves a tooltip with no trigger. This is
pre-existing, but it was invisible while the tooltip painted at
2and is visible now. Itself-clears on the next hover or click on any tooltip-bearing control.