feat: add a close button to dialog
The close affordance reuses Button (ghost, small) at the panel's top right and routes through on_change like escape and scrim clicks; it is hidden in alert mode. The dialog feature now depends on button, and AGENTS.md codifies preferring existing components over custom elements.
This commit is contained in:
@@ -6,14 +6,17 @@ use gpui::{
|
||||
IntoElement, KeyDownEvent, MouseButton, ParentElement as _, RenderOnce, Role, SharedString,
|
||||
StatefulInteractiveElement as _, Styled as _, Window, canvas, div, ease_out_quint, relative,
|
||||
};
|
||||
use gpui_native_icons::IconRole;
|
||||
use gpui_native_theme::ActiveTheme as _;
|
||||
|
||||
use crate::common::v_flex;
|
||||
use crate::button::{Button, ButtonVariant};
|
||||
use crate::common::{Sizable, v_flex};
|
||||
|
||||
/// Requests the dialog's close: `false` closes.
|
||||
pub type ChangeHandler = Rc<dyn Fn(bool, &mut Window, &mut App)>;
|
||||
type ContentFn = Box<dyn Fn(&mut Window, &mut App) -> AnyElement>;
|
||||
type ActionsFn = Box<dyn Fn(&mut Window, &mut App) -> Vec<AnyElement>>;
|
||||
|
||||
/// A centred panel over a dim scrim: the platform's modal.
|
||||
#[derive(IntoElement)]
|
||||
pub struct Dialog {
|
||||
@@ -57,7 +60,7 @@ impl Dialog {
|
||||
self
|
||||
}
|
||||
|
||||
/// Requests close through `on_change` on escape and scrim clicks.
|
||||
/// Requests close through `on_change` on escape, scrim clicks, and the close button.
|
||||
pub fn on_change<F>(mut self, handler: F) -> Self
|
||||
where
|
||||
F: Fn(bool, &mut Window, &mut App) + 'static,
|
||||
@@ -154,6 +157,7 @@ impl RenderOnce for Dialog {
|
||||
|
||||
let on_change = self.on_change.clone();
|
||||
let alert = self.alert;
|
||||
let show_close = !alert && on_change.is_some();
|
||||
|
||||
// Keyboard focus rides the panel across frames.
|
||||
let focus = gpui_native_utils::focus_handle(&self.id, window, cx);
|
||||
@@ -190,12 +194,40 @@ impl RenderOnce for Dialog {
|
||||
cx.stop_propagation();
|
||||
}
|
||||
})
|
||||
.when_some(self.title, |panel, title| {
|
||||
.when(self.title.is_some() || show_close, |panel| {
|
||||
panel.child(
|
||||
div()
|
||||
.text_size(title_size)
|
||||
.font_weight(FontWeight::SEMIBOLD)
|
||||
.child(title),
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_end()
|
||||
.gap_2()
|
||||
.when_some(self.title.clone(), |row, title| {
|
||||
row.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.text_size(title_size)
|
||||
.font_weight(FontWeight::SEMIBOLD)
|
||||
.child(title),
|
||||
)
|
||||
})
|
||||
.when(show_close, |row| {
|
||||
row.child(
|
||||
Button::new("dialog-close")
|
||||
.icon(IconRole::Close)
|
||||
.variant(ButtonVariant::Ghost)
|
||||
.small()
|
||||
.debug_selector(|| "dialog-close".to_string())
|
||||
.accessibility_label("Close")
|
||||
.on_click({
|
||||
let on_change = on_change.clone();
|
||||
move |_, window, cx| {
|
||||
if let Some(on_change) = &on_change {
|
||||
on_change(false, window, cx);
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
}),
|
||||
)
|
||||
})
|
||||
.when_some(content, |panel, content| {
|
||||
|
||||
Reference in New Issue
Block a user