drawer: support ESC to close it by on_action and call on_close (#341)

Fix #263

![2024-10-14 21 26
02](https://github.com/user-attachments/assets/b6060f82-117a-4935-91df-d336f905624d)
This commit is contained in:
xda 2024-10-15 22:47:45 +09:00 committed by GitHub
parent 9b8240c6bc
commit 51df8f2f04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 44 additions and 13 deletions

View file

@ -1,10 +1,10 @@
use std::{rc::Rc, time::Duration};
use gpui::{
anchored, div, point, prelude::FluentBuilder as _, px, Animation, AnimationExt as _,
AnyElement, ClickEvent, DefiniteLength, DismissEvent, Div, EventEmitter, FocusHandle,
InteractiveElement as _, IntoElement, MouseButton, ParentElement, Pixels, RenderOnce, Styled,
WindowContext,
actions, anchored, div, point, prelude::FluentBuilder as _, px, Animation, AnimationExt as _,
AnyElement, AppContext, ClickEvent, DefiniteLength, DismissEvent, Div, EventEmitter,
FocusHandle, InteractiveElement as _, IntoElement, KeyBinding, MouseButton, ParentElement,
Pixels, RenderOnce, Styled, WindowContext,
};
use crate::{
@ -17,9 +17,16 @@ use crate::{
v_flex, IconName, Placement, Sizable, StyledExt as _,
};
actions!(drawer, [Escape]);
const CONTEXT: &str = "Drawer";
pub fn init(cx: &mut AppContext) {
cx.bind_keys([KeyBinding::new("escape", Escape, Some(CONTEXT))])
}
#[derive(IntoElement)]
pub struct Drawer {
focus_handle: FocusHandle,
pub(crate) focus_handle: FocusHandle,
placement: Placement,
size: DefiniteLength,
resizable: bool,
@ -120,7 +127,6 @@ impl Styled for Drawer {
impl RenderOnce for Drawer {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let focus_handle = self.focus_handle.clone();
let placement = self.placement;
let titlebar_height = self.margin_top;
let size = cx.viewport_size();
@ -146,8 +152,16 @@ impl RenderOnce for Drawer {
})
.child(
v_flex()
.id("")
.track_focus(&focus_handle)
.id("drawer")
.key_context(CONTEXT)
.track_focus(&self.focus_handle)
.on_action({
let on_close = self.on_close.clone();
move |_: &Escape, cx| {
on_close(&ClickEvent::default(), cx);
cx.close_drawer();
}
})
.absolute()
.occlude()
.bg(cx.theme().background)

View file

@ -62,6 +62,7 @@ pub fn init(cx: &mut gpui::AppContext) {
context_menu::init(cx);
date_picker::init(cx);
dock::init(cx);
drawer::init(cx);
dropdown::init(cx);
input::init(cx);
list::init(cx);

View file

@ -57,7 +57,14 @@ impl<'a> ContextModal for WindowContext<'a> {
if root.active_drawer.is_none() {
root.previous_focus_handle = cx.focused();
}
root.active_drawer = Some(Rc::new(build));
let focus_handle = cx.focus_handle();
focus_handle.focus(cx);
root.active_drawer = Some(ActiveDrawer {
focus_handle,
builder: Rc::new(build),
});
cx.notify();
})
}
@ -199,12 +206,18 @@ pub struct Root {
/// Used to store the focus handle of the previus revious view.
/// When the Modal, Drawer closes, we will focus back to the previous view.
previous_focus_handle: Option<FocusHandle>,
active_drawer: Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>>,
active_drawer: Option<ActiveDrawer>,
active_modals: Vec<ActiveModal>,
pub notification: View<NotificationList>,
child: AnyView,
}
#[derive(Clone)]
struct ActiveDrawer {
focus_handle: FocusHandle,
builder: Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>,
}
#[derive(Clone)]
struct ActiveModal {
focus_handle: FocusHandle,
@ -270,9 +283,12 @@ impl Root {
.and_then(|w| w.root_view(cx).ok())
.expect("The window root view should be of type `ui::Root`.");
if let Some(builder) = root.read(cx).active_drawer.clone() {
let drawer = Drawer::new(cx);
return Some(builder(drawer, cx));
if let Some(active_drawer) = root.read(cx).active_drawer.clone() {
let mut drawer = Drawer::new(cx);
drawer = (active_drawer.builder)(drawer, cx);
drawer.focus_handle = active_drawer.focus_handle.clone();
return Some(div().child(drawer));
}
None