popover: Revert defer_to focus on Popover open. (#1571)

Revert #1559 added defer to focus.

Removed the behavior of focus back to was focused handle on close
Popover, this is not correct for Popover.
This commit is contained in:
Jason Lee 2025-11-12 17:29:22 +08:00 committed by GitHub
parent f26f01909e
commit a2c16bfae6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 76 additions and 18 deletions

View file

@ -9,6 +9,7 @@ use gpui_component::{
divider::Divider,
h_flex,
input::{Input, InputState},
list::{List, ListDelegate, ListItem, ListState},
popover::Popover,
v_flex,
};
@ -63,6 +64,48 @@ impl Focusable for Form {
}
}
struct DropdownListDelegate {
parent: Entity<PopoverStory>,
}
impl ListDelegate for DropdownListDelegate {
type Item = ListItem;
fn items_count(&self, _: usize, _: &App) -> usize {
10
}
fn render_item(
&self,
ix: gpui_component::IndexPath,
_: &mut Window,
_: &mut App,
) -> Option<Self::Item> {
Some(ListItem::new(ix).child(format!("Item {}", ix.row)))
}
fn set_selected_index(
&mut self,
_: Option<gpui_component::IndexPath>,
_: &mut Window,
_: &mut Context<gpui_component::list::ListState<Self>>,
) {
}
fn confirm(&mut self, _: bool, _: &mut Window, cx: &mut Context<ListState<Self>>) {
self.parent.update(cx, |this, cx| {
this.list_popover_open = false;
cx.notify();
})
}
fn cancel(&mut self, _: &mut Window, cx: &mut Context<ListState<Self>>) {
self.parent.update(cx, |this, cx| {
this.list_popover_open = false;
cx.notify();
})
}
}
impl EventEmitter<DismissEvent> for Form {}
impl Render for Form {
@ -81,7 +124,7 @@ impl Render for Form {
.primary()
.on_click(cx.listener(move |_, _, _, cx| {
parent.update(cx, |this, cx| {
this.form_open = false;
this.form_popover_open = false;
cx.notify();
})
})),
@ -92,7 +135,9 @@ impl Render for Form {
pub struct PopoverStory {
focus_handle: FocusHandle,
form: Entity<Form>,
form_open: bool,
list: Entity<ListState<DropdownListDelegate>>,
form_popover_open: bool,
list_popover_open: bool,
checked: bool,
message: String,
}
@ -118,13 +163,18 @@ impl PopoverStory {
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let form = Form::new(cx.entity(), window, cx);
let parent = cx.entity();
let list = cx
.new(|cx| ListState::new(DropdownListDelegate { parent }, window, cx).searchable(true));
cx.focus_self(window);
Self {
form,
list,
checked: true,
form_open: false,
form_popover_open: false,
list_popover_open: false,
focus_handle: cx.focus_handle(),
message: "".to_string(),
}
@ -201,20 +251,37 @@ impl Render for PopoverStory {
)
.child(
section("Popover with Form").child(
Popover::new("info-bottom-left")
Popover::new("popover-form")
.p_0()
.text_sm()
.trigger(Button::new("pop").outline().label("Popup Form"))
.track_focus(&form.focus_handle(cx))
.open(self.form_open)
.open(self.form_popover_open)
.on_open_change(cx.listener(move |this, open, _, cx| {
println!("Popover form open changed: {}", open);
this.form_open = *open;
this.form_popover_open = *open;
cx.notify();
}))
.child(form.clone()),
),
)
.child(
section("Popover with List").child(
Popover::new("popover-list")
.p_0()
.text_sm()
.open(self.list_popover_open)
.on_open_change(cx.listener(move |this, open, _, cx| {
this.list_popover_open = *open;
cx.notify();
}))
.trigger(Button::new("pop").outline().label("Popup List"))
.track_focus(&self.list.focus_handle(cx))
.child(List::new(&self.list))
.w_64()
.h(px(200.)),
),
)
.child(
section("Right click to open Popover").child(
Popover::new("popover-right-click")

View file

@ -193,7 +193,6 @@ pub struct PopoverState {
focus_handle: FocusHandle,
pub(crate) tracked_focus_handle: Option<FocusHandle>,
trigger_bounds: Option<Bounds<Pixels>>,
previous_focus: Option<FocusHandle>,
open: bool,
on_open_change: Option<Rc<dyn Fn(&bool, &mut Window, &mut App)>>,
@ -206,7 +205,6 @@ impl PopoverState {
focus_handle: cx.focus_handle(),
tracked_focus_handle: None,
trigger_bounds: None,
previous_focus: None,
open: default_open,
on_open_change: None,
_dismiss_subscription: None,
@ -236,17 +234,13 @@ impl PopoverState {
self.open = !self.open;
if self.open {
let state = cx.entity();
self.previous_focus = window.focused(cx);
let focus_handle = if let Some(tracked_focus_handle) = self.tracked_focus_handle.clone()
{
tracked_focus_handle
} else {
self.focus_handle.clone()
};
cx.defer_in(window, move |_, window, _| {
focus_handle.focus(window);
});
focus_handle.focus(window);
self._dismiss_subscription =
Some(
@ -258,9 +252,6 @@ impl PopoverState {
}),
);
} else {
if let Some(previous_focus) = self.previous_focus.take() {
window.focus(&previous_focus);
}
self._dismiss_subscription = None;
}
@ -309,7 +300,7 @@ impl RenderOnce for Popover {
});
let open = state.read(cx).open;
let focus_handle = state.focus_handle(cx);
let focus_handle = state.read(cx).focus_handle.clone();
let trigger_bounds = state.read(cx).trigger_bounds;
let Some(trigger) = self.trigger else {
@ -364,8 +355,8 @@ impl RenderOnce for Popover {
.child(
v_flex()
.id("content")
.key_context(CONTEXT)
.track_focus(&focus_handle)
.key_context(CONTEXT)
.on_action(window.listener_for(&state, PopoverState::on_action_cancel))
.size_full()
.occlude()