drawer: support ESC to close it by on_action and call on_close (#341)
Fix #263 
This commit is contained in:
parent
9b8240c6bc
commit
51df8f2f04
3 changed files with 44 additions and 13 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue