Repository navigation
popover: Tell the trigger it is open instead of selected - #3125
Merged
Merged
Conversation
A popover mapped its open state onto `Selectable::selected`, so a trigger whose selection already meant something else — a sidebar row that is selected when it is the current view — had to be wrapped in an adapter that re-mapped selection back into open state. `Selectable` now carries `open`/`is_open` alongside `selected`, defaulting to the selected pair, so existing triggers are unchanged. Popover, the dropdown menu and the app menu bar mark their trigger with `open`, and Button keeps the two apart in its own state while still painting them the same. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Problem
A popover told its trigger it was open by borrowing the selected state:
"Open" (a popup is showing, the trigger stays lit) and "selected" (this is the
current view, the chosen item) are two different states. Downstream
(ai-desktop/pilot) a sidebar row implements
Selectable::selectedto mean "thisis the current view"; used as the account popover's trigger it had to be wrapped
in a
SidebarRowTriggeradapter that re-mappedselectedback into open state,because the popover would otherwise light the row as if it were the current view.
Change
Selectablegains two default methods, so nothing breaks:Naming follows the boolean setter/reader rule in CLAUDE.md: the setter takes the
field name, the reader is
is_.The
crates/basechange is limited to this —Selectablelives incrates/base/src/component_traits.rs, so the seam has to be widened there; nobase component's appearance changes.
Everything that mapped "popup is open" onto the trigger now calls
open:gpui_base::Popover::triggergpui_component::popover::Popover::triggerAppMenuin the app menu bar (its privateis_selectedhelper is renamedis_open, which is what it always meant — the menu bar's open menu)DropdownMenu/DropdownMenuPopoverreach the trigger throughPopover::trigger, so they follow along;DropdownButton'sselectedis acaller-set selection, not open state, and is left alone.
Select,Comboboxand the sidebar submenu keep their own open flags and never went through
Selectable.Buttonimplementsopenexplicitly and stores it in its ownopenfield.Open and selected look identical today, so both render through one
shows_selected_style()check — no visual change — butis_open()now readsback what was set, and a future design can separate the two without another API
change.
Tests
crates/base/src/component_traits.rs: a trigger implementing onlyselectedstill receives open state through the default
open/is_open.crates/base/src/popover.rs: a recording trigger that keepsopenandselectedapart asserts an opening popover callsopen(true)and nevertouches
selected. Confirmed failing before the change(
got [("selected", true), ...]).crates/component/src/button/button.rs:openandselectedare storedapart and both paint the selected style.
Docs
Selectable's trait doc explains whatopenmeans and when to override it.website/component/popover.mdandwebsite/zh-CN/component/popover.mdgain a"Custom Trigger" / 「自定义触发器」 section showing a trigger that implements
Selectableand overridesopen/is_opento keep the two states apart.Breaking Changes
None.
open/is_openare default methods that fall back toselected/is_selected, so existingSelectableimplementations and trigger call sitescompile and behave exactly as before.
🤖 Generated with Claude Code