1#![cfg_attr(target_family = "wasm", no_main)]
2
3use gpui::{
4 App, Context, Corner, Div, Hsla, Stateful, Window, WindowOptions, anchored, deferred, div,
5 prelude::*, px,
6};
7use gpui_platform::application;
8
9/// An example show use deferred to create a floating layers.
10struct HelloWorld {
11 open: bool,
12 secondary_open: bool,
13}
14
15fn button(id: &'static str) -> Stateful<Div> {
16 div()
17 .id(id)
18 .bg(gpui::black())
19 .text_color(gpui::white())
20 .px_3()
21 .py_1()
22}
23
24fn popover() -> Div {
25 div()
26 .flex()
27 .flex_col()
28 .items_center()
29 .justify_center()
30 .shadow_lg()
31 .p_3()
32 .rounded_md()
33 .bg(gpui::white())
34 .text_color(gpui::black())
35 .border_1()
36 .text_sm()
37 .border_color(gpui::black().opacity(0.1))
38}
39
40fn line(color: Hsla) -> Div {
41 div().w(px(480.)).h_2().bg(color.opacity(0.25))
42}
43
44impl HelloWorld {
45 fn render_secondary_popover(
46 &mut self,
47 _window: &mut Window,
48 cx: &mut Context<Self>,
49 ) -> impl IntoElement {
50 button("secondary-btn")
51 .mt_2()
52 .child("Child Popover")
53 .on_click(cx.listener(|this, _, _, cx| {
54 this.secondary_open = true;
55 cx.notify();
56 }))
57 .when(self.secondary_open, |this| {
58 this.child(
59 // Now GPUI supports nested deferred!
60 deferred(
61 anchored()
62 .anchor(Corner::TopLeft)
63 .snap_to_window_with_margin(px(8.))
64 .child(
65 popover()
66 .child("This is second level Popover with nested deferred!")
67 .bg(gpui::white())
68 .border_color(gpui::blue())
69 .on_mouse_down_out(cx.listener(|this, _, _, cx| {
70 this.secondary_open = false;
71 cx.notify();
72 })),
73 ),
74 )
75 .priority(2),
76 )
77 })
78 }
79}
80
81impl Render for HelloWorld {
82 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
83 div()
84 .flex()
85 .flex_col()
86 .gap_3()
87 .size_full()
88 .bg(gpui::white())
89 .text_color(gpui::black())
90 .justify_center()
91 .items_center()
92 .child(
93 div()
94 .flex()
95 .flex_row()
96 .gap_4()
97 .child(
98 button("popover0").child("Opened Popover").child(
99 deferred(
100 anchored()
101 .anchor(Corner::TopLeft)
102 .snap_to_window_with_margin(px(8.))
103 .child(popover().w_96().gap_3().child(
104 "This is a default opened Popover, \
105 we can use deferred to render it \
106 in a floating layer.",
107 )),
108 )
109 .priority(0),
110 ),
111 )
112 .child(
113 button("popover1")
114 .child("Open Popover")
115 .on_click(cx.listener(|this, _, _, cx| {
116 this.open = true;
117 cx.notify();
118 }))
119 .when(self.open, |this| {
120 this.child(
121 deferred(
122 anchored()
123 .anchor(Corner::TopLeft)
124 .snap_to_window_with_margin(px(8.))
125 .child(
126 popover()
127 .w_96()
128 .gap_3()
129 .child(
130 "This is first level Popover, \
131 we can use deferred to render it \
132 in a floating layer.\n\
133 Click outside to close.",
134 )
135 .when(!self.secondary_open, |this| {
136 this.on_mouse_down_out(cx.listener(
137 |this, _, _, cx| {
138 this.open = false;
139 cx.notify();
140 },
141 ))
142 })
143 // Here we need render popover after the content
144 // to ensure it will be on top layer.
145 .child(
146 self.render_secondary_popover(window, cx),
147 ),
148 ),
149 )
150 .priority(1),
151 )
152 }),
153 ),
154 )
155 .child(
156 "Here is an example text rendered, \
157 to ensure the Popover will float above this contents.",
158 )
159 .children([
160 line(gpui::red()),
161 line(gpui::yellow()),
162 line(gpui::blue()),
163 line(gpui::green()),
164 ])
165 }
166}
167
168fn run_example() {
169 application().run(|cx: &mut App| {
170 cx.open_window(WindowOptions::default(), |_, cx| {
171 cx.new(|_| HelloWorld {
172 open: false,
173 secondary_open: false,
174 })
175 })
176 .unwrap();
177 cx.activate(true);
178 });
179}
180
181#[cfg(not(target_family = "wasm"))]
182fn main() {
183 run_example();
184}
185
186#[cfg(target_family = "wasm")]
187#[wasm_bindgen::prelude::wasm_bindgen(start)]
188pub fn start() {
189 gpui_platform::web_init();
190 run_example();
191}