Skip to content

fix(tooltip): render popover-hosted tooltips above their parent - #78

Merged
kirillDevPro merged 1 commit into
masterfrom
kirillDevPro/wt-628-tooltip
Sep 20, 2026
Merged

kirillDevPro merged 1 commit into
masterfrom
kirillDevPro/wt-628-tooltip

Conversation

@kirillDevPro

Copy link
Copy Markdown
Collaborator

What & why

A tooltip on a button inside a MoonPopover never appears, so every settings popup built from
glyph buttons shows unlabeled squares. Fixes Moonbot-Tech/MoonTerminal#628.

GPUI sorts all deferred draws into one global ascending order by priority and paints in
that order, regardless of nesting (moon-gpui/src/window.rs, deferred_draw_traversal_order).
The managed tooltip overlay deferred at 2; a MoonPopover defers at 30_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:

constant value surfaces
LAYER_OVERLAY 1 plain popovers, select menus, comboboxes, context menus, native-menu fallback, dropdown submenus
LAYER_MOON_POPOVER 30_000 Moon popover and dropdown surfaces
LAYER_MOON_POPOVER_MENU 31_000 a menu opened from inside a Moon popover
LAYER_TOOLTIP 100_000 the managed tooltip overlay

Only 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:512 deliberately keeps its bare literal 2 — that file is a Mirror
component with a zero donor-drift budget, so any byte change fails cargo xtask component-mirror.

docs/component-mirror-baseline.json is regenerated because four donor-tracked files changed
bytes. The diff moves only local_hash / hash / bytes; every donor_changed_files list is
byte-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_priority
and Select::menu_priority are public usize setters, and the sort is global — so a custom overlay
built with a hand-picked priority in 3..99_999 used to paint above tooltips and now paints below
them. That is the intended effect, but it is a behaviour change for anyone who relied on the old
order.

How to verify

  1. powershell -ExecutionPolicy Bypass -File tools\run-component-guardrails.ps1 — fmt, gallery
    check, component and gallery tests, component audit, API and donor-mirror checks.
  2. In the gallery, open the Overlays page, open the popover, and hover Action — the tooltip
    now renders above the popover. On master it is invisible.
  3. The added tests pin the ordering: a band-relation test on the constants, and a headless
    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.
MoonSelect solved this ad hoc with an opt-in
in_popover(); this change solves it structurally for tooltips. The rest are unsolved:

  • MoonDatePicker's calendar (time/date_picker.rs:512) defers at 2, so a date picker
    inside a MoonPopover has an invisible calendar — issue #628's exact symptom. Blocked here by
    the Mirror drift budget; needs a donor-side change or a component-class decision.
  • MoonDropdown submenus (moon/dropdown/popup.rs:891) defer at the base band while
    moon/dropdown/trigger.rs:654 puts every dropdown's own surface at 30_000, so a submenu
    paints under its own parent menu. No test pins submenu draw order anywhere.
  • MoonCombobox has no equivalent of in_popover() at all, so nesting one in a popover
    would hide its list with no API to reach for. Latent — no such composition exists today.
  • The managed tooltip has no lifetime tie to its trigger. It is hidden only by on_hover(false)
    and on_mouse_down on the trigger itself; no popover-dismiss, Escape or focus-loss path clears
    it. 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 2 and is visible now. It
    self-clears on the next hover or click on any tooltip-bearing control.

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
kirillDevPro merged commit 1767a24 into master Sep 20, 2026
4 checks passed
@kirillDevPro
kirillDevPro deleted the kirillDevPro/wt-628-tooltip branch September 20, 2026 15:32
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tooltips inside popups are invisible: MoonUI paints the tooltip overlay (priority 2) under MoonPopover (priority 30 000)

1 participant