diff --git a/crates/story/src/popover_story.rs b/crates/story/src/popover_story.rs index 7264fb14..c2e56080 100644 --- a/crates/story/src/popover_story.rs +++ b/crates/story/src/popover_story.rs @@ -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, +} +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 { + Some(ListItem::new(ix).child(format!("Item {}", ix.row))) + } + + fn set_selected_index( + &mut self, + _: Option, + _: &mut Window, + _: &mut Context>, + ) { + } + + fn confirm(&mut self, _: bool, _: &mut Window, cx: &mut Context>) { + self.parent.update(cx, |this, cx| { + this.list_popover_open = false; + cx.notify(); + }) + } + + fn cancel(&mut self, _: &mut Window, cx: &mut Context>) { + self.parent.update(cx, |this, cx| { + this.list_popover_open = false; + cx.notify(); + }) + } +} + impl EventEmitter 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_open: bool, + list: Entity>, + 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 { 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") diff --git a/crates/ui/src/popover.rs b/crates/ui/src/popover.rs index 0fd286d6..e0f3dc61 100644 --- a/crates/ui/src/popover.rs +++ b/crates/ui/src/popover.rs @@ -193,7 +193,6 @@ pub struct PopoverState { focus_handle: FocusHandle, pub(crate) tracked_focus_handle: Option, trigger_bounds: Option>, - previous_focus: Option, open: bool, on_open_change: Option>, @@ -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()