Skip to main content

gpui_component/dialog/
footer.rs

1use gpui::{
2    AnyElement, App, InteractiveElement as _, IntoElement, ParentElement, RenderOnce,
3    StatefulInteractiveElement, StyleRefinement, Styled, Window, div, relative,
4};
5
6use crate::{ActiveTheme as _, StyledExt as _, button::Button, dialog::Confirm, h_flex};
7
8/// Footer section of a dialog, typically contains action buttons.
9///
10/// # Examples
11///
12/// ```ignore
13/// DialogFooter::new()
14///     .child(DialogClose::new().trigger(|button| button.label("Cancel")))
15///     .child(Button::new("confirm").label("Confirm"))
16/// ```
17#[derive(IntoElement)]
18pub struct DialogFooter {
19    style: StyleRefinement,
20    children: Vec<AnyElement>,
21}
22
23impl DialogFooter {
24    pub fn new() -> Self {
25        Self {
26            style: StyleRefinement::default(),
27            children: Vec::new(),
28        }
29    }
30}
31
32impl ParentElement for DialogFooter {
33    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
34        self.children.extend(elements);
35    }
36}
37
38impl Styled for DialogFooter {
39    fn style(&mut self) -> &mut StyleRefinement {
40        &mut self.style
41    }
42}
43
44impl RenderOnce for DialogFooter {
45    fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
46        h_flex()
47            .gap_2()
48            .justify_end()
49            .line_height(relative(1.))
50            .rounded_b(cx.theme().radius_lg)
51            .refine_style(&self.style)
52            .children(self.children)
53    }
54}
55
56pub trait DialogFooterButton {
57    fn is_cancel(&self) -> bool {
58        false
59    }
60
61    fn is_action(&self) -> bool {
62        false
63    }
64}
65#[derive(IntoElement)]
66pub struct DialogClose {
67    base: gpui_base::DialogClose,
68}
69
70impl DialogClose {
71    pub fn new() -> Self {
72        Self {
73            base: gpui_base::DialogClose::new(),
74        }
75    }
76
77    /// Styles a close button whose accessibility and activation are owned by Base.
78    pub fn trigger<E: IntoElement>(mut self, build: impl FnOnce(Button) -> E) -> Self {
79        self.base = self
80            .base
81            .trigger(|button| build(Button::new("close").with_base(button)));
82        self
83    }
84}
85
86impl ParentElement for DialogClose {
87    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
88        self.base.extend(elements);
89    }
90}
91
92impl RenderOnce for DialogClose {
93    fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
94        div().size_full().child(self.base)
95    }
96}
97
98#[derive(IntoElement)]
99pub struct DialogAction {
100    children: Vec<AnyElement>,
101}
102
103impl DialogAction {
104    pub fn new() -> Self {
105        Self {
106            children: Vec::new(),
107        }
108    }
109}
110
111impl ParentElement for DialogAction {
112    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
113        self.children.extend(elements);
114    }
115}
116
117impl RenderOnce for DialogAction {
118    fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
119        div()
120            .size_full()
121            .id("dialog-action")
122            .on_click(move |_, window, cx| {
123                window.dispatch_action(Box::new(Confirm { secondary: false }), cx)
124            })
125            .children(self.children)
126    }
127}