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