Expand description
Popover / menu primitives: an anchored floating layer with the menu-in
animation, outside-click dismissal, and pure keyboard-navigation + search
reducers shared by every picker and menu (feature-inventory §1.12 popovers).
gpui pattern (examples/popover.rs at the pinned rev): the trigger element
conditionally children a deferred(anchored().child(content)) — deferred
paints on a floating layer above everything, anchored positions it relative
to the trigger (or an explicit point for context menus).
Pure logic (wrap-around list navigation, ranked substring filtering, key classification) lives in free functions with unit tests; the elements only feed them measurements/events.
Structs§
- Filter
- The state behind a searchable list: the items, the ranked view of them, and which row of that view is active. Shared by every picker — the palette, the combobox — so the mapping below is written and tested once.
- Popup
- Popup state with an exit phase. gpui unmounts an element the frame its
state drops, so a closing animation needs the state held alive while
motion::menu_outplays:open→begin_close(render keeps mounting, with the out animation and dead hit-testing) →reap_popup’s timerfinish_closees ~motion::MENU_OUTlater. UseSelf::is_openfor logic (a closing popup already reads as closed) andSelf::get/Self::is_closingfor rendering.
Enums§
- Loadable
- One async-loaded slot:
Idle(never requested) →Loading(skeletons) →Ready/Error(inline message + Retry). - MenuKey
- Keys the pickers care about, classified from a raw keystroke.
- Side
- Which edge a
sheetslides in from.
Functions§
- anchored_
menu - Wrap popover content in a floating anchored layer attached to the trigger:
the caller
.child(anchored_menu(...))s this from the trigger element while open. Playsmenu-in(0.14s fade + 2px drop);closing(thePopupexit phase) swaps inmenu-out. Dismissal is the caller’s.on_mouse_down_outon the content. The layer.occlude()s: hitboxes are paint-order only in gpui, so without it clicks on menu rows would ALSO fire whatever clickable sits under the floating layer. - anchored_
menu_ above anchored_menuopening UPWARD from the trigger (composer pickers, the user menu — anything anchored near the window bottom; Radix flips these automatically, gpui’sanchoredneeds the side picked).- anchored_
menu_ above_ at - Open an upward menu at a point inside a relative trigger. Useful for text completions, whose natural anchor is the token/caret rather than the input element’s outer edge.
- anchored_
menu_ above_ end anchored_menu_aboveright-aligned to the trigger’s right edge (t3code ComboboxPopupalign="end"— right-side triggers like the composer’s ref picker open leftward instead of running off the window).- anchored_
menu_ below anchored_menuopening DOWNWARD from the trigger’s bottom edge — a dropdown proper (the sidebar’s space filter). The default variant pins to the trigger’s top-left, which reads fine for context-style menus but covers a button-shaped trigger.- anchored_
menu_ below_ gap anchored_menu_belowwith a caller-chosen trigger→card gap — the changes-header dropdowns hang off a tight titlebar band and need more breathing room than the default 6px (user report; t3code sits near 10).- anchored_
submenu - The panel a
crate::menu::Item::Submenurow drops: pinned to the row’s top-right and pulled back by the card’s own inset, so the child’s first row lines up with the row that opened it and the two cards touch. No gap on purpose — a strip of nothing between them is a strip the pointer crosses on its way in, and it would land on a sibling row and close what it was reaching for. Near the right edge the layer snaps rather than flipping; gpui’sanchoredpicks no sides. - band
- The recessed band tone for a palette/picker header or footer strip — a
translucent black so the glass still reads through (the add-space palette
converged on this; measured subtler tones vanish against the dim scrim).
Free function (like
ink/hairline/[wash]), mirroringTheme::band, for the several callers with noTheme/cxin scope (some outside this crate’suimodule tree — threading a&Themeparam would ripple past this task’s file scope). - classify_
key - close_
popup - Begin a popup’s exit phase and schedule its reap —
Popup::begin_closeandreap_popup, which are only ever correct together. A popup already closing or closed is left alone. - dialog_
body - Dialog body copy:
leading-relaxed text-muted-foreground. - dialog_
card - The centered dialog card (
dialog-pop):w-[360px] rounded-2xl border border-white/[0.1] bg-popover/95 p-5 shadow-2xl— popover tone ≈ #101010. - dialog_
field - Dialog text-field frame:
rounded-lg border border-white/[0.08] bg-white/[0.04] px-3 py-2. - dialog_
title - Dialog title.
- dismiss_
on_ out - Dismiss
popupon a press outsideel— the card side of the pairmenu_triggercompletes. - divider
- Hairline divider between menu sections (the reference
MenuSeparator:mx-1 my-1 h-px bg-white/[0.07]). - error_
row - Inline error row + Retry affordance (the caller attaches the listener to the returned id).
- filter_
indices - Filter + rank labels for a search query: prefix matches first, then
substring matches, stable within each rank. Returns indices into
labels. - kbd_
hint - A muted kbd hint chip inside menu rows (
⌘↵-style accelerators). - key_cap
- One footer key-cap (22px, rounded-5,
white/[0.05]) holding arbitrary children — the base ofkey_hint/key_hint_pairand the search-bar chips (“⌘K”, “esc”). - key_
hint - A footer legend: one icon key-cap + tiny verb (the add-space palette’s footer voice, shared by the pickers).
- key_
hint_ pair - A footer legend whose cap holds TWO glyphs split by a hairline (“[ ↑ | ↓ ] Navigate”) sharing one verb.
- key_
hint_ text - A footer legend whose cap holds a WORD (“tab”, “esc”) instead of a glyph — for keys with no icon in the set.
- match_
rank - Match rank of a label against a query:
0prefix match,1substring,Noneno match. Case-insensitive; an empty query matches everything at rank 1 (input order preserved). - menu_at
- A floating menu at an explicit window position (context menus). Occludes
like
anchored_menuso row clicks never reach elements underneath. - menu_
heading - Small uppercase section heading inside a floating menu (the reference
MenuHeading):px-2 pb-1 pt-1.5 uppercase tracking-[0.1em] text-muted-foreground/60. gpui has no letter-spacing at the pinned rev; the tracking is approximated with hair spaces. - menu_
row - One menu row (the reference
menuItem):gap-2.5 rounded-lg px-2 py-1.5, active =bg-white/10 text-foreground. The caller adds the id/click listener. - menu_
section - A bordered trailing menu section (the reference picker action groups /
branch-picker worktree block:
mt-1 flex flex-col gap-0.5 border-t border-white/[0.06] pt-1— the hairline runs edge-to-edge of the card’s p-1 inset, unlikedivider’s mx-1). - menu_
step - Step the active row of a menu: wraps at both ends;
Noneenters at the edge matching the direction. Empty menus stayNone. - menu_
trigger - Wire a trigger to the popup it toggles: press note on the way down, open or close on the way up.
- menu_
trigger_ matching menu_triggerfor one popup shared by several triggers (aPopup<Menu>with a row’s index inside it):ownssays whether the open popup is this trigger’s, so pressing another trigger switches menus instead of swallowing the press. SeePopup::note_trigger_press_matching.- modal
- Full-window modal: dim scrim + centered card with the
dialog-inentrance. The scrim swallows clicks; the caller wires its own dismiss/confirm.viewportis the window size (ananchoredlayer sizes to its children, so the scrim needs explicit dimensions). The frost radius matchesdialog_card’s 16px rounding.on_dismissis the scrim press. It is a parameter rather than the caller’s.on_mouse_down_out, for the same reasonsheet’s is: the scrim lives inside this deferred layer, so nothing outside can reach it. Without it a dialog could not be dismissed by clicking away from it by any caller — which is how this one shipped, and what it looked like was a dialog that only closed on its own buttons. - modal_
glass modalfor glass-tinted cards (the add-space palette): a LIGHTER scrim, so the material card reads like the popovers — the standard 0.6 dim buried the backdrop hue under the blur and the palette came out a flat grey slab next to the hue-inheriting menus (user report).- popover_
card - popover_
card_ flush popover_cardwithout thep-1inset — for popovers that manage their own internal panes (the harness/model picker’s rail + list split).- reap_
popup - Schedule the reap for a
Popup::begin_close: after the exit animation’s span, drop the popup state and repaint.popupre-borrows the field from the view (the state can’t be captured — the view owns it). - redacted_
rows - Pulsing skeleton rows shown while a list loads (the reference:
h-7 animate-pulse rounded-md bg-white/[0.04]). - search_
line - The query line at the top of a picker popover: a magnifier, the field, and a hairline under it.
- sheet
- A panel over a dim scrim —
modalpinned to an edge. It slides in overmotion::DIALOG_INand, once the caller’sPopupenters its exit phase, back out overmotion::MENU_OUT— which it must, becausePopup::finish_closereaps on that spec’s span. - sheet_
panel - The panel body of a
sheet: glass card chrome rounded and hairlined on its inner edge only — the corners against the window edge are off-screen — so it reads as pulled out of the window rather than floating near it. - tracked_
upper - Uppercase + hair-space tracking (see
menu_heading). - trigger_
press - The press half of
menu_triggeron its own, for a trigger whose open is more thanPopup::open— a combobox that clears its query and focuses it, a gutter handle whose menu belongs to the release of a possible drag. The click side is then the caller’s, and reads the note withPopup::take_press_was_open. - trigger_
press_ matching trigger_pressfor one popup shared by several triggers — seemenu_trigger_matching.